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

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

Issue 2894873002: Improved audio buffer handling for iOS (Closed)
Patch Set: rebased Created 3 years, 6 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
« no previous file with comments | « webrtc/modules/audio_device/ios/audio_device_ios.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
11 #import <AVFoundation/AVFoundation.h> 11 #import <AVFoundation/AVFoundation.h>
12 #import <Foundation/Foundation.h> 12 #import <Foundation/Foundation.h>
13 13
14 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" 14 #include "webrtc/modules/audio_device/ios/audio_device_ios.h"
15 15
16 #include <cmath> 16 #include <cmath>
17 17
18 #include "webrtc/base/array_view.h"
18 #include "webrtc/base/atomicops.h" 19 #include "webrtc/base/atomicops.h"
19 #include "webrtc/base/bind.h" 20 #include "webrtc/base/bind.h"
20 #include "webrtc/base/checks.h" 21 #include "webrtc/base/checks.h"
21 #include "webrtc/base/criticalsection.h" 22 #include "webrtc/base/criticalsection.h"
22 #include "webrtc/base/logging.h" 23 #include "webrtc/base/logging.h"
23 #include "webrtc/base/thread.h" 24 #include "webrtc/base/thread.h"
24 #include "webrtc/base/thread_annotations.h" 25 #include "webrtc/base/thread_annotations.h"
25 #include "webrtc/modules/audio_device/fine_audio_buffer.h" 26 #include "webrtc/modules/audio_device/fine_audio_buffer.h"
26 #include "webrtc/sdk/objc/Framework/Classes/helpers.h" 27 #include "webrtc/sdk/objc/Framework/Classes/helpers.h"
27 28
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 enum AudioDeviceMessageType : uint32_t { 63 enum AudioDeviceMessageType : uint32_t {
63 kMessageTypeInterruptionBegin, 64 kMessageTypeInterruptionBegin,
64 kMessageTypeInterruptionEnd, 65 kMessageTypeInterruptionEnd,
65 kMessageTypeValidRouteChange, 66 kMessageTypeValidRouteChange,
66 kMessageTypeCanPlayOrRecordChange, 67 kMessageTypeCanPlayOrRecordChange,
67 }; 68 };
68 69
69 using ios::CheckAndLogError; 70 using ios::CheckAndLogError;
70 71
71 #if !defined(NDEBUG) 72 #if !defined(NDEBUG)
73 // Returns true when the code runs on a device simulator.
74 static bool DeviceIsSimulator() {
75 return ios::GetDeviceName() == "x86_64";
76 }
77
72 // Helper method that logs essential device information strings. 78 // Helper method that logs essential device information strings.
73 static void LogDeviceInfo() { 79 static void LogDeviceInfo() {
74 LOG(LS_INFO) << "LogDeviceInfo"; 80 LOG(LS_INFO) << "LogDeviceInfo";
75 @autoreleasepool { 81 @autoreleasepool {
76 LOG(LS_INFO) << " system name: " << ios::GetSystemName(); 82 LOG(LS_INFO) << " system name: " << ios::GetSystemName();
77 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString(); 83 LOG(LS_INFO) << " system version 1(2): " << ios::GetSystemVersionAsString();
78 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion(); 84 LOG(LS_INFO) << " system version 2(2): " << ios::GetSystemVersion();
79 LOG(LS_INFO) << " device type: " << ios::GetDeviceType(); 85 LOG(LS_INFO) << " device type: " << ios::GetDeviceType();
80 LOG(LS_INFO) << " device name: " << ios::GetDeviceName(); 86 LOG(LS_INFO) << " device name: " << ios::GetDeviceName();
81 LOG(LS_INFO) << " process name: " << ios::GetProcessName(); 87 LOG(LS_INFO) << " process name: " << ios::GetProcessName();
82 LOG(LS_INFO) << " process ID: " << ios::GetProcessID(); 88 LOG(LS_INFO) << " process ID: " << ios::GetProcessID();
83 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString(); 89 LOG(LS_INFO) << " OS version: " << ios::GetOSVersionString();
84 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount(); 90 LOG(LS_INFO) << " processing cores: " << ios::GetProcessorCount();
85 #if defined(__IPHONE_9_0) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) \ 91 #if defined(__IPHONE_9_0) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) \
86 && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 92 && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
87 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled(); 93 LOG(LS_INFO) << " low power mode: " << ios::GetLowPowerModeEnabled();
88 #endif 94 #endif
95 #if TARGET_IPHONE_SIMULATOR
96 LOG(LS_INFO) << " TARGET_IPHONE_SIMULATOR is defined";
97 #endif
98 LOG(LS_INFO) << " DeviceIsSimulator: " << DeviceIsSimulator();
89 } 99 }
90 } 100 }
91 #endif // !defined(NDEBUG) 101 #endif // !defined(NDEBUG)
92 102
93 AudioDeviceIOS::AudioDeviceIOS() 103 AudioDeviceIOS::AudioDeviceIOS()
94 : audio_device_buffer_(nullptr), 104 : audio_device_buffer_(nullptr),
95 audio_unit_(nullptr), 105 audio_unit_(nullptr),
96 recording_(0), 106 recording_(0),
97 playing_(0), 107 playing_(0),
98 initialized_(false), 108 initialized_(false),
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 } 398 }
389 399
390 // Get a pointer to the recorded audio and send it to the WebRTC ADB. 400 // Get a pointer to the recorded audio and send it to the WebRTC ADB.
391 // Use the FineAudioBuffer instance to convert between native buffer size 401 // Use the FineAudioBuffer instance to convert between native buffer size
392 // and the 10ms buffer size used by WebRTC. 402 // and the 10ms buffer size used by WebRTC.
393 AudioBuffer* audio_buffer = &io_data->mBuffers[0]; 403 AudioBuffer* audio_buffer = &io_data->mBuffers[0];
394 const size_t size_in_bytes = audio_buffer->mDataByteSize; 404 const size_t size_in_bytes = audio_buffer->mDataByteSize;
395 RTC_CHECK_EQ(size_in_bytes / VoiceProcessingAudioUnit::kBytesPerSample, 405 RTC_CHECK_EQ(size_in_bytes / VoiceProcessingAudioUnit::kBytesPerSample,
396 num_frames); 406 num_frames);
397 int8_t* data = static_cast<int8_t*>(audio_buffer->mData); 407 int8_t* data = static_cast<int8_t*>(audio_buffer->mData);
398 fine_audio_buffer_->DeliverRecordedData(data, size_in_bytes, 408 fine_audio_buffer_->DeliverRecordedData(rtc::ArrayView<const int8_t>(data, siz e_in_bytes),
399 kFixedPlayoutDelayEstimate, 409 kFixedPlayoutDelayEstimate,
400 kFixedRecordDelayEstimate); 410 kFixedRecordDelayEstimate);
401 return noErr; 411 return noErr;
402 } 412 }
403 413
404 OSStatus AudioDeviceIOS::OnGetPlayoutData(AudioUnitRenderActionFlags* flags, 414 OSStatus AudioDeviceIOS::OnGetPlayoutData(AudioUnitRenderActionFlags* flags,
405 const AudioTimeStamp* time_stamp, 415 const AudioTimeStamp* time_stamp,
406 UInt32 bus_number, 416 UInt32 bus_number,
407 UInt32 num_frames, 417 UInt32 num_frames,
408 AudioBufferList* io_data) { 418 AudioBufferList* io_data) {
409 // Verify 16-bit, noninterleaved mono PCM signal format. 419 // Verify 16-bit, noninterleaved mono PCM signal format.
410 RTC_DCHECK_EQ(1, io_data->mNumberBuffers); 420 RTC_DCHECK_EQ(1, io_data->mNumberBuffers);
411 AudioBuffer* audio_buffer = &io_data->mBuffers[0]; 421 AudioBuffer* audio_buffer = &io_data->mBuffers[0];
412 RTC_DCHECK_EQ(1, audio_buffer->mNumberChannels); 422 RTC_DCHECK_EQ(1, audio_buffer->mNumberChannels);
413 // Get pointer to internal audio buffer to which new audio data shall be 423 // Get pointer to internal audio buffer to which new audio data shall be
414 // written. 424 // written.
415 const size_t size_in_bytes = audio_buffer->mDataByteSize; 425 const size_t size_in_bytes = audio_buffer->mDataByteSize;
416 RTC_CHECK_EQ(size_in_bytes / VoiceProcessingAudioUnit::kBytesPerSample, 426 RTC_CHECK_EQ(size_in_bytes / VoiceProcessingAudioUnit::kBytesPerSample,
417 num_frames); 427 num_frames);
418 int8_t* destination = reinterpret_cast<int8_t*>(audio_buffer->mData); 428 int8_t* destination = reinterpret_cast<int8_t*>(audio_buffer->mData);
419 // Produce silence and give audio unit a hint about it if playout is not 429 // Produce silence and give audio unit a hint about it if playout is not
420 // activated. 430 // activated.
421 if (!rtc::AtomicOps::AcquireLoad(&playing_)) { 431 if (!rtc::AtomicOps::AcquireLoad(&playing_)) {
422 *flags |= kAudioUnitRenderAction_OutputIsSilence; 432 *flags |= kAudioUnitRenderAction_OutputIsSilence;
423 memset(destination, 0, size_in_bytes); 433 memset(destination, 0, size_in_bytes);
424 return noErr; 434 return noErr;
425 } 435 }
426 // Produce silence and log a warning message for the case when Core Audio is
427 // asking for an invalid number of audio frames. I don't expect this to happen
428 // but it is done as a safety measure to avoid bad audio if such as case would
429 // ever be triggered e.g. in combination with BT devices.
430 const size_t frames_per_buffer = playout_parameters_.frames_per_buffer();
431 if (num_frames != frames_per_buffer) {
432 RTCLogWarning(@"Expected %u frames but got %u",
433 static_cast<unsigned int>(frames_per_buffer),
434 static_cast<unsigned int>(num_frames));
435 *flags |= kAudioUnitRenderAction_OutputIsSilence;
436 memset(destination, 0, size_in_bytes);
437 return noErr;
438 }
439 436
440 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches 437 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches
441 // the native I/O audio unit) to a preallocated intermediate buffer and 438 // the native I/O audio unit) and copy the result to the audio buffer in the
442 // copy the result to the audio buffer in the |io_data| destination. 439 // |io_data| destination.
443 int8_t* source = playout_audio_buffer_.get(); 440 fine_audio_buffer_->GetPlayoutData(rtc::ArrayView<int8_t>(destination, size_in _bytes));
444 fine_audio_buffer_->GetPlayoutData(source);
445 memcpy(destination, source, size_in_bytes);
446 return noErr; 441 return noErr;
447 } 442 }
448 443
449 void AudioDeviceIOS::OnMessage(rtc::Message *msg) { 444 void AudioDeviceIOS::OnMessage(rtc::Message *msg) {
450 switch (msg->message_id) { 445 switch (msg->message_id) {
451 case kMessageTypeInterruptionBegin: 446 case kMessageTypeInterruptionBegin:
452 HandleInterruptionBegin(); 447 HandleInterruptionBegin();
453 break; 448 break;
454 case kMessageTypeInterruptionEnd: 449 case kMessageTypeInterruptionEnd:
455 HandleInterruptionEnd(); 450 HandleInterruptionEnd();
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 LOG(LS_INFO) << " bytes per I/O buffer: " 620 LOG(LS_INFO) << " bytes per I/O buffer: "
626 << playout_parameters_.GetBytesPerBuffer(); 621 << playout_parameters_.GetBytesPerBuffer();
627 RTC_DCHECK_EQ(playout_parameters_.GetBytesPerBuffer(), 622 RTC_DCHECK_EQ(playout_parameters_.GetBytesPerBuffer(),
628 record_parameters_.GetBytesPerBuffer()); 623 record_parameters_.GetBytesPerBuffer());
629 624
630 // Update the ADB parameters since the sample rate might have changed. 625 // Update the ADB parameters since the sample rate might have changed.
631 UpdateAudioDeviceBuffer(); 626 UpdateAudioDeviceBuffer();
632 627
633 // Create a modified audio buffer class which allows us to ask for, 628 // Create a modified audio buffer class which allows us to ask for,
634 // or deliver, any number of samples (and not only multiple of 10ms) to match 629 // or deliver, any number of samples (and not only multiple of 10ms) to match
635 // the native audio unit buffer size. 630 // the native audio unit buffer size. Use a reasonable capacity to avoid
631 // reallocations while audio is played to reduce risk of glitches.
636 RTC_DCHECK(audio_device_buffer_); 632 RTC_DCHECK(audio_device_buffer_);
637 const size_t buffer_size_in_bytes = playout_parameters_.GetBytesPerBuffer(); 633 const size_t capacity_in_bytes = 2 * playout_parameters_.GetBytesPerBuffer();
638 fine_audio_buffer_.reset(new FineAudioBuffer( 634 fine_audio_buffer_.reset(new FineAudioBuffer(
639 audio_device_buffer_, buffer_size_in_bytes, 635 audio_device_buffer_, playout_parameters_.sample_rate(), capacity_in_bytes ));
640 playout_parameters_.sample_rate()));
641 playout_audio_buffer_.reset(new SInt8[buffer_size_in_bytes]);
642 636
643 // Allocate AudioBuffers to be used as storage for the received audio. 637 // Allocate AudioBuffers to be used as storage for the received audio.
644 // The AudioBufferList structure works as a placeholder for the 638 // The AudioBufferList structure works as a placeholder for the
645 // AudioBuffer structure, which holds a pointer to the actual data buffer 639 // AudioBuffer structure, which holds a pointer to the actual data buffer
646 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory 640 // in |record_audio_buffer_|. Recorded audio will be rendered into this memory
647 // at each input callback when calling AudioUnitRender(). 641 // at each input callback when calling AudioUnitRender().
648 const int data_byte_size = record_parameters_.GetBytesPerBuffer(); 642 const int data_byte_size = record_parameters_.GetBytesPerBuffer();
649 record_audio_buffer_.reset(new SInt8[data_byte_size]); 643 record_audio_buffer_.reset(new SInt8[data_byte_size]);
650 memset(record_audio_buffer_.get(), 0, data_byte_size); 644 memset(record_audio_buffer_.get(), 0, data_byte_size);
651 audio_record_buffer_list_.mNumberBuffers = 1; 645 audio_record_buffer_list_.mNumberBuffers = 1;
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 831
838 // All I/O should be stopped or paused prior to deactivating the audio 832 // All I/O should be stopped or paused prior to deactivating the audio
839 // session, hence we deactivate as last action. 833 // session, hence we deactivate as last action.
840 [session lockForConfiguration]; 834 [session lockForConfiguration];
841 UnconfigureAudioSession(); 835 UnconfigureAudioSession();
842 [session endWebRTCSession:nil]; 836 [session endWebRTCSession:nil];
843 [session unlockForConfiguration]; 837 [session unlockForConfiguration];
844 } 838 }
845 839
846 } // namespace webrtc 840 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_device/ios/audio_device_ios.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698