OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 5 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/memory/shared_memory.h" | 10 #include "base/memory/shared_memory.h" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "content/public/common/content_switches.h" | 12 #include "content/public/common/content_switches.h" |
13 #include "media/audio/audio_buffers_state.h" | 13 #include "media/audio/audio_buffers_state.h" |
14 #include "media/audio/audio_parameters.h" | 14 #include "media/audio/audio_parameters.h" |
15 #include "media/audio/shared_memory_util.h" | 15 #include "media/audio/shared_memory_util.h" |
16 | 16 |
17 using media::AudioBus; | 17 using media::AudioBus; |
18 | 18 |
19 namespace content { | 19 namespace content { |
20 | 20 |
21 AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory, | 21 AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory, |
22 const media::AudioParameters& params, | 22 const media::AudioParameters& params, |
23 int input_channels) | 23 int input_channels) |
24 : shared_memory_(shared_memory), | 24 : shared_memory_(shared_memory), |
25 input_channels_(input_channels), | 25 input_channels_(input_channels), |
26 mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch( | 26 mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch( |
27 switches::kMuteAudio)), | 27 switches::kMuteAudio)), |
28 renderer_callback_count_(0), | 28 renderer_callback_count_(0), |
29 renderer_missed_callback_count_(0) { | 29 renderer_missed_callback_count_(0), |
30 // TODO(dalecurtis): Cap it at 20ms? | |
31 maximum_wait_time_(params.GetBufferDuration() / 2), | |
henrika (OOO until Aug 14)
2013/08/20 07:50:30
Just checking; what is the unit of GetBufferDurati
DaleCurtis
2013/09/11 01:16:03
base::TimeDelta
| |
32 buffer_index_(0) { | |
30 packet_size_ = media::PacketSizeInBytes(shared_memory_->requested_size()); | 33 packet_size_ = media::PacketSizeInBytes(shared_memory_->requested_size()); |
31 int input_memory_size = 0; | 34 int input_memory_size = 0; |
32 int output_memory_size = AudioBus::CalculateMemorySize(params); | 35 int output_memory_size = AudioBus::CalculateMemorySize(params); |
33 if (input_channels_ > 0) { | 36 if (input_channels_ > 0) { |
34 // The input storage is after the output storage. | 37 // The input storage is after the output storage. |
35 int frames = params.frames_per_buffer(); | 38 int frames = params.frames_per_buffer(); |
36 input_memory_size = AudioBus::CalculateMemorySize(input_channels_, frames); | 39 input_memory_size = AudioBus::CalculateMemorySize(input_channels_, frames); |
37 char* input_data = | 40 char* input_data = |
38 static_cast<char*>(shared_memory_->memory()) + output_memory_size; | 41 static_cast<char*>(shared_memory_->memory()) + output_memory_size; |
39 input_bus_ = AudioBus::WrapMemory(input_channels_, frames, input_data); | 42 input_bus_ = AudioBus::WrapMemory(input_channels_, frames, input_data); |
(...skipping 21 matching lines...) Expand all Loading... | |
61 // media::AudioOutputController::SyncReader implementations. | 64 // media::AudioOutputController::SyncReader implementations. |
62 void AudioSyncReader::UpdatePendingBytes(uint32 bytes) { | 65 void AudioSyncReader::UpdatePendingBytes(uint32 bytes) { |
63 if (bytes != static_cast<uint32>(media::kPauseMark)) { | 66 if (bytes != static_cast<uint32>(media::kPauseMark)) { |
64 // Store unknown length of data into buffer, so we later | 67 // Store unknown length of data into buffer, so we later |
65 // can find out if data became available. | 68 // can find out if data became available. |
66 media::SetUnknownDataSize(shared_memory_, packet_size_); | 69 media::SetUnknownDataSize(shared_memory_, packet_size_); |
67 } | 70 } |
68 | 71 |
69 if (socket_) { | 72 if (socket_) { |
70 socket_->Send(&bytes, sizeof(bytes)); | 73 socket_->Send(&bytes, sizeof(bytes)); |
74 buffer_index_++; | |
tommi (sloooow) - chröme
2013/08/20 10:55:57
nit: ++buffer_index_;
DaleCurtis
2013/09/11 01:16:03
Done.
| |
71 } | 75 } |
72 } | 76 } |
73 | 77 |
74 int AudioSyncReader::Read(bool block, const AudioBus* source, AudioBus* dest) { | 78 int AudioSyncReader::Read(bool block, const AudioBus* source, AudioBus* dest) { |
75 ++renderer_callback_count_; | 79 ++renderer_callback_count_; |
76 if (!DataReady()) { | 80 if (!WaitTillDataReady()) { |
77 ++renderer_missed_callback_count_; | 81 ++renderer_missed_callback_count_; |
78 | 82 return 0; |
79 if (block) | |
80 WaitTillDataReady(); | |
81 } | 83 } |
82 | 84 |
83 // Copy optional synchronized live audio input for consumption by renderer | 85 // Copy optional synchronized live audio input for consumption by renderer |
84 // process. | 86 // process. |
85 if (source && input_bus_) { | 87 if (source && input_bus_) { |
86 DCHECK_EQ(source->channels(), input_bus_->channels()); | 88 DCHECK_EQ(source->channels(), input_bus_->channels()); |
87 // TODO(crogers): In some cases with device and sample-rate changes | 89 // TODO(crogers): In some cases with device and sample-rate changes |
88 // it's possible for an AOR to insert a resampler in the path. | 90 // it's possible for an AOR to insert a resampler in the path. |
89 // Because this is used with the Web Audio API, it'd be better | 91 // Because this is used with the Web Audio API, it'd be better |
90 // to bypass the device change handling in AOR and instead let | 92 // to bypass the device change handling in AOR and instead let |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 base::ProcessHandle process_handle, | 168 base::ProcessHandle process_handle, |
167 base::FileDescriptor* foreign_handle) { | 169 base::FileDescriptor* foreign_handle) { |
168 foreign_handle->fd = foreign_socket_->handle(); | 170 foreign_handle->fd = foreign_socket_->handle(); |
169 foreign_handle->auto_close = false; | 171 foreign_handle->auto_close = false; |
170 if (foreign_handle->fd != -1) | 172 if (foreign_handle->fd != -1) |
171 return true; | 173 return true; |
172 return false; | 174 return false; |
173 } | 175 } |
174 #endif | 176 #endif |
175 | 177 |
176 void AudioSyncReader::WaitTillDataReady() { | 178 bool AudioSyncReader::WaitTillDataReady() { |
179 if (!socket_) | |
tommi (sloooow) - chröme
2013/08/20 10:55:57
is this something exected or unexpected (i.e. [D]C
DaleCurtis
2013/09/11 01:16:03
Set during Init() and never changed. Checks remov
| |
180 return false; | |
181 | |
182 size_t bytes_received = 0; | |
183 uint32 renderer_buffer_index = 0; | |
184 | |
177 base::TimeTicks start = base::TimeTicks::Now(); | 185 base::TimeTicks start = base::TimeTicks::Now(); |
178 const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20); | |
179 #if defined(OS_WIN) | |
180 // Sleep(0) on Windows lets the other threads run. | |
181 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0); | |
182 #else | |
183 // We want to sleep for a bit here, as otherwise a backgrounded renderer won't | |
184 // get enough cpu to send the data and the high priority thread in the browser | |
185 // will use up a core causing even more skips. | |
186 const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2); | |
187 #endif | |
188 base::TimeDelta time_since_start; | |
189 do { | 186 do { |
190 base::PlatformThread::Sleep(kSleep); | 187 bytes_received = socket_->Receive( |
tommi (sloooow) - chröme
2013/08/20 10:55:57
Since we're using sockets, we should be able to ch
DaleCurtis
2013/08/20 18:27:51
Not sure I follow which "multiple" items you want
tommi (sloooow) - chröme
2013/08/21 12:33:26
Sorry, for some reason I parsed this loop as cycli
| |
191 time_since_start = base::TimeTicks::Now() - start; | 188 &renderer_buffer_index, sizeof(renderer_buffer_index), |
192 } while (!DataReady() && time_since_start < kMaxWait); | 189 maximum_wait_time_); |
DaveMoore
2013/08/19 22:49:43
Does it mean anything (skipping) if something othe
DaleCurtis
2013/08/19 23:08:22
It means we timed out on one or more previous call
| |
190 } while (bytes_received > 0 && renderer_buffer_index != buffer_index_); | |
191 | |
192 base::TimeDelta time_since_start = base::TimeTicks::Now() - start; | |
193 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady", | 193 UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady", |
194 time_since_start, | 194 time_since_start, |
195 base::TimeDelta::FromMilliseconds(1), | 195 base::TimeDelta::FromMilliseconds(1), |
196 base::TimeDelta::FromMilliseconds(1000), | 196 base::TimeDelta::FromMilliseconds(1000), |
197 50); | 197 50); |
198 | |
199 // Receive() timed out or another unknown error occurred. | |
henrika (OOO until Aug 14)
2013/08/20 07:50:30
Could you add some more details about what can cau
DaleCurtis
2013/09/11 01:16:03
Done.
| |
200 if (!bytes_received) { | |
201 DVLOG(2) << "AudioSyncReader::WaitTillDataReady() timed out."; | |
202 return false; | |
203 } | |
204 | |
205 DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index)); | |
206 DCHECK(DataReady()); | |
207 return true; | |
198 } | 208 } |
199 | 209 |
200 } // namespace content | 210 } // namespace content |
OLD | NEW |