Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: content/renderer/media/audio_device.cc

Issue 8785008: Simplify AudioRendererImpl by using AudioDevice. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update stale comment Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/renderer/media/audio_device.h ('k') | content/renderer/media/audio_renderer_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/renderer/media/audio_device.h" 5 #include "content/renderer/media/audio_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/time.h" 10 #include "base/time.h"
11 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
13 #include "content/common/view_messages.h" 13 #include "content/common/view_messages.h"
14 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_output_controller.h"
15 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
16 17
18 AudioDevice::AudioDevice()
19 : buffer_size_(0),
20 channels_(0),
21 bits_per_sample_(16),
22 sample_rate_(0),
23 latency_format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
24 callback_(0),
25 is_initialized_(false),
26 audio_delay_milliseconds_(0),
27 volume_(1.0),
28 stream_id_(0),
29 play_on_start_(true),
30 is_started_(false),
31 memory_length_(0) {
32 filter_ = RenderThreadImpl::current()->audio_message_filter();
33 }
34
17 AudioDevice::AudioDevice(size_t buffer_size, 35 AudioDevice::AudioDevice(size_t buffer_size,
18 int channels, 36 int channels,
19 double sample_rate, 37 double sample_rate,
20 RenderCallback* callback) 38 RenderCallback* callback)
21 : buffer_size_(buffer_size), 39 : bits_per_sample_(16),
22 channels_(channels), 40 is_initialized_(false),
23 bits_per_sample_(16),
24 sample_rate_(sample_rate),
25 callback_(callback),
26 audio_delay_milliseconds_(0), 41 audio_delay_milliseconds_(0),
27 volume_(1.0), 42 volume_(1.0),
28 stream_id_(0), 43 stream_id_(0),
44 play_on_start_(true),
45 is_started_(false),
29 memory_length_(0) { 46 memory_length_(0) {
30 filter_ = RenderThreadImpl::current()->audio_message_filter(); 47 filter_ = RenderThreadImpl::current()->audio_message_filter();
48 Initialize(buffer_size,
49 channels,
50 sample_rate,
51 AudioParameters::AUDIO_PCM_LOW_LATENCY,
52 callback);
53 }
54
55 void AudioDevice::Initialize(size_t buffer_size,
56 int channels,
57 double sample_rate,
58 AudioParameters::Format latency_format,
59 RenderCallback* callback) {
60 CHECK_EQ(0, stream_id_) <<
61 "AudioDevice::Initialize() must be called before Start()";
62
63 buffer_size_ = buffer_size;
64 channels_ = channels;
65 sample_rate_ = sample_rate;
66 latency_format_ = latency_format;
67 callback_ = callback;
68
69 // Cleanup from any previous initialization.
70 for (size_t i = 0; i < audio_data_.size(); ++i)
71 delete [] audio_data_[i];
72
31 audio_data_.reserve(channels); 73 audio_data_.reserve(channels);
32 for (int i = 0; i < channels; ++i) { 74 for (int i = 0; i < channels; ++i) {
33 float* channel_data = new float[buffer_size]; 75 float* channel_data = new float[buffer_size];
34 audio_data_.push_back(channel_data); 76 audio_data_.push_back(channel_data);
35 } 77 }
78
79 is_initialized_ = true;
80 }
81
82 bool AudioDevice::IsInitialized() {
83 return is_initialized_;
36 } 84 }
37 85
38 AudioDevice::~AudioDevice() { 86 AudioDevice::~AudioDevice() {
39 // The current design requires that the user calls Stop() before deleting 87 // The current design requires that the user calls Stop() before deleting
40 // this class. 88 // this class.
41 CHECK_EQ(0, stream_id_); 89 CHECK_EQ(0, stream_id_);
42 for (int i = 0; i < channels_; ++i) 90 for (int i = 0; i < channels_; ++i)
43 delete [] audio_data_[i]; 91 delete [] audio_data_[i];
44 } 92 }
45 93
46 void AudioDevice::Start() { 94 void AudioDevice::Start() {
47 AudioParameters params; 95 AudioParameters params;
48 params.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 96 params.format = latency_format_;
49 params.channels = channels_; 97 params.channels = channels_;
50 params.sample_rate = static_cast<int>(sample_rate_); 98 params.sample_rate = static_cast<int>(sample_rate_);
51 params.bits_per_sample = bits_per_sample_; 99 params.bits_per_sample = bits_per_sample_;
52 params.samples_per_packet = buffer_size_; 100 params.samples_per_packet = buffer_size_;
53 101
54 ChildProcess::current()->io_message_loop()->PostTask( 102 ChildProcess::current()->io_message_loop()->PostTask(
55 FROM_HERE, 103 FROM_HERE,
56 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); 104 base::Bind(&AudioDevice::InitializeOnIOThread, this, params));
57 } 105 }
58 106
59 void AudioDevice::Stop() { 107 void AudioDevice::Stop() {
60 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 108 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
61 // Max waiting time for Stop() to complete. If this time limit is passed, 109 // Max waiting time for Stop() to complete. If this time limit is passed,
62 // we will stop waiting and return false. It ensures that Stop() can't block 110 // we will stop waiting and return false. It ensures that Stop() can't block
63 // the calling thread forever. 111 // the calling thread forever.
64 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000); 112 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
65 113
66 base::WaitableEvent completion(false, false); 114 base::WaitableEvent completion(false, false);
67 115
68 ChildProcess::current()->io_message_loop()->PostTask( 116 ChildProcess::current()->io_message_loop()->PostTask(
69 FROM_HERE, 117 FROM_HERE,
70 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion)); 118 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion));
71 119
72 // We wait here for the IO task to be completed to remove race conflicts 120 // We wait here for the IO task to be completed to remove race conflicts
73 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 121 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
74 // function call. 122 // function call.
75 if (!completion.TimedWait(kMaxTimeOut)) { 123 if (!completion.TimedWait(kMaxTimeOut)) {
76 LOG(ERROR) << "Failed to shut down audio output on IO thread"; 124 LOG(ERROR) << "Failed to shut down audio output on IO thread";
77 } 125 }
126 ShutDownAudioThread();
127 }
78 128
79 if (audio_thread_.get()) { 129 void AudioDevice::Play() {
80 // Close the socket handler to terminate the main thread function in the 130 ChildProcess::current()->io_message_loop()->PostTask(
81 // audio thread. 131 FROM_HERE,
82 { 132 base::Bind(&AudioDevice::PlayOnIOThread, this));
83 base::SyncSocket socket(socket_handle_); 133 }
84 } 134
85 audio_thread_->Join(); 135 void AudioDevice::Pause(bool flush) {
86 audio_thread_.reset(NULL); 136 ChildProcess::current()->io_message_loop()->PostTask(
87 } 137 FROM_HERE,
138 base::Bind(&AudioDevice::PauseOnIOThread, this, flush));
88 } 139 }
89 140
90 bool AudioDevice::SetVolume(double volume) { 141 bool AudioDevice::SetVolume(double volume) {
91 if (volume < 0 || volume > 1.0) 142 if (volume < 0 || volume > 1.0)
92 return false; 143 return false;
93 144
94 ChildProcess::current()->io_message_loop()->PostTask( 145 ChildProcess::current()->io_message_loop()->PostTask(
95 FROM_HERE, 146 FROM_HERE,
96 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume)); 147 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume));
97 148
98 volume_ = volume; 149 volume_ = volume;
99 150
100 return true; 151 return true;
101 } 152 }
102 153
103 void AudioDevice::GetVolume(double* volume) { 154 void AudioDevice::GetVolume(double* volume) {
104 // Return a locally cached version of the current scaling factor. 155 // Return a locally cached version of the current scaling factor.
105 *volume = volume_; 156 *volume = volume_;
106 } 157 }
107 158
108 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { 159 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) {
109 // Make sure we don't call Start() more than once. 160 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
161 // Make sure we don't create the stream more than once.
110 DCHECK_EQ(0, stream_id_); 162 DCHECK_EQ(0, stream_id_);
111 if (stream_id_) 163 if (stream_id_)
112 return; 164 return;
113 165
114 stream_id_ = filter_->AddDelegate(this); 166 stream_id_ = filter_->AddDelegate(this);
115 Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); 167 Send(new AudioHostMsg_CreateStream(stream_id_, params, true));
116 } 168 }
117 169
118 void AudioDevice::StartOnIOThread() { 170 void AudioDevice::PlayOnIOThread() {
119 if (stream_id_) 171 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
172 if (stream_id_ && is_started_)
120 Send(new AudioHostMsg_PlayStream(stream_id_)); 173 Send(new AudioHostMsg_PlayStream(stream_id_));
174 else
175 play_on_start_ = true;
176 }
177
178 void AudioDevice::PauseOnIOThread(bool flush) {
179 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
180 if (stream_id_ && is_started_) {
181 Send(new AudioHostMsg_PauseStream(stream_id_));
182 if (flush)
183 Send(new AudioHostMsg_FlushStream(stream_id_));
184 } else {
185 // Note that |flush| isn't relevant here since this is the case where
186 // the stream is first starting.
187 play_on_start_ = false;
188 }
121 } 189 }
122 190
123 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) { 191 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
192 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
193 is_started_ = false;
194
124 // Make sure we don't call shutdown more than once. 195 // Make sure we don't call shutdown more than once.
125 if (!stream_id_) { 196 if (!stream_id_) {
126 completion->Signal(); 197 if (completion)
198 completion->Signal();
127 return; 199 return;
128 } 200 }
129 201
130 filter_->RemoveDelegate(stream_id_); 202 filter_->RemoveDelegate(stream_id_);
131 Send(new AudioHostMsg_CloseStream(stream_id_)); 203 Send(new AudioHostMsg_CloseStream(stream_id_));
132 stream_id_ = 0; 204 stream_id_ = 0;
133 205
134 completion->Signal(); 206 if (completion)
207 completion->Signal();
135 } 208 }
136 209
137 void AudioDevice::SetVolumeOnIOThread(double volume) { 210 void AudioDevice::SetVolumeOnIOThread(double volume) {
211 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
138 if (stream_id_) 212 if (stream_id_)
139 Send(new AudioHostMsg_SetVolume(stream_id_, volume)); 213 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
140 } 214 }
141 215
142 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { 216 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) {
143 // This method does not apply to the low-latency system. 217 // This method does not apply to the low-latency system.
144 NOTIMPLEMENTED();
145 } 218 }
146 219
147 void AudioDevice::OnStateChanged(AudioStreamState state) { 220 void AudioDevice::OnStateChanged(AudioStreamState state) {
148 if (state == kAudioStreamError) { 221 if (state == kAudioStreamError) {
149 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)"; 222 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)";
150 } 223 }
151 NOTIMPLEMENTED();
152 } 224 }
153 225
154 void AudioDevice::OnCreated( 226 void AudioDevice::OnCreated(
155 base::SharedMemoryHandle handle, uint32 length) { 227 base::SharedMemoryHandle handle, uint32 length) {
156 // Not needed in this simple implementation. 228 // Not needed in this simple implementation.
157 NOTIMPLEMENTED();
158 } 229 }
159 230
160 void AudioDevice::OnLowLatencyCreated( 231 void AudioDevice::OnLowLatencyCreated(
161 base::SharedMemoryHandle handle, 232 base::SharedMemoryHandle handle,
162 base::SyncSocket::Handle socket_handle, 233 base::SyncSocket::Handle socket_handle,
163 uint32 length) { 234 uint32 length) {
164 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 235 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
165 #if defined(OS_WIN) 236 #if defined(OS_WIN)
166 DCHECK(handle); 237 DCHECK(handle);
167 DCHECK(socket_handle); 238 DCHECK(socket_handle);
(...skipping 11 matching lines...) Expand all
179 base::SyncSocket socket(socket_handle); 250 base::SyncSocket socket(socket_handle);
180 return; 251 return;
181 } 252 }
182 253
183 shared_memory_handle_ = handle; 254 shared_memory_handle_ = handle;
184 memory_length_ = length; 255 memory_length_ = length;
185 256
186 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_); 257 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_);
187 258
188 socket_handle_ = socket_handle; 259 socket_handle_ = socket_handle;
260 {
261 // Synchronize with ShutDownAudioThread().
262 base::AutoLock auto_lock(lock_);
189 263
190 audio_thread_.reset( 264 DCHECK(!audio_thread_.get());
191 new base::DelegateSimpleThread(this, "renderer_audio_thread")); 265 audio_thread_.reset(
192 audio_thread_->Start(); 266 new base::DelegateSimpleThread(this, "renderer_audio_thread"));
267 audio_thread_->Start();
268 }
193 269
194 MessageLoop::current()->PostTask( 270 // We handle the case where Play() and/or Pause() may have been called
195 FROM_HERE, 271 // multiple times before OnLowLatencyCreated() gets called.
196 base::Bind(&AudioDevice::StartOnIOThread, this)); 272 is_started_ = true;
273 if (play_on_start_)
274 PlayOnIOThread();
197 } 275 }
198 276
199 void AudioDevice::OnVolume(double volume) { 277 void AudioDevice::OnVolume(double volume) {
200 NOTIMPLEMENTED(); 278 NOTIMPLEMENTED();
201 } 279 }
202 280
203 void AudioDevice::Send(IPC::Message* message) { 281 void AudioDevice::Send(IPC::Message* message) {
204 filter_->Send(message); 282 filter_->Send(message);
205 } 283 }
206 284
207 // Our audio thread runs here. 285 // Our audio thread runs here.
208 void AudioDevice::Run() { 286 void AudioDevice::Run() {
209 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 287 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
210 288
211 base::SharedMemory shared_memory(shared_memory_handle_, false); 289 base::SharedMemory shared_memory(shared_memory_handle_, false);
212 shared_memory.Map(memory_length_); 290 shared_memory.Map(memory_length_);
213 // Allow the client to pre-populate the buffer. 291 // Allow the client to pre-populate the buffer.
214 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory())); 292 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory()));
215 293
216 base::SyncSocket socket(socket_handle_); 294 base::SyncSocket socket(socket_handle_);
217 295
218 int pending_data; 296 int pending_data;
219 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; 297 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
220 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; 298 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
221 299
222 while ((sizeof(pending_data) == socket.Receive(&pending_data, 300 while (sizeof(pending_data) ==
223 sizeof(pending_data))) && 301 socket.Receive(&pending_data, sizeof(pending_data))) {
224 (pending_data >= 0)) { 302 if (pending_data == media::AudioOutputController::kPauseMark) {
303 memset(shared_memory.memory(), 0, memory_length_);
304 continue;
305 } else if (pending_data < 0) {
306 break;
307 }
225 // Convert the number of pending bytes in the render buffer 308 // Convert the number of pending bytes in the render buffer
226 // into milliseconds. 309 // into milliseconds.
227 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 310 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
228 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory())); 311 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory()));
229 } 312 }
230 } 313 }
231 314
232 void AudioDevice::FireRenderCallback(int16* data) { 315 void AudioDevice::FireRenderCallback(int16* data) {
233 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback"); 316 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback");
234 317
235 if (callback_) { 318 if (callback_) {
236 // Update the audio-delay measurement then ask client to render audio. 319 // Update the audio-delay measurement then ask client to render audio.
237 callback_->Render(audio_data_, buffer_size_, audio_delay_milliseconds_); 320 callback_->Render(audio_data_, buffer_size_, audio_delay_milliseconds_);
238 321
239 // Interleave, scale, and clip to int16. 322 // Interleave, scale, and clip to int16.
323 // TODO(crogers): avoid converting to integer here, and pass the data
324 // to the browser process as float, so we don't lose precision for
325 // audio hardware which has better than 16bit precision.
240 media::InterleaveFloatToInt16(audio_data_, 326 media::InterleaveFloatToInt16(audio_data_,
241 data, 327 data,
242 buffer_size_); 328 buffer_size_);
243 } 329 }
244 } 330 }
331
332 void AudioDevice::ShutDownAudioThread() {
333 // Synchronize with OnLowLatencyCreated().
334 base::AutoLock auto_lock(lock_);
335 if (audio_thread_.get()) {
336 // Close the socket handler to terminate the main thread function in the
337 // audio thread.
338 {
339 base::SyncSocket socket(socket_handle_);
340 }
341 audio_thread_->Join();
342 audio_thread_.reset(NULL);
343 }
344 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_device.h ('k') | content/renderer/media/audio_renderer_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698