OLD | NEW |
---|---|
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/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/process.h" | 9 #include "base/process.h" |
10 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
11 #include "content/browser/renderer_host/media/audio_common.h" | 11 #include "content/browser/renderer_host/media/audio_common.h" |
12 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
13 #include "content/browser/renderer_host/media/media_observer.h" | 13 #include "content/browser/renderer_host/media/media_observer.h" |
14 #include "content/browser/resource_context.h" | 14 #include "content/browser/resource_context.h" |
15 #include "content/common/media/audio_messages.h" | 15 #include "content/common/media/audio_messages.h" |
16 #include "media/audio/audio_util.h" | 16 #include "media/audio/audio_util.h" |
17 #include "ipc/ipc_logging.h" | 17 #include "ipc/ipc_logging.h" |
18 | 18 |
19 using content::BrowserMessageFilter; | 19 using content::BrowserMessageFilter; |
20 using content::BrowserThread; | 20 using content::BrowserThread; |
21 | 21 |
22 AudioRendererHost::AudioEntry::AudioEntry() | 22 AudioRendererHost::AudioEntry::AudioEntry() |
23 : stream_id(0), | 23 : stream_id(0), |
24 pending_buffer_request(false), | |
25 pending_close(false) { | 24 pending_close(false) { |
26 } | 25 } |
27 | 26 |
28 AudioRendererHost::AudioEntry::~AudioEntry() {} | 27 AudioRendererHost::AudioEntry::~AudioEntry() {} |
29 | 28 |
30 /////////////////////////////////////////////////////////////////////////////// | 29 /////////////////////////////////////////////////////////////////////////////// |
31 // AudioRendererHost implementations. | 30 // AudioRendererHost implementations. |
32 AudioRendererHost::AudioRendererHost( | 31 AudioRendererHost::AudioRendererHost( |
33 const content::ResourceContext* resource_context) | 32 const content::ResourceContext* resource_context) |
34 : resource_context_(resource_context), | 33 : resource_context_(resource_context), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
84 | 83 |
85 void AudioRendererHost::OnError(media::AudioOutputController* controller, | 84 void AudioRendererHost::OnError(media::AudioOutputController* controller, |
86 int error_code) { | 85 int error_code) { |
87 BrowserThread::PostTask( | 86 BrowserThread::PostTask( |
88 BrowserThread::IO, | 87 BrowserThread::IO, |
89 FROM_HERE, | 88 FROM_HERE, |
90 base::Bind(&AudioRendererHost::DoHandleError, | 89 base::Bind(&AudioRendererHost::DoHandleError, |
91 this, make_scoped_refptr(controller), error_code)); | 90 this, make_scoped_refptr(controller), error_code)); |
92 } | 91 } |
93 | 92 |
94 void AudioRendererHost::OnMoreData(media::AudioOutputController* controller, | |
95 AudioBuffersState buffers_state) { | |
96 BrowserThread::PostTask( | |
97 BrowserThread::IO, | |
98 FROM_HERE, | |
99 base::Bind(&AudioRendererHost::DoRequestMoreData, | |
100 this, make_scoped_refptr(controller), | |
101 buffers_state)); | |
102 } | |
103 | |
104 void AudioRendererHost::DoCompleteCreation( | 93 void AudioRendererHost::DoCompleteCreation( |
105 media::AudioOutputController* controller) { | 94 media::AudioOutputController* controller) { |
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
107 | 96 |
108 AudioEntry* entry = LookupByController(controller); | 97 AudioEntry* entry = LookupByController(controller); |
109 if (!entry) | 98 if (!entry) |
110 return; | 99 return; |
111 | 100 |
112 if (!peer_handle()) { | 101 if (!peer_handle()) { |
113 NOTREACHED() << "Renderer process handle is invalid."; | 102 NOTREACHED() << "Renderer process handle is invalid."; |
114 DeleteEntryOnError(entry); | 103 DeleteEntryOnError(entry); |
115 return; | 104 return; |
116 } | 105 } |
117 | 106 |
118 // Once the audio stream is created then complete the creation process by | 107 // Once the audio stream is created then complete the creation process by |
119 // mapping shared memory and sharing with the renderer process. | 108 // mapping shared memory and sharing with the renderer process. |
120 base::SharedMemoryHandle foreign_memory_handle; | 109 base::SharedMemoryHandle foreign_memory_handle; |
121 if (!entry->shared_memory.ShareToProcess(peer_handle(), | 110 if (!entry->shared_memory.ShareToProcess(peer_handle(), |
122 &foreign_memory_handle)) { | 111 &foreign_memory_handle)) { |
123 // If we failed to map and share the shared memory then close the audio | 112 // If we failed to map and share the shared memory then close the audio |
124 // stream and send an error message. | 113 // stream and send an error message. |
125 DeleteEntryOnError(entry); | 114 DeleteEntryOnError(entry); |
126 return; | 115 return; |
127 } | 116 } |
128 | 117 |
129 if (entry->controller->LowLatencyMode()) { | 118 AudioSyncReader* reader = |
130 AudioSyncReader* reader = | 119 static_cast<AudioSyncReader*>(entry->reader.get()); |
scherkus (not reviewing)
2012/01/28 02:12:52
do you happen to know why we can't have AudioSyncR
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Doesn't seem like there's a reason not to have it
| |
131 static_cast<AudioSyncReader*>(entry->reader.get()); | |
132 | 120 |
133 #if defined(OS_WIN) | 121 #if defined(OS_WIN) |
134 base::SyncSocket::Handle foreign_socket_handle; | 122 base::SyncSocket::Handle foreign_socket_handle; |
135 #else | 123 #else |
136 base::FileDescriptor foreign_socket_handle; | 124 base::FileDescriptor foreign_socket_handle; |
137 #endif | 125 #endif |
138 | 126 |
139 // If we failed to prepare the sync socket for the renderer then we fail | 127 // If we failed to prepare the sync socket for the renderer then we fail |
140 // the construction of audio stream. | 128 // the construction of audio stream. |
141 if (!reader->PrepareForeignSocketHandle(peer_handle(), | 129 if (!reader->PrepareForeignSocketHandle(peer_handle(), |
142 &foreign_socket_handle)) { | 130 &foreign_socket_handle)) { |
143 DeleteEntryOnError(entry); | 131 DeleteEntryOnError(entry); |
144 return; | |
145 } | |
146 | |
147 Send(new AudioMsg_NotifyLowLatencyStreamCreated( | |
148 entry->stream_id, | |
149 foreign_memory_handle, | |
150 foreign_socket_handle, | |
151 media::PacketSizeSizeInBytes(entry->shared_memory.created_size()))); | |
152 return; | 132 return; |
153 } | 133 } |
154 | 134 |
155 // The normal audio stream has created, send a message to the renderer | 135 Send(new AudioMsg_NotifyLowLatencyStreamCreated( |
henrika (OOO until Aug 14)
2012/01/29 20:54:00
Proposal: remove "LowLatency"
scherkus (not reviewing)
2012/01/30 19:02:00
Yeah I agree w/ henrika here. I didn't suggest it
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Done.
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Done - Except for the audio input-related LowLaten
| |
156 // process. | 136 entry->stream_id, |
157 Send(new AudioMsg_NotifyStreamCreated( | 137 foreign_memory_handle, |
158 entry->stream_id, foreign_memory_handle, | 138 foreign_socket_handle, |
159 entry->shared_memory.created_size())); | 139 media::PacketSizeSizeInBytes(entry->shared_memory.created_size()))); |
160 } | 140 } |
161 | 141 |
162 void AudioRendererHost::DoSendPlayingMessage( | 142 void AudioRendererHost::DoSendPlayingMessage( |
163 media::AudioOutputController* controller) { | 143 media::AudioOutputController* controller) { |
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
165 | 145 |
166 AudioEntry* entry = LookupByController(controller); | 146 AudioEntry* entry = LookupByController(controller); |
167 if (!entry) | 147 if (!entry) |
168 return; | 148 return; |
169 | 149 |
170 Send(new AudioMsg_NotifyStreamStateChanged( | 150 Send(new AudioMsg_NotifyStreamStateChanged( |
171 entry->stream_id, kAudioStreamPlaying)); | 151 entry->stream_id, kAudioStreamPlaying)); |
172 } | 152 } |
173 | 153 |
174 void AudioRendererHost::DoSendPausedMessage( | 154 void AudioRendererHost::DoSendPausedMessage( |
175 media::AudioOutputController* controller) { | 155 media::AudioOutputController* controller) { |
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
177 | 157 |
178 AudioEntry* entry = LookupByController(controller); | 158 AudioEntry* entry = LookupByController(controller); |
179 if (!entry) | 159 if (!entry) |
180 return; | 160 return; |
181 | 161 |
182 Send(new AudioMsg_NotifyStreamStateChanged( | 162 Send(new AudioMsg_NotifyStreamStateChanged( |
183 entry->stream_id, kAudioStreamPaused)); | 163 entry->stream_id, kAudioStreamPaused)); |
184 } | 164 } |
185 | 165 |
186 void AudioRendererHost::DoRequestMoreData( | |
187 media::AudioOutputController* controller, | |
188 AudioBuffersState buffers_state) { | |
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
190 | |
191 // If we already have a pending request then return. | |
192 AudioEntry* entry = LookupByController(controller); | |
193 if (!entry || entry->pending_buffer_request) | |
194 return; | |
195 | |
196 DCHECK(!entry->controller->LowLatencyMode()); | |
197 entry->pending_buffer_request = true; | |
198 Send(new AudioMsg_RequestPacket( | |
199 entry->stream_id, buffers_state)); | |
200 } | |
201 | |
202 void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, | 166 void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, |
203 int error_code) { | 167 int error_code) { |
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
205 | 169 |
206 AudioEntry* entry = LookupByController(controller); | 170 AudioEntry* entry = LookupByController(controller); |
207 if (!entry) | 171 if (!entry) |
208 return; | 172 return; |
209 | 173 |
210 DeleteEntryOnError(entry); | 174 DeleteEntryOnError(entry); |
211 } | 175 } |
212 | 176 |
213 /////////////////////////////////////////////////////////////////////////////// | 177 /////////////////////////////////////////////////////////////////////////////// |
214 // IPC Messages handler | 178 // IPC Messages handler |
215 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, | 179 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, |
216 bool* message_was_ok) { | 180 bool* message_was_ok) { |
217 bool handled = true; | 181 bool handled = true; |
218 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok) | 182 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok) |
219 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) | 183 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) |
220 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) | 184 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) |
221 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) | 185 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) |
222 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) | 186 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) |
223 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) | 187 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) |
224 IPC_MESSAGE_HANDLER(AudioHostMsg_NotifyPacketReady, OnNotifyPacketReady) | |
225 IPC_MESSAGE_HANDLER(AudioHostMsg_GetVolume, OnGetVolume) | |
henrika (OOO until Aug 14)
2012/01/29 20:54:00
Not sure why GetVolume() has been removed and how
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Answered in previous comment!
| |
226 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) | 188 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) |
227 IPC_MESSAGE_UNHANDLED(handled = false) | 189 IPC_MESSAGE_UNHANDLED(handled = false) |
228 IPC_END_MESSAGE_MAP_EX() | 190 IPC_END_MESSAGE_MAP_EX() |
229 | 191 |
230 return handled; | 192 return handled; |
231 } | 193 } |
232 | 194 |
233 void AudioRendererHost::OnCreateStream( | 195 void AudioRendererHost::OnCreateStream( |
234 int stream_id, const AudioParameters& params, bool low_latency) { | 196 int stream_id, const AudioParameters& params) { |
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
236 DCHECK(LookupById(stream_id) == NULL); | 198 DCHECK(LookupById(stream_id) == NULL); |
237 | 199 |
238 AudioParameters audio_params(params); | 200 AudioParameters audio_params(params); |
239 | 201 |
240 // Select the hardware packet size if not specified. | 202 // Select the hardware packet size if not specified. |
241 if (!audio_params.samples_per_packet) { | 203 if (!audio_params.samples_per_packet) { |
242 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); | 204 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); |
243 } | 205 } |
244 uint32 packet_size = audio_params.GetPacketSize(); | 206 uint32 packet_size = audio_params.GetPacketSize(); |
245 | 207 |
246 scoped_ptr<AudioEntry> entry(new AudioEntry()); | 208 scoped_ptr<AudioEntry> entry(new AudioEntry()); |
247 // Create the shared memory and share with the renderer process. | 209 // Create the shared memory and share with the renderer process. |
henrika (OOO until Aug 14)
2012/01/29 20:54:00
New line above comment.
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Done.
| |
248 uint32 shared_memory_size = packet_size; | 210 uint32 shared_memory_size = |
249 if (low_latency) { | 211 media::TotalSharedMemorySizeInBytes(packet_size); |
250 shared_memory_size = | |
251 media::TotalSharedMemorySizeInBytes(shared_memory_size); | |
252 } | |
253 if (!entry->shared_memory.CreateAndMapAnonymous(shared_memory_size)) { | 212 if (!entry->shared_memory.CreateAndMapAnonymous(shared_memory_size)) { |
254 // If creation of shared memory failed then send an error message. | 213 // If creation of shared memory failed then send an error message. |
255 SendErrorMessage(stream_id); | 214 SendErrorMessage(stream_id); |
256 return; | 215 return; |
257 } | 216 } |
258 | 217 |
259 if (low_latency) { | 218 // Create sync reader and try to initialize it. |
260 // If this is the low latency mode, we need to construct a SyncReader first. | 219 scoped_ptr<AudioSyncReader> reader( |
261 scoped_ptr<AudioSyncReader> reader( | 220 new AudioSyncReader(&entry->shared_memory)); |
262 new AudioSyncReader(&entry->shared_memory)); | |
263 | 221 |
264 // Then try to initialize the sync reader. | 222 if (!reader->Init()) { |
265 if (!reader->Init()) { | 223 SendErrorMessage(stream_id); |
266 SendErrorMessage(stream_id); | 224 return; |
267 return; | 225 } |
268 } | |
269 | 226 |
270 // If we have successfully created the SyncReader then assign it to the | 227 // If we have successfully created the SyncReader then assign it to the |
271 // entry and construct an AudioOutputController. | 228 // entry and construct an AudioOutputController. |
272 entry->reader.reset(reader.release()); | 229 entry->reader.reset(reader.release()); |
273 entry->controller = | 230 entry->controller = |
henrika (OOO until Aug 14)
2012/01/29 20:54:00
Is it possible to improve indentation here? Feels
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Done.
| |
274 media::AudioOutputController::CreateLowLatency( | 231 media::AudioOutputController::Create( |
275 resource_context_->audio_manager(), this, audio_params, | 232 resource_context_->audio_manager(), this, audio_params, |
276 entry->reader.get()); | 233 entry->reader.get()); |
277 } else { | |
278 // The choice of buffer capacity is based on experiment. | |
279 entry->controller = | |
280 media::AudioOutputController::Create( | |
281 resource_context_->audio_manager(), this, audio_params, | |
282 3 * packet_size); | |
283 } | |
284 | 234 |
285 if (!entry->controller) { | 235 if (!entry->controller) { |
286 SendErrorMessage(stream_id); | 236 SendErrorMessage(stream_id); |
287 return; | 237 return; |
288 } | 238 } |
289 | 239 |
290 // If we have created the controller successfully create a entry and add it | 240 // If we have created the controller successfully create a entry and add it |
henrika (OOO until Aug 14)
2012/01/29 20:54:00
"an entry"
vrk (LEFT CHROMIUM)
2012/01/31 23:53:08
Done.
| |
291 // to the map. | 241 // to the map. |
292 entry->stream_id = stream_id; | 242 entry->stream_id = stream_id; |
293 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 243 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
294 media_observer()->OnSetAudioStreamStatus(this, stream_id, "created"); | 244 media_observer()->OnSetAudioStreamStatus(this, stream_id, "created"); |
295 } | 245 } |
296 | 246 |
297 void AudioRendererHost::OnPlayStream(int stream_id) { | 247 void AudioRendererHost::OnPlayStream(int stream_id) { |
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
299 | 249 |
300 AudioEntry* entry = LookupById(stream_id); | 250 AudioEntry* entry = LookupById(stream_id); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 return; | 303 return; |
354 } | 304 } |
355 | 305 |
356 // Make sure the volume is valid. | 306 // Make sure the volume is valid. |
357 if (volume < 0 || volume > 1.0) | 307 if (volume < 0 || volume > 1.0) |
358 return; | 308 return; |
359 entry->controller->SetVolume(volume); | 309 entry->controller->SetVolume(volume); |
360 media_observer()->OnSetAudioStreamVolume(this, stream_id, volume); | 310 media_observer()->OnSetAudioStreamVolume(this, stream_id, volume); |
361 } | 311 } |
362 | 312 |
363 void AudioRendererHost::OnGetVolume(int stream_id) { | |
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
365 NOTREACHED() << "This message shouldn't be received"; | |
366 } | |
367 | |
368 void AudioRendererHost::OnNotifyPacketReady(int stream_id, uint32 packet_size) { | |
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
370 | |
371 AudioEntry* entry = LookupById(stream_id); | |
372 if (!entry) { | |
373 SendErrorMessage(stream_id); | |
374 return; | |
375 } | |
376 | |
377 DCHECK(!entry->controller->LowLatencyMode()); | |
378 CHECK(packet_size <= entry->shared_memory.created_size()); | |
379 | |
380 if (!entry->pending_buffer_request) { | |
381 NOTREACHED() << "Buffer received but no such pending request"; | |
382 } | |
383 entry->pending_buffer_request = false; | |
384 | |
385 // Enqueue the data to media::AudioOutputController. | |
386 entry->controller->EnqueueData( | |
387 reinterpret_cast<uint8*>(entry->shared_memory.memory()), | |
388 packet_size); | |
389 } | |
390 | |
391 void AudioRendererHost::SendErrorMessage(int32 stream_id) { | 313 void AudioRendererHost::SendErrorMessage(int32 stream_id) { |
392 Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); | 314 Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); |
393 } | 315 } |
394 | 316 |
395 void AudioRendererHost::DeleteEntries() { | 317 void AudioRendererHost::DeleteEntries() { |
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
397 | 319 |
398 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 320 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
399 i != audio_entries_.end(); ++i) { | 321 i != audio_entries_.end(); ++i) { |
400 CloseAndDeleteStream(i->second); | 322 CloseAndDeleteStream(i->second); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
465 } | 387 } |
466 return NULL; | 388 return NULL; |
467 } | 389 } |
468 | 390 |
469 MediaObserver* AudioRendererHost::media_observer() { | 391 MediaObserver* AudioRendererHost::media_observer() { |
470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
471 if (!media_observer_) | 393 if (!media_observer_) |
472 media_observer_ = resource_context_->media_observer(); | 394 media_observer_ = resource_context_->media_observer(); |
473 return media_observer_; | 395 return media_observer_; |
474 } | 396 } |
OLD | NEW |