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

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: Remove unneeded volatile. 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 };
70
64 using ios::CheckAndLogError; 71 using ios::CheckAndLogError;
65 72
66 #if !defined(NDEBUG) 73 #if !defined(NDEBUG)
67 // Helper method that logs essential device information strings. 74 // Helper method that logs essential device information strings.
68 static void LogDeviceInfo() { 75 static void LogDeviceInfo() {
69 LOG(LS_INFO) << "LogDeviceInfo"; 76 LOG(LS_INFO) << "LogDeviceInfo";
70 @autoreleasepool { 77 @autoreleasepool {
71 LOG(LS_INFO) << " system name: " << ios::GetSystemName(); 78 LOG(LS_INFO) << " system name: " << ios::GetSystemName();
72 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString(); 79 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString();
73 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion(); 80 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion();
74 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); 81 LOG(LS_INFO) << " device type: " << ios::GetDeviceType();
75 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); 82 LOG(LS_INFO) << " device name: " << ios::GetDeviceName();
76 LOG(LS_INFO) << " process name: " << ios::GetProcessName(); 83 LOG(LS_INFO) << " process name: " << ios::GetProcessName();
77 LOG(LS_INFO) << " process ID: " << ios::GetProcessID(); 84 LOG(LS_INFO) << " process ID: " << ios::GetProcessID();
78 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString(); 85 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString();
79 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount(); 86 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount();
80 #if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 87 #if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
81 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled(); 88 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled();
82 #endif 89 #endif
83 } 90 }
84 } 91 }
85 #endif // !defined(NDEBUG) 92 #endif // !defined(NDEBUG)
86 93
87 AudioDeviceIOS::AudioDeviceIOS() 94 AudioDeviceIOS::AudioDeviceIOS()
88 : async_invoker_(new rtc::AsyncInvoker()), 95 : audio_device_buffer_(nullptr),
89 audio_device_buffer_(nullptr),
90 audio_unit_(nullptr), 96 audio_unit_(nullptr),
91 recording_(0), 97 recording_(0),
92 playing_(0), 98 playing_(0),
93 initialized_(false), 99 initialized_(false),
94 rec_is_initialized_(false), 100 rec_is_initialized_(false),
95 play_is_initialized_(false), 101 play_is_initialized_(false),
96 is_interrupted_(false) { 102 is_interrupted_(false),
103 has_configured_session_(false) {
97 LOGI() << "ctor" << ios::GetCurrentThreadDescription(); 104 LOGI() << "ctor" << ios::GetCurrentThreadDescription();
98 thread_ = rtc::Thread::Current(); 105 thread_ = rtc::Thread::Current();
99 audio_session_observer_ = 106 audio_session_observer_ =
100 [[RTCAudioSessionDelegateAdapter alloc] initWithObserver:this]; 107 [[RTCAudioSessionDelegateAdapter alloc] initWithObserver:this];
101 } 108 }
102 109
103 AudioDeviceIOS::~AudioDeviceIOS() { 110 AudioDeviceIOS::~AudioDeviceIOS() {
104 LOGI() << "~dtor" << ios::GetCurrentThreadDescription(); 111 LOGI() << "~dtor" << ios::GetCurrentThreadDescription();
105 audio_session_observer_ = nil; 112 audio_session_observer_ = nil;
106 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 113 RTC_DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 } 191 }
185 rec_is_initialized_ = true; 192 rec_is_initialized_ = true;
186 return 0; 193 return 0;
187 } 194 }
188 195
189 int32_t AudioDeviceIOS::StartPlayout() { 196 int32_t AudioDeviceIOS::StartPlayout() {
190 LOGI() << "StartPlayout"; 197 LOGI() << "StartPlayout";
191 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 198 RTC_DCHECK(thread_checker_.CalledOnValidThread());
192 RTC_DCHECK(play_is_initialized_); 199 RTC_DCHECK(play_is_initialized_);
193 RTC_DCHECK(!playing_); 200 RTC_DCHECK(!playing_);
201 RTC_DCHECK(audio_unit_);
194 if (fine_audio_buffer_) { 202 if (fine_audio_buffer_) {
195 fine_audio_buffer_->ResetPlayout(); 203 fine_audio_buffer_->ResetPlayout();
196 } 204 }
197 if (!recording_ && 205 if (!recording_ &&
198 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) { 206 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
199 if (!audio_unit_->Start()) { 207 if (!audio_unit_->Start()) {
200 RTCLogError(@"StartPlayout failed to start audio unit."); 208 RTCLogError(@"StartPlayout failed to start audio unit.");
201 return -1; 209 return -1;
202 } 210 }
203 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; 211 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
204 } 212 }
205 rtc::AtomicOps::ReleaseStore(&playing_, 1); 213 rtc::AtomicOps::ReleaseStore(&playing_, 1);
206 return 0; 214 return 0;
207 } 215 }
208 216
209 int32_t AudioDeviceIOS::StopPlayout() { 217 int32_t AudioDeviceIOS::StopPlayout() {
210 LOGI() << "StopPlayout"; 218 LOGI() << "StopPlayout";
211 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 219 RTC_DCHECK(thread_checker_.CalledOnValidThread());
212 if (!play_is_initialized_ || !playing_) { 220 if (!play_is_initialized_) {
221 return 0;
222 }
223 if (!playing_) {
224 play_is_initialized_ = false;
213 return 0; 225 return 0;
214 } 226 }
215 if (!recording_) { 227 if (!recording_) {
216 ShutdownPlayOrRecord(); 228 ShutdownPlayOrRecord();
217 } 229 }
218 play_is_initialized_ = false; 230 play_is_initialized_ = false;
219 rtc::AtomicOps::ReleaseStore(&playing_, 0); 231 rtc::AtomicOps::ReleaseStore(&playing_, 0);
220 return 0; 232 return 0;
221 } 233 }
222 234
223 int32_t AudioDeviceIOS::StartRecording() { 235 int32_t AudioDeviceIOS::StartRecording() {
224 LOGI() << "StartRecording"; 236 LOGI() << "StartRecording";
225 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 237 RTC_DCHECK(thread_checker_.CalledOnValidThread());
226 RTC_DCHECK(rec_is_initialized_); 238 RTC_DCHECK(rec_is_initialized_);
227 RTC_DCHECK(!recording_); 239 RTC_DCHECK(!recording_);
240 RTC_DCHECK(audio_unit_);
228 if (fine_audio_buffer_) { 241 if (fine_audio_buffer_) {
229 fine_audio_buffer_->ResetRecord(); 242 fine_audio_buffer_->ResetRecord();
230 } 243 }
231 if (!playing_ && 244 if (!playing_ &&
232 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) { 245 audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
233 if (!audio_unit_->Start()) { 246 if (!audio_unit_->Start()) {
234 RTCLogError(@"StartRecording failed to start audio unit."); 247 RTCLogError(@"StartRecording failed to start audio unit.");
235 return -1; 248 return -1;
236 } 249 }
237 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started"; 250 LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
238 } 251 }
239 rtc::AtomicOps::ReleaseStore(&recording_, 1); 252 rtc::AtomicOps::ReleaseStore(&recording_, 1);
240 return 0; 253 return 0;
241 } 254 }
242 255
243 int32_t AudioDeviceIOS::StopRecording() { 256 int32_t AudioDeviceIOS::StopRecording() {
244 LOGI() << "StopRecording"; 257 LOGI() << "StopRecording";
245 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 258 RTC_DCHECK(thread_checker_.CalledOnValidThread());
246 if (!rec_is_initialized_ || !recording_) { 259 if (!rec_is_initialized_) {
260 return 0;
261 }
262 if (!recording_) {
263 rec_is_initialized_ = false;
247 return 0; 264 return 0;
248 } 265 }
249 if (!playing_) { 266 if (!playing_) {
250 ShutdownPlayOrRecord(); 267 ShutdownPlayOrRecord();
251 } 268 }
252 rec_is_initialized_ = false; 269 rec_is_initialized_ = false;
253 rtc::AtomicOps::ReleaseStore(&recording_, 0); 270 rtc::AtomicOps::ReleaseStore(&recording_, 0);
254 return 0; 271 return 0;
255 } 272 }
256 273
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 328
312 int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const { 329 int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const {
313 LOGI() << "GetRecordAudioParameters"; 330 LOGI() << "GetRecordAudioParameters";
314 RTC_DCHECK(record_parameters_.is_valid()); 331 RTC_DCHECK(record_parameters_.is_valid());
315 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 332 RTC_DCHECK(thread_checker_.CalledOnValidThread());
316 *params = record_parameters_; 333 *params = record_parameters_;
317 return 0; 334 return 0;
318 } 335 }
319 336
320 void AudioDeviceIOS::OnInterruptionBegin() { 337 void AudioDeviceIOS::OnInterruptionBegin() {
321 RTC_DCHECK(async_invoker_);
322 RTC_DCHECK(thread_); 338 RTC_DCHECK(thread_);
323 if (thread_->IsCurrent()) { 339 thread_->Post(this, kMessageTypeInterruptionBegin);
324 HandleInterruptionBegin();
325 return;
326 }
327 async_invoker_->AsyncInvoke<void>(
328 thread_,
329 rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionBegin, this));
330 } 340 }
331 341
332 void AudioDeviceIOS::OnInterruptionEnd() { 342 void AudioDeviceIOS::OnInterruptionEnd() {
333 RTC_DCHECK(async_invoker_);
334 RTC_DCHECK(thread_); 343 RTC_DCHECK(thread_);
335 if (thread_->IsCurrent()) { 344 thread_->Post(this, kMessageTypeInterruptionEnd);
336 HandleInterruptionEnd();
337 return;
338 }
339 async_invoker_->AsyncInvoke<void>(
340 thread_,
341 rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionEnd, this));
342 } 345 }
343 346
344 void AudioDeviceIOS::OnValidRouteChange() { 347 void AudioDeviceIOS::OnValidRouteChange() {
345 RTC_DCHECK(async_invoker_);
346 RTC_DCHECK(thread_); 348 RTC_DCHECK(thread_);
347 if (thread_->IsCurrent()) { 349 thread_->Post(this, kMessageTypeValidRouteChange);
348 HandleValidRouteChange();
349 return;
350 }
351 async_invoker_->AsyncInvoke<void>(
352 thread_,
353 rtc::Bind(&webrtc::AudioDeviceIOS::HandleValidRouteChange, this));
354 } 350 }
355 351
356 void AudioDeviceIOS::OnConfiguredForWebRTC() { 352 void AudioDeviceIOS::OnCanPlayOrRecordChange(bool can_play_or_record) {
357 RTC_DCHECK(async_invoker_);
358 RTC_DCHECK(thread_); 353 RTC_DCHECK(thread_);
359 if (thread_->IsCurrent()) { 354 thread_->Post(this, kMessageTypeCanPlayOrRecordChange,
360 HandleValidRouteChange(); 355 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 } 356 }
367 357
368 OSStatus AudioDeviceIOS::OnDeliverRecordedData( 358 OSStatus AudioDeviceIOS::OnDeliverRecordedData(
369 AudioUnitRenderActionFlags* flags, 359 AudioUnitRenderActionFlags* flags,
370 const AudioTimeStamp* time_stamp, 360 const AudioTimeStamp* time_stamp,
371 UInt32 bus_number, 361 UInt32 bus_number,
372 UInt32 num_frames, 362 UInt32 num_frames,
373 AudioBufferList* /* io_data */) { 363 AudioBufferList* /* io_data */) {
374 OSStatus result = noErr; 364 OSStatus result = noErr;
375 // Simply return if recording is not enabled. 365 // Simply return if recording is not enabled.
376 if (!rtc::AtomicOps::AcquireLoad(&recording_)) 366 if (!rtc::AtomicOps::AcquireLoad(&recording_))
377 return result; 367 return result;
378 368
379 size_t frames_per_buffer = record_parameters_.frames_per_buffer(); 369 size_t frames_per_buffer = record_parameters_.frames_per_buffer();
380 if (num_frames != frames_per_buffer) { 370 if (num_frames != frames_per_buffer) {
381 // We have seen short bursts (1-2 frames) where |in_number_frames| changes. 371 // 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. 372 // 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 373 // Also return since calling AudioUnitRender in this state will only result
384 // in kAudio_ParamError (-50) anyhow. 374 // in kAudio_ParamError (-50) anyhow.
385 RTCLogWarning(@"Expected %u frames but got %u", 375 RTCLogWarning(@"Expected %u frames but got %u",
386 static_cast<unsigned int>(frames_per_buffer), 376 static_cast<unsigned int>(frames_per_buffer),
387 static_cast<unsigned int>(num_frames)); 377 static_cast<unsigned int>(num_frames));
378
379 RTCAudioSession *session = [RTCAudioSession sharedInstance];
380 RTCLogWarning(@"Session:\n %@", session);
388 return result; 381 return result;
389 } 382 }
390 383
391 // Obtain the recorded audio samples by initiating a rendering cycle. 384 // 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 385 // 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. 386 // 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 387 // We can make the audio unit provide a buffer instead in io_data, but we
395 // currently just use our own. 388 // currently just use our own.
396 // TODO(henrika): should error handling be improved? 389 // TODO(henrika): should error handling be improved?
397 AudioBufferList* io_data = &audio_record_buffer_list_; 390 AudioBufferList* io_data = &audio_record_buffer_list_;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 } 433 }
441 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches 434 // 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 435 // 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. 436 // copy the result to the audio buffer in the |io_data| destination.
444 int8_t* source = playout_audio_buffer_.get(); 437 int8_t* source = playout_audio_buffer_.get();
445 fine_audio_buffer_->GetPlayoutData(source); 438 fine_audio_buffer_->GetPlayoutData(source);
446 memcpy(destination, source, size_in_bytes); 439 memcpy(destination, source, size_in_bytes);
447 return noErr; 440 return noErr;
448 } 441 }
449 442
443 void AudioDeviceIOS::OnMessage(rtc::Message *msg) {
444 switch (msg->message_id) {
445 case kMessageTypeInterruptionBegin:
446 HandleInterruptionBegin();
447 break;
448 case kMessageTypeInterruptionEnd:
449 HandleInterruptionEnd();
450 break;
451 case kMessageTypeValidRouteChange:
452 HandleValidRouteChange();
453 break;
454 case kMessageTypeCanPlayOrRecordChange: {
455 rtc::TypedMessageData<bool>* data =
456 static_cast<rtc::TypedMessageData<bool>*>(msg->pdata);
457 HandleCanPlayOrRecordChange(data->data());
458 delete data;
459 break;
460 }
461 }
462 }
463
450 void AudioDeviceIOS::HandleInterruptionBegin() { 464 void AudioDeviceIOS::HandleInterruptionBegin() {
451 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 465 RTC_DCHECK(thread_checker_.CalledOnValidThread());
452 466
453 RTCLog(@"Stopping the audio unit due to interruption begin."); 467 if (audio_unit_ &&
454 if (!audio_unit_->Stop()) { 468 audio_unit_->GetState() == VoiceProcessingAudioUnit::kStarted) {
455 RTCLogError(@"Failed to stop the audio unit."); 469 RTCLog(@"Stopping the audio unit due to interruption begin.");
470 if (!audio_unit_->Stop()) {
471 RTCLogError(@"Failed to stop the audio unit for interruption begin.");
472 }
456 } 473 }
457 is_interrupted_ = true; 474 is_interrupted_ = true;
458 } 475 }
459 476
460 void AudioDeviceIOS::HandleInterruptionEnd() { 477 void AudioDeviceIOS::HandleInterruptionEnd() {
461 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 478 RTC_DCHECK(thread_checker_.CalledOnValidThread());
462 479
463 RTCLog(@"Starting the audio unit due to interruption end.");
464 if (!audio_unit_->Start()) {
465 RTCLogError(@"Failed to start the audio unit.");
466 }
467 is_interrupted_ = false; 480 is_interrupted_ = false;
481 RTCLog(@"Interruption ended. Updating audio unit state.");
482 UpdateAudioUnit([RTCAudioSession sharedInstance].canPlayOrRecord);
468 } 483 }
469 484
470 void AudioDeviceIOS::HandleValidRouteChange() { 485 void AudioDeviceIOS::HandleValidRouteChange() {
471 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 486 RTC_DCHECK(thread_checker_.CalledOnValidThread());
472 487
488 RTCAudioSession* session = [RTCAudioSession sharedInstance];
489 HandleSampleRateChange(session.sampleRate);
490 }
491
492 void AudioDeviceIOS::HandleCanPlayOrRecordChange(bool can_play_or_record) {
493 RTCLog(@"Handling CanPlayOrRecord change to: %d", can_play_or_record);
494 UpdateAudioUnit(can_play_or_record);
495 }
496
497 void AudioDeviceIOS::HandleSampleRateChange(float sample_rate) {
498 RTC_DCHECK(thread_checker_.CalledOnValidThread());
499 RTCLog(@"Handling sample rate change to %f.", sample_rate);
500
473 // Don't do anything if we're interrupted. 501 // Don't do anything if we're interrupted.
474 if (is_interrupted_) { 502 if (is_interrupted_) {
503 RTCLog(@"Ignoring sample rate change to %f due to interruption.",
504 sample_rate);
475 return; 505 return;
476 } 506 }
477 507
478 // Only restart audio for a valid route change if the session sample rate 508 // If we don't have an audio unit yet, or the audio unit is uninitialized,
479 // has changed. 509 // there is no work to do.
480 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 510 if (!audio_unit_ ||
481 const double current_sample_rate = playout_parameters_.sample_rate(); 511 audio_unit_->GetState() < VoiceProcessingAudioUnit::kInitialized) {
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 }
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 return;
512 } 513 }
513 514
514 // If we haven't started playing or recording there's nothing more to do. 515 // The audio unit is already initialized or started.
515 if (!playing_ && !recording_) 516 // Check to see if the sample rate or buffer size has changed.
516 return; 517 RTCAudioSession* session = [RTCAudioSession sharedInstance];
518 const double session_sample_rate = session.sampleRate;
519 const NSTimeInterval session_buffer_duration = session.IOBufferDuration;
520 const size_t session_frames_per_buffer =
521 static_cast<size_t>(session_sample_rate * session_buffer_duration + .5);
522 const double current_sample_rate = playout_parameters_.sample_rate();
523 const size_t current_frames_per_buffer =
524 playout_parameters_.frames_per_buffer();
525 RTCLog(@"Handling playout sample rate change to: %f\n"
526 " Session sample rate: %f frames_per_buffer: %lu\n"
527 " ADM sample rate: %f frames_per_buffer: %lu",
528 sample_rate,
529 session_sample_rate, (unsigned long)session_frames_per_buffer,
530 current_sample_rate, (unsigned long)current_frames_per_buffer);;
517 531
518 // We are in a play or record state, start the audio unit. 532 // Sample rate and buffer size are the same, no work to do.
519 if (!audio_unit_->Start()) { 533 if (abs(current_sample_rate - session_sample_rate) <= DBL_EPSILON &&
520 RTCLogError(@"Failed to start audio unit after configuration."); 534 current_frames_per_buffer == session_frames_per_buffer) {
521 return; 535 return;
522 } 536 }
537
538 // We need to adjust our format and buffer sizes.
539 // The stream format is about to be changed and it requires that we first
540 // stop and uninitialize the audio unit to deallocate its resources.
541 RTCLog(@"Stopping and uninitializing audio unit to adjust buffers.");
542 bool restart_audio_unit = false;
543 if (audio_unit_->GetState() == VoiceProcessingAudioUnit::kStarted) {
544 audio_unit_->Stop();
545 restart_audio_unit = true;
546 }
547 if (audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
548 audio_unit_->Uninitialize();
549 }
550
551 // Allocate new buffers given the new stream format.
552 SetupAudioBuffersForActiveAudioSession();
553
554 // Initialize the audio unit again with the new sample rate.
555 RTC_DCHECK_EQ(playout_parameters_.sample_rate(), session_sample_rate);
556 if (!audio_unit_->Initialize(session_sample_rate)) {
557 RTCLogError(@"Failed to initialize the audio unit with sample rate: %f",
558 session_sample_rate);
559 return;
560 }
561
562 // Restart the audio unit if it was already running.
563 if (restart_audio_unit && !audio_unit_->Start()) {
564 RTCLogError(@"Failed to start audio unit with sample rate: %f",
565 session_sample_rate);
566 return;
567 }
568 RTCLog(@"Successfully handled sample rate change.");
523 } 569 }
524 570
525 void AudioDeviceIOS::UpdateAudioDeviceBuffer() { 571 void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
526 LOGI() << "UpdateAudioDevicebuffer"; 572 LOGI() << "UpdateAudioDevicebuffer";
527 // AttachAudioBuffer() is called at construction by the main class but check 573 // AttachAudioBuffer() is called at construction by the main class but check
528 // just in case. 574 // just in case.
529 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first"; 575 RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first";
530 // Inform the audio device buffer (ADB) about the new audio format. 576 // Inform the audio device buffer (ADB) about the new audio format.
531 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate()); 577 audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate());
532 audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels()); 578 audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels());
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 << required_playout_buffer_size; 636 << required_playout_buffer_size;
591 playout_audio_buffer_.reset(new SInt8[required_playout_buffer_size]); 637 playout_audio_buffer_.reset(new SInt8[required_playout_buffer_size]);
592 638
593 // Allocate AudioBuffers to be used as storage for the received audio. 639 // Allocate AudioBuffers to be used as storage for the received audio.
594 // The AudioBufferList structure works as a placeholder for the 640 // The AudioBufferList structure works as a placeholder for the
595 // AudioBuffer structure, which holds a pointer to the actual data buffer 641 // AudioBuffer structure, which holds a pointer to the actual data buffer
596 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory 642 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory
597 // at each input callback when calling AudioUnitRender(). 643 // at each input callback when calling AudioUnitRender().
598 const int data_byte_size = record_parameters_.GetBytesPerBuffer(); 644 const int data_byte_size = record_parameters_.GetBytesPerBuffer();
599 record_audio_buffer_.reset(new SInt8[data_byte_size]); 645 record_audio_buffer_.reset(new SInt8[data_byte_size]);
646 memset(record_audio_buffer_.get(), 0, data_byte_size);
600 audio_record_buffer_list_.mNumberBuffers = 1; 647 audio_record_buffer_list_.mNumberBuffers = 1;
601 AudioBuffer* audio_buffer = &audio_record_buffer_list_.mBuffers[0]; 648 AudioBuffer* audio_buffer = &audio_record_buffer_list_.mBuffers[0];
602 audio_buffer->mNumberChannels = record_parameters_.channels(); 649 audio_buffer->mNumberChannels = record_parameters_.channels();
603 audio_buffer->mDataByteSize = data_byte_size; 650 audio_buffer->mDataByteSize = data_byte_size;
604 audio_buffer->mData = record_audio_buffer_.get(); 651 audio_buffer->mData = record_audio_buffer_.get();
605 } 652 }
606 653
607 bool AudioDeviceIOS::CreateAudioUnit() { 654 bool AudioDeviceIOS::CreateAudioUnit() {
608 RTC_DCHECK(!audio_unit_); 655 RTC_DCHECK(!audio_unit_);
609 656
610 audio_unit_.reset(new VoiceProcessingAudioUnit(this)); 657 audio_unit_.reset(new VoiceProcessingAudioUnit(this));
611 if (!audio_unit_->Init()) { 658 if (!audio_unit_->Init()) {
612 audio_unit_.reset(); 659 audio_unit_.reset();
613 return false; 660 return false;
614 } 661 }
615 662
616 return true; 663 return true;
617 } 664 }
618 665
619 bool AudioDeviceIOS::RestartAudioUnit(float sample_rate) { 666 void AudioDeviceIOS::UpdateAudioUnit(bool can_play_or_record) {
620 RTCLog(@"Restarting audio unit with new sample rate: %f", sample_rate); 667 RTC_DCHECK(thread_checker_.CalledOnValidThread());
668 RTCLog(@"Updating audio unit state. CanPlayOrRecord=%d IsInterrupted=%d",
669 can_play_or_record, is_interrupted_);
621 670
622 // Stop the active audio unit. 671 if (is_interrupted_) {
623 if (!audio_unit_->Stop()) { 672 RTCLog(@"Ignoring audio unit update due to interruption.");
624 RTCLogError(@"Failed to stop the audio unit."); 673 return;
625 return false;
626 } 674 }
627 675
628 // The stream format is about to be changed and it requires that we first 676 // If we're not initialized we don't need to do anything. Audio unit will
629 // uninitialize it to deallocate its resources. 677 // be initialized on initialization.
630 if (!audio_unit_->Uninitialize()) { 678 if (!rec_is_initialized_ && !play_is_initialized_)
631 RTCLogError(@"Failed to uninitialize the audio unit."); 679 return;
632 return false; 680
681 // If we're initialized, we must have an audio unit.
682 RTC_DCHECK(audio_unit_);
683
684 bool should_initialize_audio_unit = false;
685 bool should_uninitialize_audio_unit = false;
686 bool should_start_audio_unit = false;
687 bool should_stop_audio_unit = false;
688
689 switch (audio_unit_->GetState()) {
690 case VoiceProcessingAudioUnit::kInitRequired:
691 RTC_NOTREACHED();
692 break;
693 case VoiceProcessingAudioUnit::kUninitialized:
694 should_initialize_audio_unit = can_play_or_record;
695 should_start_audio_unit = should_initialize_audio_unit &&
696 (playing_ || recording_);
697 break;
698 case VoiceProcessingAudioUnit::kInitialized:
699 should_start_audio_unit =
700 can_play_or_record && (playing_ || recording_);
701 should_uninitialize_audio_unit = !can_play_or_record;
702 break;
703 case VoiceProcessingAudioUnit::kStarted:
704 RTC_DCHECK(playing_ || recording_);
705 should_stop_audio_unit = !can_play_or_record;
706 should_uninitialize_audio_unit = should_stop_audio_unit;
707 break;
633 } 708 }
634 709
635 // Allocate new buffers given the new stream format. 710 if (should_initialize_audio_unit) {
636 SetupAudioBuffersForActiveAudioSession(); 711 RTCLog(@"Initializing audio unit for UpdateAudioUnit");
637 712 ConfigureAudioSession();
638 // Initialize the audio unit again with the new sample rate. 713 SetupAudioBuffersForActiveAudioSession();
639 RTC_DCHECK_EQ(playout_parameters_.sample_rate(), sample_rate); 714 if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
640 if (!audio_unit_->Initialize(sample_rate)) { 715 RTCLogError(@"Failed to initialize audio unit.");
641 RTCLogError(@"Failed to initialize the audio unit with sample rate: %f", 716 return;
642 sample_rate); 717 }
643 return false;
644 } 718 }
645 719
646 // Restart the audio unit. 720 if (should_start_audio_unit) {
647 if (!audio_unit_->Start()) { 721 RTCLog(@"Starting audio unit for UpdateAudioUnit");
648 RTCLogError(@"Failed to start audio unit."); 722 if (!audio_unit_->Start()) {
649 return false; 723 RTCLogError(@"Failed to start audio unit.");
724 return;
725 }
650 } 726 }
651 RTCLog(@"Successfully restarted audio unit.");
652 727
653 return true; 728 if (should_stop_audio_unit) {
729 RTCLog(@"Stopping audio unit for UpdateAudioUnit");
730 if (!audio_unit_->Stop()) {
731 RTCLogError(@"Failed to stop audio unit.");
732 return;
733 }
734 }
735
736 if (should_uninitialize_audio_unit) {
737 RTCLog(@"Uninitializing audio unit for UpdateAudioUnit");
738 audio_unit_->Uninitialize();
739 UnconfigureAudioSession();
740 }
741 }
742
743 void AudioDeviceIOS::ConfigureAudioSession() {
744 RTC_DCHECK(thread_checker_.CalledOnValidThread());
745 RTCLog(@"Configuring audio session.");
746 if (has_configured_session_) {
747 RTCLogWarning(@"Audio session already configured.");
748 return;
749 }
750 RTCAudioSession* session = [RTCAudioSession sharedInstance];
751 [session lockForConfiguration];
752 [session configureWebRTCSession:nil];
753 [session unlockForConfiguration];
754 has_configured_session_ = true;
755 RTCLog(@"Configured audio session.");
756 }
757
758 void AudioDeviceIOS::UnconfigureAudioSession() {
759 RTC_DCHECK(thread_checker_.CalledOnValidThread());
760 RTCLog(@"Unconfiguring audio session.");
761 if (!has_configured_session_) {
762 RTCLogWarning(@"Audio session already unconfigured.");
763 return;
764 }
765 RTCAudioSession* session = [RTCAudioSession sharedInstance];
766 [session lockForConfiguration];
767 [session unconfigureWebRTCSession:nil];
768 [session unlockForConfiguration];
769 has_configured_session_ = false;
770 RTCLog(@"Unconfigured audio session.");
654 } 771 }
655 772
656 bool AudioDeviceIOS::InitPlayOrRecord() { 773 bool AudioDeviceIOS::InitPlayOrRecord() {
657 LOGI() << "InitPlayOrRecord"; 774 LOGI() << "InitPlayOrRecord";
658 775
776 // There should be no audio unit at this point.
659 if (!CreateAudioUnit()) { 777 if (!CreateAudioUnit()) {
660 return false; 778 return false;
661 } 779 }
662 780
663 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 781 RTCAudioSession* session = [RTCAudioSession sharedInstance];
664 // Subscribe to audio session events. 782 // Subscribe to audio session events.
665 [session pushDelegate:audio_session_observer_]; 783 [session pushDelegate:audio_session_observer_];
666 784
667 // Lock the session to make configuration changes. 785 // Lock the session to make configuration changes.
668 [session lockForConfiguration]; 786 [session lockForConfiguration];
669 NSError* error = nil; 787 NSError* error = nil;
670 if (![session beginWebRTCSession:&error]) { 788 if (![session beginWebRTCSession:&error]) {
671 [session unlockForConfiguration]; 789 [session unlockForConfiguration];
672 RTCLogError(@"Failed to begin WebRTC session: %@", 790 RTCLogError(@"Failed to begin WebRTC session: %@",
673 error.localizedDescription); 791 error.localizedDescription);
674 return false; 792 return false;
675 } 793 }
676 794
677 // If we are already configured properly, we can initialize the audio unit. 795 // If we are ready to play or record, initialize the audio unit.
678 if (session.isConfiguredForWebRTC) { 796 if (session.canPlayOrRecord) {
679 [session unlockForConfiguration]; 797 ConfigureAudioSession();
680 SetupAudioBuffersForActiveAudioSession(); 798 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()); 799 audio_unit_->Initialize(playout_parameters_.sample_rate());
684 return true;
685 } 800 }
686 801
687 // Release the lock. 802 // Release the lock.
688 [session unlockForConfiguration]; 803 [session unlockForConfiguration];
689 804
690 return true; 805 return true;
691 } 806 }
692 807
693 void AudioDeviceIOS::ShutdownPlayOrRecord() { 808 void AudioDeviceIOS::ShutdownPlayOrRecord() {
694 LOGI() << "ShutdownPlayOrRecord"; 809 LOGI() << "ShutdownPlayOrRecord";
695 810
696 // Close and delete the voice-processing I/O unit. 811 // Close and delete the voice-processing I/O unit.
697 if (audio_unit_) { 812 audio_unit_.reset();
698 audio_unit_.reset();
699 }
700 813
701 // Remove audio session notification observers. 814 // Remove audio session notification observers.
702 RTCAudioSession* session = [RTCAudioSession sharedInstance]; 815 RTCAudioSession* session = [RTCAudioSession sharedInstance];
703 [session removeDelegate:audio_session_observer_]; 816 [session removeDelegate:audio_session_observer_];
704 817
705 // All I/O should be stopped or paused prior to deactivating the audio 818 // All I/O should be stopped or paused prior to deactivating the audio
706 // session, hence we deactivate as last action. 819 // session, hence we deactivate as last action.
707 [session lockForConfiguration]; 820 [session lockForConfiguration];
821 UnconfigureAudioSession();
708 [session endWebRTCSession:nil]; 822 [session endWebRTCSession:nil];
709 [session unlockForConfiguration]; 823 [session unlockForConfiguration];
710 } 824 }
711 825
712 } // namespace webrtc 826 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_device/ios/audio_device_ios.h ('k') | webrtc/modules/audio_device/ios/audio_session_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698