OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "webrtc/base/checks.h" | 21 #include "webrtc/base/checks.h" |
22 #include "webrtc/base/criticalsection.h" | 22 #include "webrtc/base/criticalsection.h" |
23 #include "webrtc/base/logging.h" | 23 #include "webrtc/base/logging.h" |
24 #include "webrtc/base/thread_annotations.h" | 24 #include "webrtc/base/thread_annotations.h" |
25 #include "webrtc/modules/audio_device/fine_audio_buffer.h" | 25 #include "webrtc/modules/audio_device/fine_audio_buffer.h" |
26 #include "webrtc/modules/utility/include/helpers_ios.h" | 26 #include "webrtc/modules/utility/include/helpers_ios.h" |
27 | 27 |
28 namespace webrtc { | 28 namespace webrtc { |
29 | 29 |
30 // Protects |g_audio_session_users|. | 30 // Protects |g_audio_session_users|. |
31 static rtc::GlobalLockPod g_lock = {{0}}; | 31 static rtc::GlobalLockPod g_lock; |
32 | 32 |
33 // Counts number of users (=instances of this object) who needs an active | 33 // Counts number of users (=instances of this object) who needs an active |
34 // audio session. This variable is used to ensure that we only activate an audio | 34 // audio session. This variable is used to ensure that we only activate an audio |
35 // session for the first user and deactivate it for the last. | 35 // session for the first user and deactivate it for the last. |
36 // Member is static to ensure that the value is counted for all instances | 36 // Member is static to ensure that the value is counted for all instances |
37 // and not per instance. | 37 // and not per instance. |
38 static int g_audio_session_users GUARDED_BY(g_lock) = 0; | 38 static int g_audio_session_users GUARDED_BY(g_lock) = 0; |
39 | 39 |
40 #define LOGI() LOG(LS_INFO) << "AudioDeviceIOS::" | 40 #define LOGI() LOG(LS_INFO) << "AudioDeviceIOS::" |
41 | 41 |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 LOG(LS_INFO) << " system version: " << ios::GetSystemVersion(); | 281 LOG(LS_INFO) << " system version: " << ios::GetSystemVersion(); |
282 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); | 282 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); |
283 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); | 283 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); |
284 } | 284 } |
285 } | 285 } |
286 #endif // !defined(NDEBUG) | 286 #endif // !defined(NDEBUG) |
287 | 287 |
288 AudioDeviceIOS::AudioDeviceIOS() | 288 AudioDeviceIOS::AudioDeviceIOS() |
289 : audio_device_buffer_(nullptr), | 289 : audio_device_buffer_(nullptr), |
290 vpio_unit_(nullptr), | 290 vpio_unit_(nullptr), |
291 recording_({0}), | 291 recording_(0), |
292 playing_({0}), | 292 playing_(0), |
293 initialized_(false), | 293 initialized_(false), |
294 rec_is_initialized_(false), | 294 rec_is_initialized_(false), |
295 play_is_initialized_(false), | 295 play_is_initialized_(false), |
296 audio_interruption_observer_(nullptr), | 296 audio_interruption_observer_(nullptr), |
297 route_change_observer_(nullptr) { | 297 route_change_observer_(nullptr) { |
298 LOGI() << "ctor" << ios::GetCurrentThreadDescription(); | 298 LOGI() << "ctor" << ios::GetCurrentThreadDescription(); |
299 } | 299 } |
300 | 300 |
301 AudioDeviceIOS::~AudioDeviceIOS() { | 301 AudioDeviceIOS::~AudioDeviceIOS() { |
302 LOGI() << "~dtor" << ios::GetCurrentThreadDescription(); | 302 LOGI() << "~dtor" << ios::GetCurrentThreadDescription(); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 RTC_DCHECK_GE(g_audio_session_users, 0); | 352 RTC_DCHECK_GE(g_audio_session_users, 0); |
353 } | 353 } |
354 return 0; | 354 return 0; |
355 } | 355 } |
356 | 356 |
357 int32_t AudioDeviceIOS::InitPlayout() { | 357 int32_t AudioDeviceIOS::InitPlayout() { |
358 LOGI() << "InitPlayout"; | 358 LOGI() << "InitPlayout"; |
359 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 359 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
360 RTC_DCHECK(initialized_); | 360 RTC_DCHECK(initialized_); |
361 RTC_DCHECK(!play_is_initialized_); | 361 RTC_DCHECK(!play_is_initialized_); |
362 RTC_DCHECK(!Playing()); | 362 RTC_DCHECK(!playing_); |
363 if (!rec_is_initialized_) { | 363 if (!rec_is_initialized_) { |
364 if (!InitPlayOrRecord()) { | 364 if (!InitPlayOrRecord()) { |
365 LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitPlayout!"; | 365 LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitPlayout!"; |
366 return -1; | 366 return -1; |
367 } | 367 } |
368 } | 368 } |
369 play_is_initialized_ = true; | 369 play_is_initialized_ = true; |
370 return 0; | 370 return 0; |
371 } | 371 } |
372 | 372 |
373 int32_t AudioDeviceIOS::InitRecording() { | 373 int32_t AudioDeviceIOS::InitRecording() { |
374 LOGI() << "InitRecording"; | 374 LOGI() << "InitRecording"; |
375 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 375 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
376 RTC_DCHECK(initialized_); | 376 RTC_DCHECK(initialized_); |
377 RTC_DCHECK(!rec_is_initialized_); | 377 RTC_DCHECK(!rec_is_initialized_); |
378 RTC_DCHECK(!Recording()); | 378 RTC_DCHECK(!recording_); |
379 if (!play_is_initialized_) { | 379 if (!play_is_initialized_) { |
380 if (!InitPlayOrRecord()) { | 380 if (!InitPlayOrRecord()) { |
381 LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitRecording!"; | 381 LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitRecording!"; |
382 return -1; | 382 return -1; |
383 } | 383 } |
384 } | 384 } |
385 rec_is_initialized_ = true; | 385 rec_is_initialized_ = true; |
386 return 0; | 386 return 0; |
387 } | 387 } |
388 | 388 |
389 int32_t AudioDeviceIOS::StartPlayout() { | 389 int32_t AudioDeviceIOS::StartPlayout() { |
390 LOGI() << "StartPlayout"; | 390 LOGI() << "StartPlayout"; |
391 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 391 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
392 RTC_DCHECK(play_is_initialized_); | 392 RTC_DCHECK(play_is_initialized_); |
393 RTC_DCHECK(!Playing()); | 393 RTC_DCHECK(!playing_); |
394 fine_audio_buffer_->ResetPlayout(); | 394 fine_audio_buffer_->ResetPlayout(); |
395 if (!Recording()) { | 395 if (!recording_) { |
396 OSStatus result = AudioOutputUnitStart(vpio_unit_); | 396 OSStatus result = AudioOutputUnitStart(vpio_unit_); |
397 if (result != noErr) { | 397 if (result != noErr) { |
398 LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartPlayout: " | 398 LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartPlayout: " |
399 << result; | 399 << result; |
400 return -1; | 400 return -1; |
401 } | 401 } |
402 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; | 402 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; |
403 } | 403 } |
404 rtc::AtomicInt::ReleaseStore(&playing_, 1); | 404 rtc::AtomicOps::ReleaseStore(&playing_, 1); |
405 return 0; | 405 return 0; |
406 } | 406 } |
407 | 407 |
408 int32_t AudioDeviceIOS::StopPlayout() { | 408 int32_t AudioDeviceIOS::StopPlayout() { |
409 LOGI() << "StopPlayout"; | 409 LOGI() << "StopPlayout"; |
410 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 410 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
411 if (!play_is_initialized_ || !Playing()) { | 411 if (!play_is_initialized_ || !playing_) { |
412 return 0; | 412 return 0; |
413 } | 413 } |
414 if (!Recording()) { | 414 if (!recording_) { |
415 ShutdownPlayOrRecord(); | 415 ShutdownPlayOrRecord(); |
416 } | 416 } |
417 play_is_initialized_ = false; | 417 play_is_initialized_ = false; |
418 rtc::AtomicInt::ReleaseStore(&playing_, 0); | 418 rtc::AtomicOps::ReleaseStore(&playing_, 0); |
419 return 0; | 419 return 0; |
420 } | 420 } |
421 | 421 |
422 int32_t AudioDeviceIOS::StartRecording() { | 422 int32_t AudioDeviceIOS::StartRecording() { |
423 LOGI() << "StartRecording"; | 423 LOGI() << "StartRecording"; |
424 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 424 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
425 RTC_DCHECK(rec_is_initialized_); | 425 RTC_DCHECK(rec_is_initialized_); |
426 RTC_DCHECK(!Recording()); | 426 RTC_DCHECK(!recording_); |
427 fine_audio_buffer_->ResetRecord(); | 427 fine_audio_buffer_->ResetRecord(); |
428 if (!Playing()) { | 428 if (!playing_) { |
429 OSStatus result = AudioOutputUnitStart(vpio_unit_); | 429 OSStatus result = AudioOutputUnitStart(vpio_unit_); |
430 if (result != noErr) { | 430 if (result != noErr) { |
431 LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartRecording: " | 431 LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartRecording: " |
432 << result; | 432 << result; |
433 return -1; | 433 return -1; |
434 } | 434 } |
435 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; | 435 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; |
436 } | 436 } |
437 rtc::AtomicInt::ReleaseStore(&recording_, 1); | 437 rtc::AtomicOps::ReleaseStore(&recording_, 1); |
438 return 0; | 438 return 0; |
439 } | 439 } |
440 | 440 |
441 int32_t AudioDeviceIOS::StopRecording() { | 441 int32_t AudioDeviceIOS::StopRecording() { |
442 LOGI() << "StopRecording"; | 442 LOGI() << "StopRecording"; |
443 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 443 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
444 if (!rec_is_initialized_ || !Recording()) { | 444 if (!rec_is_initialized_ || !recording_) { |
445 return 0; | 445 return 0; |
446 } | 446 } |
447 if (!Playing()) { | 447 if (!playing_) { |
448 ShutdownPlayOrRecord(); | 448 ShutdownPlayOrRecord(); |
449 } | 449 } |
450 rec_is_initialized_ = false; | 450 rec_is_initialized_ = false; |
451 rtc::AtomicInt::ReleaseStore(&recording_, 0); | 451 rtc::AtomicOps::ReleaseStore(&recording_, 0); |
452 return 0; | 452 return 0; |
453 } | 453 } |
454 | 454 |
455 // Change the default receiver playout route to speaker. | 455 // Change the default receiver playout route to speaker. |
456 int32_t AudioDeviceIOS::SetLoudspeakerStatus(bool enable) { | 456 int32_t AudioDeviceIOS::SetLoudspeakerStatus(bool enable) { |
457 LOGI() << "SetLoudspeakerStatus(" << enable << ")"; | 457 LOGI() << "SetLoudspeakerStatus(" << enable << ")"; |
458 | 458 |
459 AVAudioSession* session = [AVAudioSession sharedInstance]; | 459 AVAudioSession* session = [AVAudioSession sharedInstance]; |
460 NSString* category = session.category; | 460 NSString* category = session.category; |
461 AVAudioSessionCategoryOptions options = session.categoryOptions; | 461 AVAudioSessionCategoryOptions options = session.categoryOptions; |
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 io_action_flags, in_time_stamp, in_bus_number, in_number_frames); | 1021 io_action_flags, in_time_stamp, in_bus_number, in_number_frames); |
1022 } | 1022 } |
1023 | 1023 |
1024 OSStatus AudioDeviceIOS::OnRecordedDataIsAvailable( | 1024 OSStatus AudioDeviceIOS::OnRecordedDataIsAvailable( |
1025 AudioUnitRenderActionFlags* io_action_flags, | 1025 AudioUnitRenderActionFlags* io_action_flags, |
1026 const AudioTimeStamp* in_time_stamp, | 1026 const AudioTimeStamp* in_time_stamp, |
1027 UInt32 in_bus_number, | 1027 UInt32 in_bus_number, |
1028 UInt32 in_number_frames) { | 1028 UInt32 in_number_frames) { |
1029 OSStatus result = noErr; | 1029 OSStatus result = noErr; |
1030 // Simply return if recording is not enabled. | 1030 // Simply return if recording is not enabled. |
1031 if (!Recording()) | 1031 if (!rtc::AtomicOps::AcquireLoad(&recording_)) |
1032 return result; | 1032 return result; |
1033 if (in_number_frames != record_parameters_.frames_per_buffer()) { | 1033 if (in_number_frames != record_parameters_.frames_per_buffer()) { |
1034 // We have seen short bursts (1-2 frames) where |in_number_frames| changes. | 1034 // We have seen short bursts (1-2 frames) where |in_number_frames| changes. |
1035 // Add a log to keep track of longer sequences if that should ever happen. | 1035 // Add a log to keep track of longer sequences if that should ever happen. |
1036 LOG(LS_WARNING) << "in_number_frames (" << in_number_frames | 1036 LOG(LS_WARNING) << "in_number_frames (" << in_number_frames |
1037 << ") != " << record_parameters_.frames_per_buffer(); | 1037 << ") != " << record_parameters_.frames_per_buffer(); |
1038 } | 1038 } |
1039 // Obtain the recorded audio samples by initiating a rendering cycle. | 1039 // Obtain the recorded audio samples by initiating a rendering cycle. |
1040 // Since it happens on the input bus, the |io_data| parameter is a reference | 1040 // Since it happens on the input bus, the |io_data| parameter is a reference |
1041 // to the preallocated audio buffer list that the audio unit renders into. | 1041 // to the preallocated audio buffer list that the audio unit renders into. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 // Verify 16-bit, noninterleaved mono PCM signal format. | 1080 // Verify 16-bit, noninterleaved mono PCM signal format. |
1081 RTC_DCHECK_EQ(1u, io_data->mNumberBuffers); | 1081 RTC_DCHECK_EQ(1u, io_data->mNumberBuffers); |
1082 RTC_DCHECK_EQ(1u, io_data->mBuffers[0].mNumberChannels); | 1082 RTC_DCHECK_EQ(1u, io_data->mBuffers[0].mNumberChannels); |
1083 // Get pointer to internal audio buffer to which new audio data shall be | 1083 // Get pointer to internal audio buffer to which new audio data shall be |
1084 // written. | 1084 // written. |
1085 const UInt32 dataSizeInBytes = io_data->mBuffers[0].mDataByteSize; | 1085 const UInt32 dataSizeInBytes = io_data->mBuffers[0].mDataByteSize; |
1086 RTC_CHECK_EQ(dataSizeInBytes / kBytesPerSample, in_number_frames); | 1086 RTC_CHECK_EQ(dataSizeInBytes / kBytesPerSample, in_number_frames); |
1087 SInt8* destination = static_cast<SInt8*>(io_data->mBuffers[0].mData); | 1087 SInt8* destination = static_cast<SInt8*>(io_data->mBuffers[0].mData); |
1088 // Produce silence and give audio unit a hint about it if playout is not | 1088 // Produce silence and give audio unit a hint about it if playout is not |
1089 // activated. | 1089 // activated. |
1090 if (!Playing()) { | 1090 if (!rtc::AtomicOps::AcquireLoad(&playing_)) { |
1091 *io_action_flags |= kAudioUnitRenderAction_OutputIsSilence; | 1091 *io_action_flags |= kAudioUnitRenderAction_OutputIsSilence; |
1092 memset(destination, 0, dataSizeInBytes); | 1092 memset(destination, 0, dataSizeInBytes); |
1093 return noErr; | 1093 return noErr; |
1094 } | 1094 } |
1095 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches | 1095 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches |
1096 // the native I/O audio unit) to a preallocated intermediate buffer and | 1096 // the native I/O audio unit) to a preallocated intermediate buffer and |
1097 // copy the result to the audio buffer in the |io_data| destination. | 1097 // copy the result to the audio buffer in the |io_data| destination. |
1098 SInt8* source = playout_audio_buffer_.get(); | 1098 SInt8* source = playout_audio_buffer_.get(); |
1099 fine_audio_buffer_->GetPlayoutData(source); | 1099 fine_audio_buffer_->GetPlayoutData(source); |
1100 memcpy(destination, source, dataSizeInBytes); | 1100 memcpy(destination, source, dataSizeInBytes); |
1101 return noErr; | 1101 return noErr; |
1102 } | 1102 } |
1103 | 1103 |
1104 } // namespace webrtc | 1104 } // namespace webrtc |
OLD | NEW |