Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: webrtc/modules/audio_device/ios/audio_device_ios.mm

Issue 1945563003: Provide isAudioEnabled flag to control audio unit. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix some bluetooth issue. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 } \ 54 } \
55 } while (0) 55 } while (0)
56 56
57 57
58 // Hardcoded delay estimates based on real measurements. 58 // Hardcoded delay estimates based on real measurements.
59 // TODO(henrika): these value is not used in combination with built-in AEC. 59 // TODO(henrika): these value is not used in combination with built-in AEC.
60 // Can most likely be removed. 60 // Can most likely be removed.
61 const UInt16 kFixedPlayoutDelayEstimate = 30; 61 const UInt16 kFixedPlayoutDelayEstimate = 30;
62 const UInt16 kFixedRecordDelayEstimate = 30; 62 const UInt16 kFixedRecordDelayEstimate = 30;
63 63
64 enum AudioDeviceMessageType : uint32_t {
65 kMessageTypeInterruptionBegin,
66 kMessageTypeInterruptionEnd,
67 kMessageTypeValidRouteChange,
68 kMessageTypeCanPlayOrRecordChange,
69 kMessageTypeSampleRateChange,
70 };
71
64 using ios::CheckAndLogError; 72 using ios::CheckAndLogError;
65 73
66 #if !defined(NDEBUG) 74 #if !defined(NDEBUG)
67 // Helper method that logs essential device information strings. 75 // Helper method that logs essential device information strings.
68 static void LogDeviceInfo() { 76 static void LogDeviceInfo() {
69 LOG(LS_INFO) << "LogDeviceInfo"; 77 LOG(LS_INFO) << "LogDeviceInfo";
70 @autoreleasepool { 78 @autoreleasepool {
71 LOG(LS_INFO) << " system name: " << ios::GetSystemName(); 79 LOG(LS_INFO) << " system name: " << ios::GetSystemName();
72 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString(); 80 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString();
73 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion(); 81 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion();
74 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); 82 LOG(LS_INFO) << " device type: " << ios::GetDeviceType();
75 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); 83 LOG(LS_INFO) << " device name: " << ios::GetDeviceName();
76 LOG(LS_INFO) << " process name: " << ios::GetProcessName(); 84 LOG(LS_INFO) << " process name: " << ios::GetProcessName();
77 LOG(LS_INFO) << " process ID: " << ios::GetProcessID(); 85 LOG(LS_INFO) << " process ID: " << ios::GetProcessID();
78 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString(); 86 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString();
79 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount(); 87 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount();
80 #if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 88 #if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
81 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled(); 89 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled();
82 #endif 90 #endif
83 } 91 }
84 } 92 }
85 #endif // !defined(NDEBUG) 93 #endif // !defined(NDEBUG)
86 94
87 AudioDeviceIOS::AudioDeviceIOS() 95 AudioDeviceIOS::AudioDeviceIOS()
88 : async_invoker_(new rtc::AsyncInvoker()), 96 : audio_device_buffer_(nullptr),
89 audio_device_buffer_(nullptr),
90 audio_unit_(nullptr), 97 audio_unit_(nullptr),
91 recording_(0), 98 recording_(0),
92 playing_(0), 99 playing_(0),
93 initialized_(false), 100 initialized_(false),
94 rec_is_initialized_(false), 101 rec_is_initialized_(false),
95 play_is_initialized_(false), 102 play_is_initialized_(false),
96 is_interrupted_(false) { 103 is_interrupted_(false),
104 has_configured_session_(false) {
97 LOGI() << "ctor" << ios::GetCurrentThreadDescription(); 105 LOGI() << "ctor" << ios::GetCurrentThreadDescription();
98 thread_ = rtc::Thread::Current(); 106 thread_ = rtc::Thread::Current();
99 audio_session_observer_ = 107 audio_session_observer_ =
100 [[RTCAudioSessionDelegateAdapter alloc] initWithObserver:this]; 108 [[RTCAudioSessionDelegateAdapter alloc] initWithObserver:this];
101 } 109 }
102 110
103 AudioDeviceIOS::~AudioDeviceIOS() { 111 AudioDeviceIOS::~AudioDeviceIOS() {
104 LOGI() << "~dtor" << ios::GetCurrentThreadDescription(); 112 LOGI() << "~dtor" << ios::GetCurrentThreadDescription();
105 audio_session_observer_ = nil; 113 audio_session_observer_ = nil;
106 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 114 RTC_DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 319
312 int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const { 320 int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const {
313 LOGI() << "GetRecordAudioParameters"; 321 LOGI() << "GetRecordAudioParameters";
314 RTC_DCHECK(record_parameters_.is_valid()); 322 RTC_DCHECK(record_parameters_.is_valid());
315 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 323 RTC_DCHECK(thread_checker_.CalledOnValidThread());
316 *params = record_parameters_; 324 *params = record_parameters_;
317 return 0; 325 return 0;
318 } 326 }
319 327
320 void AudioDeviceIOS::OnInterruptionBegin() { 328 void AudioDeviceIOS::OnInterruptionBegin() {
321 RTC_DCHECK(async_invoker_);
322 RTC_DCHECK(thread_); 329 RTC_DCHECK(thread_);
323 if (thread_->IsCurrent()) { 330 thread_->Post(this, kMessageTypeInterruptionBegin);
324 HandleInterruptionBegin();
325 return;
326 }
327 async_invoker_->AsyncInvoke<void>(
328 thread_,
329 rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionBegin, this));
330 } 331 }
331 332
332 void AudioDeviceIOS::OnInterruptionEnd() { 333 void AudioDeviceIOS::OnInterruptionEnd() {
333 RTC_DCHECK(async_invoker_);
334 RTC_DCHECK(thread_); 334 RTC_DCHECK(thread_);
335 if (thread_->IsCurrent()) { 335 thread_->Post(this, kMessageTypeInterruptionEnd);
336 HandleInterruptionEnd();
337 return;
338 }
339 async_invoker_->AsyncInvoke<void>(
340 thread_,
341 rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionEnd, this));
342 } 336 }
343 337
344 void AudioDeviceIOS::OnValidRouteChange() { 338 void AudioDeviceIOS::OnValidRouteChange() {
345 RTC_DCHECK(async_invoker_);
346 RTC_DCHECK(thread_); 339 RTC_DCHECK(thread_);
347 if (thread_->IsCurrent()) { 340 thread_->Post(this, kMessageTypeValidRouteChange);
348 HandleValidRouteChange();
349 return;
350 }
351 async_invoker_->AsyncInvoke<void>(
352 thread_,
353 rtc::Bind(&webrtc::AudioDeviceIOS::HandleValidRouteChange, this));
354 } 341 }
355 342
356 void AudioDeviceIOS::OnConfiguredForWebRTC() { 343 void AudioDeviceIOS::OnCanPlayOrRecordChange(bool can_play_or_record) {
357 RTC_DCHECK(async_invoker_);
358 RTC_DCHECK(thread_); 344 RTC_DCHECK(thread_);
359 if (thread_->IsCurrent()) { 345 thread_->Post(this, kMessageTypeCanPlayOrRecordChange,
360 HandleValidRouteChange(); 346 new rtc::TypedMessageData<bool>(can_play_or_record));
361 return;
362 }
363 async_invoker_->AsyncInvoke<void>(
364 thread_,
365 rtc::Bind(&webrtc::AudioDeviceIOS::HandleConfiguredForWebRTC, this));
366 } 347 }
367 348
368 OSStatus AudioDeviceIOS::OnDeliverRecordedData( 349 OSStatus AudioDeviceIOS::OnDeliverRecordedData(
369 AudioUnitRenderActionFlags* flags, 350 AudioUnitRenderActionFlags* flags,
370 const AudioTimeStamp* time_stamp, 351 const AudioTimeStamp* time_stamp,
371 UInt32 bus_number, 352 UInt32 bus_number,
372 UInt32 num_frames, 353 UInt32 num_frames,
373 AudioBufferList* /* io_data */) { 354 AudioBufferList* /* io_data */) {
374 OSStatus result = noErr; 355 OSStatus result = noErr;
375 // Simply return if recording is not enabled. 356 // Simply return if recording is not enabled.
376 if (!rtc::AtomicOps::AcquireLoad(&recording_)) 357 if (!rtc::AtomicOps::AcquireLoad(&recording_))
377 return result; 358 return result;
378 359
379 size_t frames_per_buffer = record_parameters_.frames_per_buffer(); 360 size_t frames_per_buffer = record_parameters_.frames_per_buffer();
380 if (num_frames != frames_per_buffer) { 361 if (num_frames != frames_per_buffer) {
381 // We have seen short bursts (1-2 frames) where |in_number_frames| changes. 362 // We have seen short bursts (1-2 frames) where |in_number_frames| changes.
382 // Add a log to keep track of longer sequences if that should ever happen. 363 // Add a log to keep track of longer sequences if that should ever happen.
383 // Also return since calling AudioUnitRender in this state will only result 364 // Also return since calling AudioUnitRender in this state will only result
384 // in kAudio_ParamError (-50) anyhow. 365 // in kAudio_ParamError (-50) anyhow.
385 RTCLogWarning(@"Expected %u frames but got %u", 366 RTCLogWarning(@"Expected %u frames but got %u",
386 static_cast<unsigned int>(frames_per_buffer), 367 static_cast<unsigned int>(frames_per_buffer),
387 static_cast<unsigned int>(num_frames)); 368 static_cast<unsigned int>(num_frames));
369
370 RTCAudioSession *session = [RTCAudioSession sharedInstance];
371 RTCLogWarning(@"Session:\n %@", session);
388 return result; 372 return result;
389 } 373 }
390 374
391 // Obtain the recorded audio samples by initiating a rendering cycle. 375 // Obtain the recorded audio samples by initiating a rendering cycle.
392 // Since it happens on the input bus, the |io_data| parameter is a reference 376 // Since it happens on the input bus, the |io_data| parameter is a reference
393 // to the preallocated audio buffer list that the audio unit renders into. 377 // to the preallocated audio buffer list that the audio unit renders into.
394 // We can make the audio unit provide a buffer instead in io_data, but we 378 // We can make the audio unit provide a buffer instead in io_data, but we
395 // currently just use our own. 379 // currently just use our own.
396 // TODO(henrika): should error handling be improved? 380 // TODO(henrika): should error handling be improved?
397 AudioBufferList* io_data = &audio_record_buffer_list_; 381 AudioBufferList* io_data = &audio_record_buffer_list_;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 } 424 }
441 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches 425 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches
442 // the native I/O audio unit) to a preallocated intermediate buffer and 426 // the native I/O audio unit) to a preallocated intermediate buffer and
443 // copy the result to the audio buffer in the |io_data| destination. 427 // copy the result to the audio buffer in the |io_data| destination.
444 int8_t* source = playout_audio_buffer_.get(); 428 int8_t* source = playout_audio_buffer_.get();
445 fine_audio_buffer_->GetPlayoutData(source); 429 fine_audio_buffer_->GetPlayoutData(source);
446 memcpy(destination, source, size_in_bytes); 430 memcpy(destination, source, size_in_bytes);
447 return noErr; 431 return noErr;
448 } 432 }
449 433
434 void AudioDeviceIOS::OnSampleRateChange(float sample_rate) {
435 RTC_DCHECK(thread_);
436 thread_->Post(this, kMessageTypeSampleRateChange,
437 new rtc::TypedMessageData<float>(sample_rate));
438 }
439
440 void AudioDeviceIOS::OnMessage(rtc::Message *msg) {
henrika_webrtc 2016/05/04 12:33:07 nice!
tkchin_webrtc 2016/05/05 23:23:27 Acknowledged.
441 switch (msg->message_id) {
442 case kMessageTypeInterruptionBegin:
443 HandleInterruptionBegin();
444 break;
445 case kMessageTypeInterruptionEnd:
446 HandleInterruptionEnd();
447 break;
448 case kMessageTypeValidRouteChange:
449 HandleValidRouteChange();
450 break;
451 case kMessageTypeCanPlayOrRecordChange: {
452 rtc::TypedMessageData<bool>* data =
453 static_cast<rtc::TypedMessageData<bool>*>(msg->pdata);
454 HandleCanPlayOrRecordChange(data->data());
455 delete data;
456 break;
457 }
458 case kMessageTypeSampleRateChange: {
459 rtc::TypedMessageData<float>* data =
460 static_cast<rtc::TypedMessageData<float>*>(msg->pdata);
461 HandleSampleRateChange(data->data());
462 delete data;
463 break;
464 }
465 }
466 }
467
450 void AudioDeviceIOS::HandleInterruptionBegin() { 468 void AudioDeviceIOS::HandleInterruptionBegin() {
451 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 469 RTC_DCHECK(thread_checker_.CalledOnValidThread());
452 470
453 RTCLog(@"Stopping the audio unit due to interruption begin."); 471 RTCLog(@"Stopping the audio unit due to interruption begin.");
454 if (!audio_unit_->Stop()) { 472 if (!audio_unit_->Stop()) {
455 RTCLogError(@"Failed to stop the audio unit."); 473 RTCLogError(@"Failed to stop the audio unit.");
456 } 474 }
457 is_interrupted_ = true; 475 is_interrupted_ = true;
458 } 476 }
459 477
460 void AudioDeviceIOS::HandleInterruptionEnd() { 478 void AudioDeviceIOS::HandleInterruptionEnd() {
461 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 479 RTC_DCHECK(thread_checker_.CalledOnValidThread());
462 480
463 RTCLog(@"Starting the audio unit due to interruption end."); 481 RTCLog(@"Starting the audio unit due to interruption end.");
464 if (!audio_unit_->Start()) { 482 if (!audio_unit_->Start()) {
465 RTCLogError(@"Failed to start the audio unit."); 483 RTCLogError(@"Failed to start the audio unit.");
466 } 484 }
467 is_interrupted_ = false; 485 is_interrupted_ = false;
468 } 486 }
469 487
470 void AudioDeviceIOS::HandleValidRouteChange() { 488 void AudioDeviceIOS::HandleValidRouteChange() {
471 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 489 RTC_DCHECK(thread_checker_.CalledOnValidThread());
472 490
473 // Don't do anything if we're interrupted.
474 if (is_interrupted_) {
475 return;
476 }
477
478 // Only restart audio for a valid route change if the session sample rate
479 // has changed.
480 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 491 RTCAudioSession* session = [RTCAudioSession sharedInstance];
481 const double current_sample_rate = playout_parameters_.sample_rate(); 492 HandleSampleRateChange(session.sampleRate);
482 const double session_sample_rate = session.sampleRate;
483 if (current_sample_rate != session_sample_rate) {
484 RTCLog(@"Route changed caused sample rate to change from %f to %f. "
485 "Restarting audio unit.", current_sample_rate, session_sample_rate);
486 if (!RestartAudioUnit(session_sample_rate)) {
487 RTCLogError(@"Audio restart failed.");
488 }
489 }
490 } 493 }
491 494
492 void AudioDeviceIOS::HandleConfiguredForWebRTC() { 495 void AudioDeviceIOS::HandleCanPlayOrRecordChange(bool can_play_or_record) {
493 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 496 RTC_DCHECK(thread_checker_.CalledOnValidThread());
497 RTCLog(@"Handling CanPlayOrRecordChange to %d", can_play_or_record);
494 498
495 // If we're not initialized we don't need to do anything. Audio unit will 499 // If we're not initialized we don't need to do anything. Audio unit will
496 // be initialized on initialization. 500 // be initialized on initialization.
497 if (!rec_is_initialized_ && !play_is_initialized_) 501 if (!rec_is_initialized_ && !play_is_initialized_)
498 return; 502 return;
499 503
500 // If we're initialized, we must have an audio unit. 504 // If we're initialized, we must have an audio unit.
501 RTC_DCHECK(audio_unit_); 505 RTC_DCHECK(audio_unit_);
502 506
503 // Use configured audio session's settings to set up audio device buffer. 507 bool should_initialize_audio_unit = false;
504 // TODO(tkchin): Use RTCAudioSessionConfiguration to pick up settings and 508 bool should_uninitialize_audio_unit = false;
505 // pass it along. 509 bool should_start_audio_unit = false;
506 SetupAudioBuffersForActiveAudioSession(); 510 bool should_stop_audio_unit = false;
507 511
508 // Initialize the audio unit. This will affect any existing audio playback. 512 switch (audio_unit_->GetState()) {
509 if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) { 513 case VoiceProcessingAudioUnit::kInitRequired:
510 RTCLogError(@"Failed to initialize audio unit after configuration."); 514 RTC_NOTREACHED();
515 break;
516 case VoiceProcessingAudioUnit::kUninitialized:
517 should_initialize_audio_unit = can_play_or_record;
518 should_start_audio_unit = should_initialize_audio_unit &&
519 (playing_ || recording_);
520 break;
521 case VoiceProcessingAudioUnit::kInitialized:
522 should_start_audio_unit = can_play_or_record && (playing_ || recording_);
523 should_uninitialize_audio_unit = !can_play_or_record;
524 break;
525 case VoiceProcessingAudioUnit::kStarted:
526 RTC_DCHECK(playing_ || recording_);
527 should_stop_audio_unit = !can_play_or_record;
528 should_uninitialize_audio_unit = should_stop_audio_unit;
529 break;
530 }
531
532 if (should_initialize_audio_unit) {
533 RTCLog(@"Initializing audio unit for CanPlayOrRecordChange");
534 // Mad hack: Sometimes the audio session is already active because the app
henrika_webrtc 2016/05/04 12:33:07 Wow. Do you have a case where you can reliably tes
tkchin_webrtc 2016/05/05 23:23:27 Yup. With my BT headset. I'm backing out the chang
henrika_webrtc 2016/05/06 11:22:16 Acknowledged.
535 // activated it. In this condition, the audio session reports an inaccurate
536 // IOBufferDuration until the audio unit is started, but this causes audio
537 // artifacts. To work around it, deactivate it forcibly and reactivate it.
538 // This only works if the app has only activated the session once.
539 RTCAudioSession *session = [RTCAudioSession sharedInstance];
540 BOOL refreshAudioSession = session.isActive;
541 if (refreshAudioSession) {
542 [session lockForConfiguration];
543 [session setActive:NO error:nil];
544 [session unlockForConfiguration];
545 }
546 ConfigureAudioSession();
547 if (refreshAudioSession) {
548 [session lockForConfiguration];
549 [session setActive:YES error:nil];
550 [session unlockForConfiguration];
551 }
552 SetupAudioBuffersForActiveAudioSession();
553 if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
554 RTCLogError(@"Failed to initialize audio unit.");
555 return;
556 }
557 }
558
559 if (should_start_audio_unit) {
560 RTCLog(@"Starting audio unit for CanPlayOrRecordChange");
561 if (!audio_unit_->Start()) {
562 RTCLogError(@"Failed to start audio unit.");
563 return;
564 }
565 }
566
567 if (should_stop_audio_unit) {
568 RTCLog(@"Stopping audio unit for CanPlayOrRecordChange");
569 if (!audio_unit_->Stop()) {
570 RTCLogError(@"Failed to stop audio unit.");
571 return;
572 }
573 }
574
575 if (should_uninitialize_audio_unit) {
576 RTCLog(@"Uninitializing audio unit for CanPlayOrRecordChange");
577 audio_unit_->Uninitialize();
578 UnconfigureAudioSession();
579 }
580 }
581
582 void AudioDeviceIOS::HandleSampleRateChange(float sample_rate) {
583 RTC_DCHECK(thread_checker_.CalledOnValidThread());
584
585 // Don't do anything if we're interrupted.
586 if (is_interrupted_) {
511 return; 587 return;
512 } 588 }
513 589
514 // If we haven't started playing or recording there's nothing more to do. 590 RTCAudioSession* session = [RTCAudioSession sharedInstance];
515 if (!playing_ && !recording_) 591 const double session_sample_rate = session.sampleRate;
516 return; 592 const NSTimeInterval session_buffer_duration = session.IOBufferDuration;
593 const size_t session_frames_per_buffer =
594 static_cast<size_t>(session_sample_rate * session_buffer_duration + .5);
595 const double current_sample_rate = playout_parameters_.sample_rate();
596 const size_t current_frames_per_buffer =
597 playout_parameters_.frames_per_buffer();
598 RTCLog(@"Handling playout sample rate change to: %f\n"
599 " Session sample rate: %f frames_per_buffer: %lu\n"
600 " ADM sample rate: %f frames_per_buffer: %lu",
601 sample_rate,
602 session_sample_rate, (unsigned long)session_frames_per_buffer,
603 current_sample_rate, (unsigned long)current_frames_per_buffer);;
517 604
518 // We are in a play or record state, start the audio unit. 605 if (current_sample_rate != session_sample_rate ||
519 if (!audio_unit_->Start()) { 606 current_frames_per_buffer != session_frames_per_buffer) {
520 RTCLogError(@"Failed to start audio unit after configuration."); 607 RTCLog(@"Restarting audio unit due to frames per buffer change.");
521 return; 608 if (!RestartAudioUnit(sample_rate)) {
609 RTCLogError(@"Audio restart failed.");
610 }
522 } 611 }
523 } 612 }
524 613
525 void AudioDeviceIOS::UpdateAudioDeviceBuffer() { 614 void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
526 LOGI() << "UpdateAudioDevicebuffer"; 615 LOGI() << "UpdateAudioDevicebuffer";
527 // AttachAudioBuffer() is called at construction by the main class but check 616 // AttachAudioBuffer() is called at construction by the main class but check
528 // just in case. 617 // just in case.
529 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first"; 618 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first";
530 // Inform the audio device buffer (ADB) about the new audio format. 619 // Inform the audio device buffer (ADB) about the new audio format.
531 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate()); 620 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate());
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 << required_playout_buffer_size; 679 << required_playout_buffer_size;
591 playout_audio_buffer_.reset(new SInt8[required_playout_buffer_size]); 680 playout_audio_buffer_.reset(new SInt8[required_playout_buffer_size]);
592 681
593 // Allocate AudioBuffers to be used as storage for the received audio. 682 // Allocate AudioBuffers to be used as storage for the received audio.
594 // The AudioBufferList structure works as a placeholder for the 683 // The AudioBufferList structure works as a placeholder for the
595 // AudioBuffer structure, which holds a pointer to the actual data buffer 684 // AudioBuffer structure, which holds a pointer to the actual data buffer
596 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory 685 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory
597 // at each input callback when calling AudioUnitRender(). 686 // at each input callback when calling AudioUnitRender().
598 const int data_byte_size = record_parameters_.GetBytesPerBuffer(); 687 const int data_byte_size = record_parameters_.GetBytesPerBuffer();
599 record_audio_buffer_.reset(new SInt8[data_byte_size]); 688 record_audio_buffer_.reset(new SInt8[data_byte_size]);
689 memset(record_audio_buffer_.get(), 0, data_byte_size);
600 audio_record_buffer_list_.mNumberBuffers = 1; 690 audio_record_buffer_list_.mNumberBuffers = 1;
601 AudioBuffer* audio_buffer = &audio_record_buffer_list_.mBuffers[0]; 691 AudioBuffer* audio_buffer = &audio_record_buffer_list_.mBuffers[0];
602 audio_buffer->mNumberChannels = record_parameters_.channels(); 692 audio_buffer->mNumberChannels = record_parameters_.channels();
603 audio_buffer->mDataByteSize = data_byte_size; 693 audio_buffer->mDataByteSize = data_byte_size;
604 audio_buffer->mData = record_audio_buffer_.get(); 694 audio_buffer->mData = record_audio_buffer_.get();
605 } 695 }
606 696
607 bool AudioDeviceIOS::CreateAudioUnit() { 697 bool AudioDeviceIOS::CreateAudioUnit() {
608 RTC_DCHECK(!audio_unit_); 698 RTC_DCHECK(!audio_unit_);
609 699
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 // Restart the audio unit. 736 // Restart the audio unit.
647 if (!audio_unit_->Start()) { 737 if (!audio_unit_->Start()) {
648 RTCLogError(@"Failed to start audio unit."); 738 RTCLogError(@"Failed to start audio unit.");
649 return false; 739 return false;
650 } 740 }
651 RTCLog(@"Successfully restarted audio unit."); 741 RTCLog(@"Successfully restarted audio unit.");
652 742
653 return true; 743 return true;
654 } 744 }
655 745
746 void AudioDeviceIOS::ConfigureAudioSession() {
747 RTC_DCHECK(thread_checker_.CalledOnValidThread());
748 RTCLog(@"Configuring audio session.");
749 if (has_configured_session_) {
750 RTCLogWarning(@"Audio session already configured.");
751 return;
752 }
753 RTCAudioSession* session = [RTCAudioSession sharedInstance];
754 [session lockForConfiguration];
755 [session configureWebRTCSession:nil];
756 [session unlockForConfiguration];
757 has_configured_session_ = true;
758 RTCLog(@"Configured audio session.");
759 }
760
761 void AudioDeviceIOS::UnconfigureAudioSession() {
762 RTC_DCHECK(thread_checker_.CalledOnValidThread());
763 RTCLog(@"Unconfiguring audio session.");
764 if (!has_configured_session_) {
765 RTCLogWarning(@"Audio session already unconfigured.");
766 return;
767 }
768 RTCAudioSession* session = [RTCAudioSession sharedInstance];
769 [session lockForConfiguration];
770 [session unconfigureWebRTCSession:nil];
771 [session unlockForConfiguration];
772 has_configured_session_ = false;
773 RTCLog(@"Unconfigured audio session.");
774 }
775
656 bool AudioDeviceIOS::InitPlayOrRecord() { 776 bool AudioDeviceIOS::InitPlayOrRecord() {
657 LOGI() << "InitPlayOrRecord"; 777 LOGI() << "InitPlayOrRecord";
658 778
779 // There should be no audio unit at this point.
659 if (!CreateAudioUnit()) { 780 if (!CreateAudioUnit()) {
660 return false; 781 return false;
661 } 782 }
662 783
663 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 784 RTCAudioSession* session = [RTCAudioSession sharedInstance];
664 // Subscribe to audio session events. 785 // Subscribe to audio session events.
665 [session pushDelegate:audio_session_observer_]; 786 [session pushDelegate:audio_session_observer_];
666 787
667 // Lock the session to make configuration changes. 788 // Lock the session to make configuration changes.
668 [session lockForConfiguration]; 789 [session lockForConfiguration];
669 NSError* error = nil; 790 NSError* error = nil;
670 if (![session beginWebRTCSession:&error]) { 791 if (![session beginWebRTCSession:&error]) {
671 [session unlockForConfiguration]; 792 [session unlockForConfiguration];
672 RTCLogError(@"Failed to begin WebRTC session: %@", 793 RTCLogError(@"Failed to begin WebRTC session: %@",
673 error.localizedDescription); 794 error.localizedDescription);
674 return false; 795 return false;
675 } 796 }
676 797
677 // If we are already configured properly, we can initialize the audio unit. 798 // If we are ready to play or record, initialize the audio unit.
678 if (session.isConfiguredForWebRTC) { 799 if (session.canPlayOrRecord) {
679 [session unlockForConfiguration]; 800 ConfigureAudioSession();
680 SetupAudioBuffersForActiveAudioSession(); 801 SetupAudioBuffersForActiveAudioSession();
681 // Audio session has been marked ready for WebRTC so we can initialize the
682 // audio unit now.
683 audio_unit_->Initialize(playout_parameters_.sample_rate()); 802 audio_unit_->Initialize(playout_parameters_.sample_rate());
684 return true;
685 } 803 }
686 804
687 // Release the lock. 805 // Release the lock.
688 [session unlockForConfiguration]; 806 [session unlockForConfiguration];
689 807
690 return true; 808 return true;
691 } 809 }
692 810
693 void AudioDeviceIOS::ShutdownPlayOrRecord() { 811 void AudioDeviceIOS::ShutdownPlayOrRecord() {
694 LOGI() << "ShutdownPlayOrRecord"; 812 LOGI() << "ShutdownPlayOrRecord";
695 813
696 // Close and delete the voice-processing I/O unit. 814 // Close and delete the voice-processing I/O unit.
697 if (audio_unit_) { 815 audio_unit_.reset();
698 audio_unit_.reset();
699 }
700 816
817 RTCAudioSession* session = [RTCAudioSession sharedInstance];
701 // Remove audio session notification observers. 818 // Remove audio session notification observers.
702 RTCAudioSession* session = [RTCAudioSession sharedInstance];
703 [session removeDelegate:audio_session_observer_]; 819 [session removeDelegate:audio_session_observer_];
704 820
705 // All I/O should be stopped or paused prior to deactivating the audio 821 // All I/O should be stopped or paused prior to deactivating the audio
706 // session, hence we deactivate as last action. 822 // session, hence we deactivate as last action.
707 [session lockForConfiguration]; 823 [session lockForConfiguration];
824 UnconfigureAudioSession();
708 [session endWebRTCSession:nil]; 825 [session endWebRTCSession:nil];
709 [session unlockForConfiguration]; 826 [session unlockForConfiguration];
710 } 827 }
711 828
712 } // namespace webrtc 829 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698