Chromium Code Reviews| 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 |