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

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

Issue 1822543002: Support delayed AudioUnit initialization. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 9 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 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 } 184 }
185 rec_is_initialized_ = true; 185 rec_is_initialized_ = true;
186 return 0; 186 return 0;
187 } 187 }
188 188
189 int32_t AudioDeviceIOS::StartPlayout() { 189 int32_t AudioDeviceIOS::StartPlayout() {
190 LOGI() << "StartPlayout"; 190 LOGI() << "StartPlayout";
191 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 191 RTC_DCHECK(thread_checker_.CalledOnValidThread());
192 RTC_DCHECK(play_is_initialized_); 192 RTC_DCHECK(play_is_initialized_);
193 RTC_DCHECK(!playing_); 193 RTC_DCHECK(!playing_);
194 fine_audio_buffer_->ResetPlayout(); 194 if (fine_audio_buffer_) {
195 if (!recording_) { 195 fine_audio_buffer_->ResetPlayout();
196 }
197 if (!recording_ &&
198 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
196 if (!audio_unit_->Start()) { 199 if (!audio_unit_->Start()) {
197 RTCLogError(@"StartPlayout failed to start audio unit."); 200 RTCLogError(@"StartPlayout failed to start audio unit.");
198 return -1; 201 return -1;
199 } 202 }
200 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; 203 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
201 } 204 }
202 rtc::AtomicOps::ReleaseStore(&playing_, 1); 205 rtc::AtomicOps::ReleaseStore(&playing_, 1);
203 return 0; 206 return 0;
204 } 207 }
205 208
206 int32_t AudioDeviceIOS::StopPlayout() { 209 int32_t AudioDeviceIOS::StopPlayout() {
207 LOGI() << "StopPlayout"; 210 LOGI() << "StopPlayout";
208 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 211 RTC_DCHECK(thread_checker_.CalledOnValidThread());
209 if (!play_is_initialized_ || !playing_) { 212 if (!play_is_initialized_ || !playing_) {
210 return 0; 213 return 0;
211 } 214 }
212 if (!recording_) { 215 if (!recording_) {
213 ShutdownPlayOrRecord(); 216 ShutdownPlayOrRecord();
214 } 217 }
215 play_is_initialized_ = false; 218 play_is_initialized_ = false;
216 rtc::AtomicOps::ReleaseStore(&playing_, 0); 219 rtc::AtomicOps::ReleaseStore(&playing_, 0);
217 return 0; 220 return 0;
218 } 221 }
219 222
220 int32_t AudioDeviceIOS::StartRecording() { 223 int32_t AudioDeviceIOS::StartRecording() {
221 LOGI() << "StartRecording"; 224 LOGI() << "StartRecording";
222 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 225 RTC_DCHECK(thread_checker_.CalledOnValidThread());
223 RTC_DCHECK(rec_is_initialized_); 226 RTC_DCHECK(rec_is_initialized_);
224 RTC_DCHECK(!recording_); 227 RTC_DCHECK(!recording_);
225 fine_audio_buffer_->ResetRecord(); 228 if (fine_audio_buffer_) {
226 if (!playing_) { 229 fine_audio_buffer_->ResetRecord();
230 }
231 if (!playing_ &&
232 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
227 if (!audio_unit_->Start()) { 233 if (!audio_unit_->Start()) {
228 RTCLogError(@"StartRecording failed to start audio unit."); 234 RTCLogError(@"StartRecording failed to start audio unit.");
229 return -1; 235 return -1;
230 } 236 }
231 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; 237 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
232 } 238 }
233 rtc::AtomicOps::ReleaseStore(&recording_, 1); 239 rtc::AtomicOps::ReleaseStore(&recording_, 1);
234 return 0; 240 return 0;
235 } 241 }
236 242
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 RTC_DCHECK(thread_); 346 RTC_DCHECK(thread_);
341 if (thread_->IsCurrent()) { 347 if (thread_->IsCurrent()) {
342 HandleValidRouteChange(); 348 HandleValidRouteChange();
343 return; 349 return;
344 } 350 }
345 async_invoker_->AsyncInvoke<void>( 351 async_invoker_->AsyncInvoke<void>(
346 thread_, 352 thread_,
347 rtc::Bind(&webrtc::AudioDeviceIOS::HandleValidRouteChange, this)); 353 rtc::Bind(&webrtc::AudioDeviceIOS::HandleValidRouteChange, this));
348 } 354 }
349 355
356 void AudioDeviceIOS::OnConfiguredForWebRTC() {
357 RTC_DCHECK(async_invoker_);
358 RTC_DCHECK(thread_);
359 if (thread_->IsCurrent()) {
360 HandleValidRouteChange();
361 return;
362 }
363 async_invoker_->AsyncInvoke<void>(
364 thread_,
365 rtc::Bind(&webrtc::AudioDeviceIOS::HandleConfiguredForWebRTC, this));
366 }
367
350 OSStatus AudioDeviceIOS::OnDeliverRecordedData( 368 OSStatus AudioDeviceIOS::OnDeliverRecordedData(
351 AudioUnitRenderActionFlags* flags, 369 AudioUnitRenderActionFlags* flags,
352 const AudioTimeStamp* time_stamp, 370 const AudioTimeStamp* time_stamp,
353 UInt32 bus_number, 371 UInt32 bus_number,
354 UInt32 num_frames, 372 UInt32 num_frames,
355 AudioBufferList* /* io_data */) { 373 AudioBufferList* /* io_data */) {
356 OSStatus result = noErr; 374 OSStatus result = noErr;
357 // Simply return if recording is not enabled. 375 // Simply return if recording is not enabled.
358 if (!rtc::AtomicOps::AcquireLoad(&recording_)) 376 if (!rtc::AtomicOps::AcquireLoad(&recording_))
359 return result; 377 return result;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // the native I/O audio unit) to a preallocated intermediate buffer and 442 // the native I/O audio unit) to a preallocated intermediate buffer and
425 // copy the result to the audio buffer in the |io_data| destination. 443 // copy the result to the audio buffer in the |io_data| destination.
426 int8_t* source = playout_audio_buffer_.get(); 444 int8_t* source = playout_audio_buffer_.get();
427 fine_audio_buffer_->GetPlayoutData(source); 445 fine_audio_buffer_->GetPlayoutData(source);
428 memcpy(destination, source, size_in_bytes); 446 memcpy(destination, source, size_in_bytes);
429 return noErr; 447 return noErr;
430 } 448 }
431 449
432 void AudioDeviceIOS::HandleInterruptionBegin() { 450 void AudioDeviceIOS::HandleInterruptionBegin() {
433 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 451 RTC_DCHECK(thread_checker_.CalledOnValidThread());
452
434 RTCLog(@"Stopping the audio unit due to interruption begin."); 453 RTCLog(@"Stopping the audio unit due to interruption begin.");
435 if (!audio_unit_->Stop()) { 454 if (!audio_unit_->Stop()) {
436 RTCLogError(@"Failed to stop the audio unit."); 455 RTCLogError(@"Failed to stop the audio unit.");
437 } 456 }
438 is_interrupted_ = true; 457 is_interrupted_ = true;
439 } 458 }
440 459
441 void AudioDeviceIOS::HandleInterruptionEnd() { 460 void AudioDeviceIOS::HandleInterruptionEnd() {
442 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 461 RTC_DCHECK(thread_checker_.CalledOnValidThread());
462
443 RTCLog(@"Starting the audio unit due to interruption end."); 463 RTCLog(@"Starting the audio unit due to interruption end.");
444 if (!audio_unit_->Start()) { 464 if (!audio_unit_->Start()) {
445 RTCLogError(@"Failed to start the audio unit."); 465 RTCLogError(@"Failed to start the audio unit.");
446 } 466 }
447 is_interrupted_ = false; 467 is_interrupted_ = false;
448 } 468 }
449 469
450 void AudioDeviceIOS::HandleValidRouteChange() { 470 void AudioDeviceIOS::HandleValidRouteChange() {
451 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 471 RTC_DCHECK(thread_checker_.CalledOnValidThread());
452 472
453 // Don't do anything if we're interrupted. 473 // Don't do anything if we're interrupted.
454 if (is_interrupted_) { 474 if (is_interrupted_) {
455 return; 475 return;
456 } 476 }
457 477
458 // Only restart audio for a valid route change if the session sample rate 478 // Only restart audio for a valid route change if the session sample rate
459 // has changed. 479 // has changed.
460 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 480 RTCAudioSession* session = [RTCAudioSession sharedInstance];
461 const double current_sample_rate = playout_parameters_.sample_rate(); 481 const double current_sample_rate = playout_parameters_.sample_rate();
462 const double session_sample_rate = session.sampleRate; 482 const double session_sample_rate = session.sampleRate;
463 if (current_sample_rate != session_sample_rate) { 483 if (current_sample_rate != session_sample_rate) {
464 RTCLog(@"Route changed caused sample rate to change from %f to %f. " 484 RTCLog(@"Route changed caused sample rate to change from %f to %f. "
465 "Restarting audio unit.", current_sample_rate, session_sample_rate); 485 "Restarting audio unit.", current_sample_rate, session_sample_rate);
466 if (!RestartAudioUnit(session_sample_rate)) { 486 if (!RestartAudioUnit(session_sample_rate)) {
467 RTCLogError(@"Audio restart failed."); 487 RTCLogError(@"Audio restart failed.");
468 } 488 }
469 } 489 }
470 } 490 }
471 491
492 void AudioDeviceIOS::HandleConfiguredForWebRTC() {
493 RTC_DCHECK(thread_checker_.CalledOnValidThread());
494
495 // If we're not initialized we don't need to do anything. Audio unit will
496 // be initialized on initialization.
497 if (!rec_is_initialized_ && !play_is_initialized_)
498 return;
499
500 // If we're initialized, we must have an audio unit.
501 RTC_DCHECK(audio_unit_);
502
503 // Use configured audio session's settings to set up audio device buffer.
504 // TODO(tkchin): Use RTCAudioSessionConfiguration to pick up settings and
505 // pass it along.
506 SetupAudioBuffersForActiveAudioSession();
507
508 // Initialize the audio unit. This will affect any existing audio playback.
509 if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
510 RTCLogError(@"Failed to initialize audio unit after configuration.");
511 return;
512 }
513
514 // If we haven't started playing or recording there's nothing more to do.
515 if (!playing_ && !recording_)
516 return;
517
518 // We are in a play or record state, start the audio unit.
519 if (!audio_unit_->Start()) {
520 RTCLogError(@"Failed to start audio unit after configuration.");
521 return;
522 }
523 }
524
472 void AudioDeviceIOS::UpdateAudioDeviceBuffer() { 525 void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
473 LOGI() << "UpdateAudioDevicebuffer"; 526 LOGI() << "UpdateAudioDevicebuffer";
474 // AttachAudioBuffer() is called at construction by the main class but check 527 // AttachAudioBuffer() is called at construction by the main class but check
475 // just in case. 528 // just in case.
476 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first"; 529 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first";
477 // Inform the audio device buffer (ADB) about the new audio format. 530 // Inform the audio device buffer (ADB) about the new audio format.
478 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate()); 531 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate());
479 audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels()); 532 audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels());
480 audio_device_buffer_->SetRecordingSampleRate( 533 audio_device_buffer_->SetRecordingSampleRate(
481 record_parameters_.sample_rate()); 534 record_parameters_.sample_rate());
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 return false; 649 return false;
597 } 650 }
598 RTCLog(@"Successfully restarted audio unit."); 651 RTCLog(@"Successfully restarted audio unit.");
599 652
600 return true; 653 return true;
601 } 654 }
602 655
603 bool AudioDeviceIOS::InitPlayOrRecord() { 656 bool AudioDeviceIOS::InitPlayOrRecord() {
604 LOGI() << "InitPlayOrRecord"; 657 LOGI() << "InitPlayOrRecord";
605 658
606 // Use the correct audio session configuration for WebRTC. 659 if (!CreateAudioUnit()) {
607 // This will attempt to activate the audio session.
608 RTCAudioSession* session = [RTCAudioSession sharedInstance];
609 [session lockForConfiguration];
610 NSError* error = nil;
611 if (![session configureWebRTCSession:&error]) {
612 RTCLogError(@"Failed to configure WebRTC session: %@",
613 error.localizedDescription);
614 [session unlockForConfiguration];
615 return false; 660 return false;
616 } 661 }
617 662
618 // Start observing audio session interruptions and route changes. 663 RTCAudioSession* session = [RTCAudioSession sharedInstance];
664 // Subscribe to audio session events.
619 [session pushDelegate:audio_session_observer_]; 665 [session pushDelegate:audio_session_observer_];
620 666
621 // Ensure that we got what what we asked for in our active audio session. 667 // Lock the session to make configuration changes.
622 SetupAudioBuffersForActiveAudioSession(); 668 [session lockForConfiguration];
623 669 NSError* error = nil;
624 // Create, setup and initialize a new Voice-Processing I/O unit. 670 if (![session beginWebRTCSession:&error]) {
625 // TODO(tkchin): Delay the initialization when needed.
626 if (!CreateAudioUnit() ||
627 !audio_unit_->Initialize(playout_parameters_.sample_rate())) {
628 [session setActive:NO error:nil];
629 [session unlockForConfiguration]; 671 [session unlockForConfiguration];
672 RTCLogError(@"Failed to begin WebRTC session: %@",
673 error.localizedDescription);
630 return false; 674 return false;
631 } 675 }
676
677 // If we are already configured properly, we can initialize the audio unit.
678 if (session.isConfiguredForWebRTC) {
679 [session unlockForConfiguration];
680 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());
684 return true;
685 }
686
687 // Release the lock.
632 [session unlockForConfiguration]; 688 [session unlockForConfiguration];
633 689
634 return true; 690 return true;
635 } 691 }
636 692
637 void AudioDeviceIOS::ShutdownPlayOrRecord() { 693 void AudioDeviceIOS::ShutdownPlayOrRecord() {
638 LOGI() << "ShutdownPlayOrRecord"; 694 LOGI() << "ShutdownPlayOrRecord";
639 695
640 // Close and delete the voice-processing I/O unit. 696 // Close and delete the voice-processing I/O unit.
641 if (audio_unit_) { 697 if (audio_unit_) {
642 audio_unit_->Stop();
643 audio_unit_->Uninitialize();
644 audio_unit_.reset(); 698 audio_unit_.reset();
645 } 699 }
646 700
647 // Remove audio session notification observers. 701 // Remove audio session notification observers.
648 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 702 RTCAudioSession* session = [RTCAudioSession sharedInstance];
649 [session removeDelegate:audio_session_observer_]; 703 [session removeDelegate:audio_session_observer_];
650 704
651 // All I/O should be stopped or paused prior to deactivating the audio 705 // All I/O should be stopped or paused prior to deactivating the audio
652 // session, hence we deactivate as last action. 706 // session, hence we deactivate as last action.
653 [session lockForConfiguration]; 707 [session lockForConfiguration];
654 [session setActive:NO error:nil]; 708 [session endWebRTCSession:nil];
655 [session unlockForConfiguration]; 709 [session unlockForConfiguration];
656 } 710 }
657 711
658 } // namespace webrtc 712 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698