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_input_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_input_renderer_host.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/process.h" | 8 #include "base/process.h" |
9 #include "base/shared_memory.h" | 9 #include "base/shared_memory.h" |
10 #include "content/browser/renderer_host/media/audio_common.h" | 10 #include "content/browser/renderer_host/media/audio_common.h" |
11 #include "content/browser/renderer_host/media/audio_input_sync_writer.h" | 11 #include "content/browser/renderer_host/media/audio_input_sync_writer.h" |
12 #include "content/common/media/audio_messages.h" | 12 #include "content/common/media/audio_messages.h" |
13 #include "ipc/ipc_logging.h" | 13 #include "ipc/ipc_logging.h" |
14 | 14 |
15 | 15 |
16 AudioInputRendererHost::AudioEntry::AudioEntry() | 16 AudioInputRendererHost::AudioEntry::AudioEntry() |
17 : render_view_id(0), | 17 : stream_id(0), |
18 stream_id(0), | |
19 pending_close(false) { | 18 pending_close(false) { |
20 } | 19 } |
21 | 20 |
22 AudioInputRendererHost::AudioEntry::~AudioEntry() {} | 21 AudioInputRendererHost::AudioEntry::~AudioEntry() {} |
23 | 22 |
24 AudioInputRendererHost::AudioInputRendererHost() {} | 23 AudioInputRendererHost::AudioInputRendererHost() {} |
25 | 24 |
26 AudioInputRendererHost::~AudioInputRendererHost() { | 25 AudioInputRendererHost::~AudioInputRendererHost() { |
27 DCHECK(audio_entries_.empty()); | 26 DCHECK(audio_entries_.empty()); |
28 } | 27 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 } | 72 } |
74 | 73 |
75 void AudioInputRendererHost::OnData(media::AudioInputController* controller, | 74 void AudioInputRendererHost::OnData(media::AudioInputController* controller, |
76 const uint8* data, | 75 const uint8* data, |
77 uint32 size) { | 76 uint32 size) { |
78 NOTREACHED() << "Only low-latency mode is supported."; | 77 NOTREACHED() << "Only low-latency mode is supported."; |
79 } | 78 } |
80 | 79 |
81 void AudioInputRendererHost::DoCompleteCreation( | 80 void AudioInputRendererHost::DoCompleteCreation( |
82 media::AudioInputController* controller) { | 81 media::AudioInputController* controller) { |
83 VLOG(1) << "AudioInputRendererHost::DoCompleteCreation()"; | |
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
85 | 83 |
86 AudioEntry* entry = LookupByController(controller); | 84 AudioEntry* entry = LookupByController(controller); |
87 if (!entry) | 85 if (!entry) |
88 return; | 86 return; |
89 | 87 |
90 if (!peer_handle()) { | 88 if (!peer_handle()) { |
91 NOTREACHED() << "Renderer process handle is invalid."; | 89 NOTREACHED() << "Renderer process handle is invalid."; |
92 DeleteEntryOnError(entry); | 90 DeleteEntryOnError(entry); |
93 return; | 91 return; |
(...skipping 28 matching lines...) Expand all Loading... |
122 | 120 |
123 // If we failed to prepare the sync socket for the renderer then we fail | 121 // If we failed to prepare the sync socket for the renderer then we fail |
124 // the construction of audio input stream. | 122 // the construction of audio input stream. |
125 if (!writer->PrepareForeignSocketHandle(peer_handle(), | 123 if (!writer->PrepareForeignSocketHandle(peer_handle(), |
126 &foreign_socket_handle)) { | 124 &foreign_socket_handle)) { |
127 DeleteEntryOnError(entry); | 125 DeleteEntryOnError(entry); |
128 return; | 126 return; |
129 } | 127 } |
130 | 128 |
131 Send(new AudioInputMsg_NotifyLowLatencyStreamCreated( | 129 Send(new AudioInputMsg_NotifyLowLatencyStreamCreated( |
132 entry->render_view_id, entry->stream_id, foreign_memory_handle, | 130 entry->stream_id, foreign_memory_handle, |
133 foreign_socket_handle, entry->shared_memory.created_size())); | 131 foreign_socket_handle, entry->shared_memory.created_size())); |
134 return; | 132 return; |
135 } | 133 } |
136 } | 134 } |
137 | 135 |
138 void AudioInputRendererHost::DoSendRecordingMessage( | 136 void AudioInputRendererHost::DoSendRecordingMessage( |
139 media::AudioInputController* controller) { | 137 media::AudioInputController* controller) { |
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
141 | 139 |
142 // TODO(henrika): TBI? | 140 // TODO(henrika): TBI? |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream) | 172 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream) |
175 IPC_MESSAGE_HANDLER(AudioInputHostMsg_GetVolume, OnGetVolume) | 173 IPC_MESSAGE_HANDLER(AudioInputHostMsg_GetVolume, OnGetVolume) |
176 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume) | 174 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume) |
177 IPC_MESSAGE_UNHANDLED(handled = false) | 175 IPC_MESSAGE_UNHANDLED(handled = false) |
178 IPC_END_MESSAGE_MAP_EX() | 176 IPC_END_MESSAGE_MAP_EX() |
179 | 177 |
180 return handled; | 178 return handled; |
181 } | 179 } |
182 | 180 |
183 void AudioInputRendererHost::OnCreateStream( | 181 void AudioInputRendererHost::OnCreateStream( |
184 const IPC::Message& msg, int stream_id, | 182 int stream_id, const AudioParameters& params, bool low_latency) { |
185 const AudioParameters& params, bool low_latency) { | |
186 VLOG(1) << "AudioInputRendererHost::OnCreateStream(stream_id=" | 183 VLOG(1) << "AudioInputRendererHost::OnCreateStream(stream_id=" |
187 << stream_id << ")"; | 184 << stream_id << ")"; |
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
189 DCHECK(LookupById(msg.routing_id(), stream_id) == NULL); | 186 DCHECK(LookupById(stream_id) == NULL); |
190 | 187 |
191 // Prevent the renderer process from asking for a normal-latency | 188 // Prevent the renderer process from asking for a normal-latency |
192 // input stream. | 189 // input stream. |
193 if (!low_latency) { | 190 if (!low_latency) { |
194 NOTREACHED() << "Current implementation only supports low-latency mode."; | 191 NOTREACHED() << "Current implementation only supports low-latency mode."; |
195 return; | 192 return; |
196 } | 193 } |
197 | 194 |
198 AudioParameters audio_params(params); | 195 AudioParameters audio_params(params); |
199 | 196 |
200 // Select the hardware packet size if not specified. | 197 // Select the hardware packet size if not specified. |
201 if (!audio_params.samples_per_packet) { | 198 if (!audio_params.samples_per_packet) { |
202 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); | 199 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); |
203 } | 200 } |
204 uint32 packet_size = audio_params.GetPacketSize(); | 201 uint32 packet_size = audio_params.GetPacketSize(); |
205 | 202 |
206 scoped_ptr<AudioEntry> entry(new AudioEntry()); | 203 scoped_ptr<AudioEntry> entry(new AudioEntry()); |
207 // Create the shared memory and share with the renderer process. | 204 // Create the shared memory and share with the renderer process. |
208 if (!entry->shared_memory.CreateAndMapAnonymous(packet_size)) { | 205 if (!entry->shared_memory.CreateAndMapAnonymous(packet_size)) { |
209 // If creation of shared memory failed then send an error message. | 206 // If creation of shared memory failed then send an error message. |
210 SendErrorMessage(msg.routing_id(), stream_id); | 207 SendErrorMessage(stream_id); |
211 return; | 208 return; |
212 } | 209 } |
213 | 210 |
214 // This is a low latency mode, hence we need to construct a SyncWriter first. | 211 // This is a low latency mode, hence we need to construct a SyncWriter first. |
215 scoped_ptr<AudioInputSyncWriter> writer( | 212 scoped_ptr<AudioInputSyncWriter> writer( |
216 new AudioInputSyncWriter(&entry->shared_memory)); | 213 new AudioInputSyncWriter(&entry->shared_memory)); |
217 | 214 |
218 // Then try to initialize the sync writer. | 215 // Then try to initialize the sync writer. |
219 if (!writer->Init()) { | 216 if (!writer->Init()) { |
220 SendErrorMessage(msg.routing_id(), stream_id); | 217 SendErrorMessage(stream_id); |
221 return; | 218 return; |
222 } | 219 } |
223 | 220 |
224 // If we have successfully created the SyncWriter then assign it to the | 221 // If we have successfully created the SyncWriter then assign it to the |
225 // entry and construct an AudioInputController. | 222 // entry and construct an AudioInputController. |
226 entry->writer.reset(writer.release()); | 223 entry->writer.reset(writer.release()); |
227 entry->controller = | 224 entry->controller = |
228 media::AudioInputController::CreateLowLatency(this, | 225 media::AudioInputController::CreateLowLatency(this, |
229 audio_params, | 226 audio_params, |
230 entry->writer.get()); | 227 entry->writer.get()); |
231 | 228 |
232 if (!entry->controller) { | 229 if (!entry->controller) { |
233 SendErrorMessage(msg.routing_id(), stream_id); | 230 SendErrorMessage(stream_id); |
234 return; | 231 return; |
235 } | 232 } |
236 | 233 |
237 // If we have created the controller successfully create a entry and add it | 234 // If we have created the controller successfully create a entry and add it |
238 // to the map. | 235 // to the map. |
239 entry->render_view_id = msg.routing_id(); | |
240 entry->stream_id = stream_id; | 236 entry->stream_id = stream_id; |
241 | 237 |
242 audio_entries_.insert(std::make_pair( | 238 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
243 AudioEntryId(msg.routing_id(), stream_id), | |
244 entry.release())); | |
245 } | 239 } |
246 | 240 |
247 void AudioInputRendererHost::OnRecordStream(const IPC::Message& msg, | 241 void AudioInputRendererHost::OnRecordStream(int stream_id) { |
248 int stream_id) { | |
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
250 | 243 |
251 AudioEntry* entry = LookupById(msg.routing_id(), stream_id); | 244 AudioEntry* entry = LookupById(stream_id); |
252 if (!entry) { | 245 if (!entry) { |
253 SendErrorMessage(msg.routing_id(), stream_id); | 246 SendErrorMessage(stream_id); |
254 return; | 247 return; |
255 } | 248 } |
256 | 249 |
257 entry->controller->Record(); | 250 entry->controller->Record(); |
258 } | 251 } |
259 | 252 |
260 void AudioInputRendererHost::OnCloseStream(const IPC::Message& msg, | 253 void AudioInputRendererHost::OnCloseStream(int stream_id) { |
261 int stream_id) { | |
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
263 | 255 |
264 AudioEntry* entry = LookupById(msg.routing_id(), stream_id); | 256 AudioEntry* entry = LookupById(stream_id); |
265 | 257 |
266 if (entry) | 258 if (entry) |
267 CloseAndDeleteStream(entry); | 259 CloseAndDeleteStream(entry); |
268 } | 260 } |
269 | 261 |
270 void AudioInputRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, | 262 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) { |
271 double volume) { | |
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
273 | 264 |
274 AudioEntry* entry = LookupById(msg.routing_id(), stream_id); | 265 AudioEntry* entry = LookupById(stream_id); |
275 if (!entry) { | 266 if (!entry) { |
276 SendErrorMessage(msg.routing_id(), stream_id); | 267 SendErrorMessage(stream_id); |
277 return; | 268 return; |
278 } | 269 } |
279 | 270 |
280 // TODO(henrika): TBI. | 271 // TODO(henrika): TBI. |
281 NOTIMPLEMENTED(); | 272 NOTIMPLEMENTED(); |
282 } | 273 } |
283 | 274 |
284 void AudioInputRendererHost::OnGetVolume(const IPC::Message& msg, | 275 void AudioInputRendererHost::OnGetVolume(int stream_id) { |
285 int stream_id) { | |
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
287 | 277 |
288 AudioEntry* entry = LookupById(msg.routing_id(), stream_id); | 278 AudioEntry* entry = LookupById(stream_id); |
289 if (!entry) { | 279 if (!entry) { |
290 SendErrorMessage(msg.routing_id(), stream_id); | 280 SendErrorMessage(stream_id); |
291 return; | 281 return; |
292 } | 282 } |
293 | 283 |
294 // TODO(henrika): TBI. | 284 // TODO(henrika): TBI. |
295 NOTIMPLEMENTED(); | 285 NOTIMPLEMENTED(); |
296 } | 286 } |
297 | 287 |
298 void AudioInputRendererHost::SendErrorMessage(int32 render_view_id, | 288 void AudioInputRendererHost::SendErrorMessage(int stream_id) { |
299 int32 stream_id) { | |
300 // TODO(henrika): error state for audio input is not unique | 289 // TODO(henrika): error state for audio input is not unique |
301 Send(new AudioMsg_NotifyStreamStateChanged(render_view_id, | 290 Send(new AudioMsg_NotifyStreamStateChanged(stream_id, |
302 stream_id, | |
303 kAudioStreamError)); | 291 kAudioStreamError)); |
304 } | 292 } |
305 | 293 |
306 void AudioInputRendererHost::DeleteEntries() { | 294 void AudioInputRendererHost::DeleteEntries() { |
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
308 | 296 |
309 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 297 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
310 i != audio_entries_.end(); ++i) { | 298 i != audio_entries_.end(); ++i) { |
311 CloseAndDeleteStream(i->second); | 299 CloseAndDeleteStream(i->second); |
312 } | 300 } |
(...skipping 17 matching lines...) Expand all Loading... |
330 NewRunnableMethod(this, &AudioInputRendererHost::DeleteEntry, entry)); | 318 NewRunnableMethod(this, &AudioInputRendererHost::DeleteEntry, entry)); |
331 } | 319 } |
332 | 320 |
333 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { | 321 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { |
334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
335 | 323 |
336 // Delete the entry when this method goes out of scope. | 324 // Delete the entry when this method goes out of scope. |
337 scoped_ptr<AudioEntry> entry_deleter(entry); | 325 scoped_ptr<AudioEntry> entry_deleter(entry); |
338 | 326 |
339 // Erase the entry from the map. | 327 // Erase the entry from the map. |
340 audio_entries_.erase( | 328 audio_entries_.erase(entry->stream_id); |
341 AudioEntryId(entry->render_view_id, entry->stream_id)); | |
342 } | 329 } |
343 | 330 |
344 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) { | 331 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) { |
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
346 | 333 |
347 // Sends the error message first before we close the stream because | 334 // Sends the error message first before we close the stream because |
348 // |entry| is destroyed in DeleteEntry(). | 335 // |entry| is destroyed in DeleteEntry(). |
349 SendErrorMessage(entry->render_view_id, entry->stream_id); | 336 SendErrorMessage(entry->stream_id); |
350 CloseAndDeleteStream(entry); | 337 CloseAndDeleteStream(entry); |
351 } | 338 } |
352 | 339 |
353 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById( | 340 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById( |
354 int route_id, int stream_id) { | 341 int stream_id) { |
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
356 | 343 |
357 AudioEntryMap::iterator i = audio_entries_.find( | 344 AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
358 AudioEntryId(route_id, stream_id)); | |
359 if (i != audio_entries_.end()) | 345 if (i != audio_entries_.end()) |
360 return i->second; | 346 return i->second; |
361 return NULL; | 347 return NULL; |
362 } | 348 } |
363 | 349 |
364 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController( | 350 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController( |
365 media::AudioInputController* controller) { | 351 media::AudioInputController* controller) { |
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
367 | 353 |
368 // Iterate the map of entries. | 354 // Iterate the map of entries. |
369 // TODO(hclam): Implement a faster look up method. | 355 // TODO(hclam): Implement a faster look up method. |
370 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 356 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
371 i != audio_entries_.end(); ++i) { | 357 i != audio_entries_.end(); ++i) { |
372 if (controller == i->second->controller.get()) | 358 if (controller == i->second->controller.get()) |
373 return i->second; | 359 return i->second; |
374 } | 360 } |
375 return NULL; | 361 return NULL; |
376 } | 362 } |
OLD | NEW |