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