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

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

Issue 8477037: Simplify AudioRendererImpl by using AudioDevice. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 1 month 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
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_util.h" 15 #include "media/audio/audio_util.h"
16 16
17 AudioDevice::AudioDevice(RenderCallback* callback)
18 : buffer_size_(0),
scherkus (not reviewing) 2011/11/09 02:39:05 indent by two more
Chris Rogers 2011/11/10 02:17:22 Done.
19 channels_(0),
20 bits_per_sample_(16),
21 sample_rate_(0),
22 latency_format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
23 callback_(callback),
24 audio_delay_milliseconds_(0),
25 volume_(1.0),
26 stream_id_(0) {
27 filter_ = RenderThreadImpl::current()->audio_message_filter();
28 }
29
17 AudioDevice::AudioDevice(size_t buffer_size, 30 AudioDevice::AudioDevice(size_t buffer_size,
18 int channels, 31 int channels,
19 double sample_rate, 32 double sample_rate,
20 RenderCallback* callback) 33 RenderCallback* callback)
21 : buffer_size_(buffer_size), 34 : buffer_size_(buffer_size),
22 channels_(channels), 35 channels_(channels),
23 bits_per_sample_(16), 36 bits_per_sample_(16),
24 sample_rate_(sample_rate), 37 sample_rate_(sample_rate),
25 callback_(callback), 38 callback_(callback),
26 audio_delay_milliseconds_(0), 39 audio_delay_milliseconds_(0),
27 volume_(1.0), 40 volume_(1.0),
28 stream_id_(0) { 41 stream_id_(0) {
29 filter_ = RenderThreadImpl::current()->audio_message_filter(); 42 filter_ = RenderThreadImpl::current()->audio_message_filter();
43 Initialize(buffer_size,
44 channels,
45 sample_rate,
46 AudioParameters::AUDIO_PCM_LOW_LATENCY);
47 }
48
49 void AudioDevice::Initialize(size_t buffer_size,
50 int channels,
51 double sample_rate,
52 AudioParameters::Format latency_format) {
53 CHECK_EQ(0, stream_id_);
scherkus (not reviewing) 2011/11/09 02:39:05 nit: perhaps add logging? CHECK_EQ(0, stream_id) <
Chris Rogers 2011/11/10 02:17:22 Done.
54 if (stream_id_)
55 return;
56
57 buffer_size_ = buffer_size;
58 channels_ = channels;
59 sample_rate_ = sample_rate;
60 latency_format_ = latency_format;
61
62 // Cleanup from any previous initialization.
63 for (size_t i = 0; i < audio_data_.size(); ++i)
64 delete [] audio_data_[i];
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 How about changing audio_data_ to use scoped_array
Chris Rogers 2011/11/10 02:17:22 It seems that scoped_array<> cannot be used with S
65
30 audio_data_.reserve(channels); 66 audio_data_.reserve(channels);
31 for (int i = 0; i < channels; ++i) { 67 for (int i = 0; i < channels; ++i) {
32 float* channel_data = new float[buffer_size]; 68 float* channel_data = new float[buffer_size];
33 audio_data_.push_back(channel_data); 69 audio_data_.push_back(channel_data);
34 } 70 }
35 } 71 }
36 72
73 bool AudioDevice::IsInitialized() {
74 return audio_data_.size() > 0;
75 }
76
37 AudioDevice::~AudioDevice() { 77 AudioDevice::~AudioDevice() {
38 // The current design requires that the user calls Stop() before deleting 78 // The current design requires that the user calls Stop() before deleting
39 // this class. 79 // this class.
40 CHECK_EQ(0, stream_id_); 80 CHECK_EQ(0, stream_id_);
41 for (int i = 0; i < channels_; ++i) 81 for (int i = 0; i < channels_; ++i)
42 delete [] audio_data_[i]; 82 delete [] audio_data_[i];
43 } 83 }
44 84
45 void AudioDevice::Start() { 85 void AudioDevice::Start() {
86 if (stream_id_)
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 Should this be a CHECK_EQ() like elsewhere? We wan
henrika (OOO until Aug 14) 2011/11/09 17:05:22 Why is the existing check in InitializeOnIOThread(
Chris Rogers 2011/11/10 02:17:22 I believe Henrik is right here. This check is not
87 return;
88
46 AudioParameters params; 89 AudioParameters params;
47 params.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 90 params.format = latency_format_;
48 params.channels = channels_; 91 params.channels = channels_;
49 params.sample_rate = static_cast<int>(sample_rate_); 92 params.sample_rate = static_cast<int>(sample_rate_);
50 params.bits_per_sample = bits_per_sample_; 93 params.bits_per_sample = bits_per_sample_;
51 params.samples_per_packet = buffer_size_; 94 params.samples_per_packet = buffer_size_;
52 95
53 ChildProcess::current()->io_message_loop()->PostTask( 96 ChildProcess::current()->io_message_loop()->PostTask(
54 FROM_HERE, 97 FROM_HERE,
55 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); 98 base::Bind(&AudioDevice::InitializeOnIOThread, this, params));
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 Any reason we can't just move all this into Initia
Chris Rogers 2011/11/10 02:17:22 That would change the client-API contract, as we c
56 } 99 }
57 100
58 bool AudioDevice::Stop() { 101 bool AudioDevice::Stop() {
102 if (!stream_id_)
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 CHECK_NE(0, stream_id_) ?
henrika (OOO until Aug 14) 2011/11/09 17:05:22 Similar comment as for Start().
Chris Rogers 2011/11/10 02:17:22 Yes the check that's already in ShutDownOnIOThread
103 return true;
104
59 // Max waiting time for Stop() to complete. If this time limit is passed, 105 // Max waiting time for Stop() to complete. If this time limit is passed,
60 // we will stop waiting and return false. It ensures that Stop() can't block 106 // we will stop waiting and return false. It ensures that Stop() can't block
61 // the calling thread forever. 107 // the calling thread forever.
62 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000); 108 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
63 109
64 base::WaitableEvent completion(false, false); 110 base::WaitableEvent completion(false, false);
65 111
66 ChildProcess::current()->io_message_loop()->PostTask( 112 ChildProcess::current()->io_message_loop()->PostTask(
67 FROM_HERE, 113 FROM_HERE,
68 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion)); 114 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion));
69 115
70 // We wait here for the IO task to be completed to remove race conflicts 116 // We wait here for the IO task to be completed to remove race conflicts
71 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 117 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
72 // function call. 118 // function call.
73 if (completion.TimedWait(kMaxTimeOut)) { 119 if (completion.TimedWait(kMaxTimeOut)) {
74 if (audio_thread_.get()) { 120 if (audio_thread_.get()) {
75 socket_->Close(); 121 socket_->Close();
76 audio_thread_->Join(); 122 audio_thread_->Join();
77 audio_thread_.reset(NULL); 123 audio_thread_.reset(NULL);
78 } 124 }
79 } else { 125 } else {
80 LOG(ERROR) << "Failed to shut down audio output on IO thread"; 126 LOG(ERROR) << "Failed to shut down audio output on IO thread";
81 return false; 127 return false;
82 } 128 }
83 129
84 return true; 130 return true;
85 } 131 }
86 132
133 void AudioDevice::Play() {
134 ChildProcess::current()->io_message_loop()->PostTask(
135 FROM_HERE,
136 base::Bind(&AudioDevice::PlayOnIOThread, this));
137 }
138
139 void AudioDevice::Pause(bool flush) {
henrika (OOO until Aug 14) 2011/11/09 17:05:22 What happens if a user calls Start(), Pause(), Pla
Chris Rogers 2011/11/10 02:17:22 Yes, I think we can make it even simpler and consi
henrika (OOO until Aug 14) 2011/11/10 11:45:07 Fine by me. In general I prefer simple and readabl
Chris Rogers 2011/11/15 22:48:29 I think I've addressed this problem with |play_on_
140 ChildProcess::current()->io_message_loop()->PostTask(
141 FROM_HERE,
142 base::Bind(&AudioDevice::PauseOnIOThread, this, flush));
143 }
144
87 bool AudioDevice::SetVolume(double volume) { 145 bool AudioDevice::SetVolume(double volume) {
88 if (volume < 0 || volume > 1.0) 146 if (volume < 0 || volume > 1.0)
89 return false; 147 return false;
90 148
91 ChildProcess::current()->io_message_loop()->PostTask( 149 ChildProcess::current()->io_message_loop()->PostTask(
92 FROM_HERE, 150 FROM_HERE,
93 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume)); 151 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume));
94 152
95 volume_ = volume; 153 volume_ = volume;
96 154
97 return true; 155 return true;
98 } 156 }
99 157
100 void AudioDevice::GetVolume(double* volume) { 158 void AudioDevice::GetVolume(double* volume) {
101 // Return a locally cached version of the current scaling factor. 159 // Return a locally cached version of the current scaling factor.
102 *volume = volume_; 160 *volume = volume_;
103 } 161 }
104 162
105 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { 163 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) {
106 // Make sure we don't call Start() more than once. 164 // Make sure we don't create the stream more than once.
107 DCHECK_EQ(0, stream_id_); 165 DCHECK_EQ(0, stream_id_);
108 if (stream_id_) 166 if (stream_id_)
109 return; 167 return;
110 168
111 stream_id_ = filter_->AddDelegate(this); 169 stream_id_ = filter_->AddDelegate(this);
112 Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); 170 Send(new AudioHostMsg_CreateStream(stream_id_, params, true));
113 } 171 }
114 172
115 void AudioDevice::StartOnIOThread() { 173 void AudioDevice::PlayOnIOThread() {
116 if (stream_id_) 174 if (stream_id_)
117 Send(new AudioHostMsg_PlayStream(stream_id_)); 175 Send(new AudioHostMsg_PlayStream(stream_id_));
118 } 176 }
119 177
178 void AudioDevice::PauseOnIOThread(bool flush) {
179 if (stream_id_) {
180 Send(new AudioHostMsg_PauseStream(stream_id_));
181 if (flush)
182 Send(new AudioHostMsg_FlushStream(stream_id_));
183 }
184 }
185
120 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) { 186 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
121 // Make sure we don't call shutdown more than once. 187 // Make sure we don't call shutdown more than once.
122 if (!stream_id_) { 188 if (!stream_id_) {
123 completion->Signal(); 189 completion->Signal();
124 return; 190 return;
125 } 191 }
126 192
127 filter_->RemoveDelegate(stream_id_); 193 filter_->RemoveDelegate(stream_id_);
128 Send(new AudioHostMsg_CloseStream(stream_id_)); 194 Send(new AudioHostMsg_CloseStream(stream_id_));
129 stream_id_ = 0; 195 stream_id_ = 0;
130 196
131 completion->Signal(); 197 completion->Signal();
132 } 198 }
133 199
134 void AudioDevice::SetVolumeOnIOThread(double volume) { 200 void AudioDevice::SetVolumeOnIOThread(double volume) {
135 if (stream_id_) 201 if (stream_id_)
136 Send(new AudioHostMsg_SetVolume(stream_id_, volume)); 202 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
137 } 203 }
138 204
139 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { 205 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) {
140 // This method does not apply to the low-latency system. 206 // This method does not apply to the low-latency system.
141 NOTIMPLEMENTED();
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 Why? This and the 2 below.
Chris Rogers 2011/11/10 02:17:22 These are unrelated changes - just part of general
142 } 207 }
143 208
144 void AudioDevice::OnStateChanged(AudioStreamState state) { 209 void AudioDevice::OnStateChanged(AudioStreamState state) {
145 if (state == kAudioStreamError) { 210 if (state == kAudioStreamError) {
146 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)"; 211 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)";
147 } 212 }
148 NOTIMPLEMENTED();
149 } 213 }
150 214
151 void AudioDevice::OnCreated( 215 void AudioDevice::OnCreated(
152 base::SharedMemoryHandle handle, uint32 length) { 216 base::SharedMemoryHandle handle, uint32 length) {
153 // Not needed in this simple implementation. 217 // Not needed in this simple implementation.
154 NOTIMPLEMENTED();
155 } 218 }
156 219
157 void AudioDevice::OnLowLatencyCreated( 220 void AudioDevice::OnLowLatencyCreated(
158 base::SharedMemoryHandle handle, 221 base::SharedMemoryHandle handle,
159 base::SyncSocket::Handle socket_handle, 222 base::SyncSocket::Handle socket_handle,
160 uint32 length) { 223 uint32 length) {
161 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 224 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
162 #if defined(OS_WIN) 225 #if defined(OS_WIN)
163 DCHECK(handle); 226 DCHECK(handle);
164 DCHECK(socket_handle); 227 DCHECK(socket_handle);
(...skipping 19 matching lines...) Expand all
184 socket_.reset(new base::SyncSocket(socket_handle)); 247 socket_.reset(new base::SyncSocket(socket_handle));
185 // Allow the client to pre-populate the buffer. 248 // Allow the client to pre-populate the buffer.
186 FireRenderCallback(); 249 FireRenderCallback();
187 250
188 audio_thread_.reset( 251 audio_thread_.reset(
189 new base::DelegateSimpleThread(this, "renderer_audio_thread")); 252 new base::DelegateSimpleThread(this, "renderer_audio_thread"));
190 audio_thread_->Start(); 253 audio_thread_->Start();
191 254
192 MessageLoop::current()->PostTask( 255 MessageLoop::current()->PostTask(
193 FROM_HERE, 256 FROM_HERE,
194 base::Bind(&AudioDevice::StartOnIOThread, this)); 257 base::Bind(&AudioDevice::PlayOnIOThread, this));
195 } 258 }
196 259
197 void AudioDevice::OnVolume(double volume) { 260 void AudioDevice::OnVolume(double volume) {
198 NOTIMPLEMENTED(); 261 NOTIMPLEMENTED();
199 } 262 }
200 263
201 void AudioDevice::Send(IPC::Message* message) { 264 void AudioDevice::Send(IPC::Message* message) {
202 filter_->Send(message); 265 filter_->Send(message);
203 } 266 }
204 267
205 // Our audio thread runs here. 268 // Our audio thread runs here.
206 void AudioDevice::Run() { 269 void AudioDevice::Run() {
207 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 270 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
208 271
209 int pending_data; 272 int pending_data;
210 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; 273 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
211 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; 274 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
212 275
213 while ((sizeof(pending_data) == socket_->Receive(&pending_data, 276 while (sizeof(pending_data) ==
214 sizeof(pending_data))) && 277 socket_->Receive(&pending_data, sizeof(pending_data))) {
215 (pending_data >= 0)) {
acolwell GONE FROM CHROMIUM 2011/11/08 21:44:20 Why is it safe to remove the >= 0 check?
Chris Rogers 2011/11/10 02:17:22 We need to remove this check, because this case co
acolwell GONE FROM CHROMIUM 2011/11/10 21:58:15 Won't allow pending_data < 0 break the audio_delay
Chris Rogers 2011/11/15 22:48:29 Yes, good point -- fixed. On 2011/11/10 21:58:15,
216
217 // Convert the number of pending bytes in the render buffer 278 // Convert the number of pending bytes in the render buffer
218 // into milliseconds. 279 // into milliseconds.
219 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 280 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
220 FireRenderCallback(); 281 FireRenderCallback();
221 } 282 }
222 } 283 }
223 284
224 void AudioDevice::FireRenderCallback() { 285 void AudioDevice::FireRenderCallback() {
225 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback"); 286 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback");
226 287
(...skipping 20 matching lines...) Expand all
247 308
248 size_t AudioDevice::GetAudioHardwareBufferSize() { 309 size_t AudioDevice::GetAudioHardwareBufferSize() {
249 // Uses cached value if possible. 310 // Uses cached value if possible.
250 static size_t buffer_size = 0; 311 static size_t buffer_size = 0;
251 312
252 if (!buffer_size) 313 if (!buffer_size)
253 buffer_size = media::GetAudioHardwareBufferSize(); 314 buffer_size = media::GetAudioHardwareBufferSize();
254 315
255 return buffer_size; 316 return buffer_size;
256 } 317 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698