| 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 |