Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/mac/audio_low_latency_input_mac.h" | 5 #include "media/audio/mac/audio_low_latency_input_mac.h" |
| 6 | |
| 7 #include <CoreServices/CoreServices.h> | 6 #include <CoreServices/CoreServices.h> |
| 8 | 7 |
| 9 #include "base/logging.h" | 8 #include "base/logging.h" |
| 10 #include "base/mac/mac_logging.h" | 9 #include "base/mac/mac_logging.h" |
| 11 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/metrics/sparse_histogram.h" | 11 #include "base/metrics/sparse_histogram.h" |
| 13 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 14 #include "media/audio/mac/audio_manager_mac.h" | 13 #include "media/audio/mac/audio_manager_mac.h" |
| 15 #include "media/base/audio_bus.h" | 14 #include "media/base/audio_bus.h" |
| 16 #include "media/base/data_buffer.h" | 15 #include "media/base/data_buffer.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 29 // Media.Audio.InputStartupSuccessMac is then updated where true is added | 28 // Media.Audio.InputStartupSuccessMac is then updated where true is added |
| 30 // if input callbacks have started, and false otherwise. | 29 // if input callbacks have started, and false otherwise. |
| 31 const int kInputCallbackStartTimeoutInSeconds = 5; | 30 const int kInputCallbackStartTimeoutInSeconds = 5; |
| 32 | 31 |
| 33 // Returns true if the format flags in |format_flags| has the "non-interleaved" | 32 // Returns true if the format flags in |format_flags| has the "non-interleaved" |
| 34 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0). | 33 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0). |
| 35 static bool FormatIsInterleaved(UInt32 format_flags) { | 34 static bool FormatIsInterleaved(UInt32 format_flags) { |
| 36 return !(format_flags & kAudioFormatFlagIsNonInterleaved); | 35 return !(format_flags & kAudioFormatFlagIsNonInterleaved); |
| 37 } | 36 } |
| 38 | 37 |
| 38 // Converts the 32-bit non-terminated 4 byte string into an std::string. | |
| 39 // Example: code=1735354734 <=> 'goin' <=> kAudioDevicePropertyDeviceIsRunning. | |
| 40 static std::string FourCharFormatCodeToString(UInt32 code) { | |
| 41 char code_string[5]; | |
| 42 // Converts a 32-bit integer from the host’s native byte order to big-endian. | |
| 43 UInt32 code_id = CFSwapInt32HostToBig(code); | |
| 44 bcopy(&code_id, code_string, 4); | |
| 45 code_string[4] = '\0'; | |
| 46 return std::string(code_string); | |
| 47 } | |
| 48 | |
| 39 static std::ostream& operator<<(std::ostream& os, | 49 static std::ostream& operator<<(std::ostream& os, |
| 40 const AudioStreamBasicDescription& format) { | 50 const AudioStreamBasicDescription& format) { |
| 41 // The 32-bit integer format.mFormatID is actually a non-terminated 4 byte | 51 std::string format_string = FourCharFormatCodeToString(format.mFormatID); |
| 42 // string. Example: kAudioFormatLinearPCM = 'lpcm'. | |
| 43 char format_id_string[5]; | |
| 44 // Converts a 32-bit integer from the host’s native byte order to big-endian. | |
| 45 UInt32 format_id = CFSwapInt32HostToBig(format.mFormatID); | |
| 46 bcopy(&format_id, format_id_string, 4); | |
| 47 os << "sample rate : " << format.mSampleRate << std::endl | 52 os << "sample rate : " << format.mSampleRate << std::endl |
| 48 << "format ID : " << format_id_string << std::endl | 53 << "format ID : " << format_string << std::endl |
| 49 << "format flags : " << format.mFormatFlags << std::endl | 54 << "format flags : " << format.mFormatFlags << std::endl |
| 50 << "bytes per packet : " << format.mBytesPerPacket << std::endl | 55 << "bytes per packet : " << format.mBytesPerPacket << std::endl |
| 51 << "frames per packet : " << format.mFramesPerPacket << std::endl | 56 << "frames per packet : " << format.mFramesPerPacket << std::endl |
| 52 << "bytes per frame : " << format.mBytesPerFrame << std::endl | 57 << "bytes per frame : " << format.mBytesPerFrame << std::endl |
| 53 << "channels per frame: " << format.mChannelsPerFrame << std::endl | 58 << "channels per frame: " << format.mChannelsPerFrame << std::endl |
| 54 << "bits per channel : " << format.mBitsPerChannel << std::endl | 59 << "bits per channel : " << format.mBitsPerChannel << std::endl |
| 55 << "reserved : " << format.mReserved << std::endl | 60 << "reserved : " << format.mReserved << std::endl |
| 56 << "interleaved : " | 61 << "interleaved : " |
| 57 << (FormatIsInterleaved(format.mFormatFlags) ? "yes" : "no"); | 62 << (FormatIsInterleaved(format.mFormatFlags) ? "yes" : "no"); |
| 58 return os; | 63 return os; |
| 59 } | 64 } |
| 60 | 65 |
| 66 // Property address to monitor device changes. Use wildcards to match any and | |
| 67 // all values for their associated type. Filtering for device-specific | |
| 68 // notifications will take place in the callback. | |
| 69 const AudioObjectPropertyAddress | |
| 70 AUAudioInputStream::kDeviceChangePropertyAddress = { | |
| 71 kAudioObjectPropertySelectorWildcard, kAudioObjectPropertyScopeWildcard, | |
| 72 kAudioObjectPropertyElementWildcard}; | |
| 73 | |
| 74 // Maps internal enumerator values (e.g. kAudioDevicePropertyDeviceHasChanged) | |
| 75 // into local values that are suitable for UMA stats. | |
| 76 // See AudioObjectPropertySelector in CoreAudio/AudioHardware.h for details. | |
| 77 enum AudioDevicePropertyResult { | |
| 78 PROPERTY_DEVICE_HAS_CHANGED = 0, | |
| 79 PROPERTY_IO_STOPPED_ABNORMALLY = 1, | |
| 80 PROPERTY_HOG_MODE = 2, | |
| 81 PROPERTY_BUFFER_FRAME_SIZE = 3, | |
| 82 PROPERTY_BUFFER_FRAME_SIZE_RANGE = 4, | |
| 83 PROPERTY_STREAM_CONFIGURATION = 5, | |
| 84 PROPERTY_ACTUAL_SAMPLE_RATE = 6, | |
| 85 PROPERTY_NOMINAL_SAMPLE_RATE = 7, | |
| 86 PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE = 8, | |
| 87 PROPERTY_DEVICE_IS_RUNNING = 9, | |
| 88 PROPERTY_DEVICE_IS_ALIVE = 10, | |
| 89 PROPERTY_STREAM_PHYSICAL_FORMAT = 11, | |
| 90 PROPERTY_NOT_SPECIFIED = 12, | |
| 91 PROPERTY_MAX = PROPERTY_NOT_SPECIFIED | |
| 92 }; | |
| 93 | |
| 94 // Add the provided value in |result| to a UMA histogram. | |
| 95 static void LogDevicePropertyChange(const std::string& name, | |
| 96 AudioDevicePropertyResult result) { | |
| 97 UMA_HISTOGRAM_ENUMERATION(name, result, PROPERTY_MAX + 1); | |
|
Ilya Sherman
2016/02/22 18:38:30
The name parameter of the UMA_HISTOGRAM_* macros m
henrika (OOO until Aug 14)
2016/02/22 18:51:58
OK, will create one method for each histogram then
| |
| 98 } | |
| 99 | |
| 61 static OSStatus GetInputDeviceStreamFormat( | 100 static OSStatus GetInputDeviceStreamFormat( |
| 62 AudioUnit audio_unit, | 101 AudioUnit audio_unit, |
| 63 AudioStreamBasicDescription* format) { | 102 AudioStreamBasicDescription* format) { |
| 64 DCHECK(audio_unit); | 103 DCHECK(audio_unit); |
| 65 UInt32 property_size = sizeof(*format); | 104 UInt32 property_size = sizeof(*format); |
| 66 // Get the audio stream data format on the input scope of the input element | 105 // Get the audio stream data format on the input scope of the input element |
| 67 // since it is connected to the current input device. | 106 // since it is connected to the current input device. |
| 68 OSStatus result = | 107 OSStatus result = |
| 69 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, | 108 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, |
| 70 kAudioUnitScope_Input, 1, format, &property_size); | 109 kAudioUnitScope_Input, 1, format, &property_size); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 86 audio_unit_(0), | 125 audio_unit_(0), |
| 87 input_device_id_(audio_device_id), | 126 input_device_id_(audio_device_id), |
| 88 hardware_latency_frames_(0), | 127 hardware_latency_frames_(0), |
| 89 number_of_channels_in_frame_(0), | 128 number_of_channels_in_frame_(0), |
| 90 fifo_(input_params.channels(), | 129 fifo_(input_params.channels(), |
| 91 number_of_frames_, | 130 number_of_frames_, |
| 92 kNumberOfBlocksBufferInFifo), | 131 kNumberOfBlocksBufferInFifo), |
| 93 input_callback_is_active_(false), | 132 input_callback_is_active_(false), |
| 94 start_was_deferred_(false), | 133 start_was_deferred_(false), |
| 95 buffer_size_was_changed_(false), | 134 buffer_size_was_changed_(false), |
| 96 audio_unit_render_has_worked_(false) { | 135 audio_unit_render_has_worked_(false), |
| 136 device_listener_is_active_(false) { | |
| 97 DCHECK(manager_); | 137 DCHECK(manager_); |
| 98 | 138 |
| 99 // Set up the desired (output) format specified by the client. | 139 // Set up the desired (output) format specified by the client. |
| 100 format_.mSampleRate = input_params.sample_rate(); | 140 format_.mSampleRate = input_params.sample_rate(); |
| 101 format_.mFormatID = kAudioFormatLinearPCM; | 141 format_.mFormatID = kAudioFormatLinearPCM; |
| 102 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | | 142 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | |
| 103 kLinearPCMFormatFlagIsSignedInteger; | 143 kLinearPCMFormatFlagIsSignedInteger; |
| 104 DCHECK(FormatIsInterleaved(format_.mFormatFlags)); | 144 DCHECK(FormatIsInterleaved(format_.mFormatFlags)); |
| 105 format_.mBitsPerChannel = input_params.bits_per_sample(); | 145 format_.mBitsPerChannel = input_params.bits_per_sample(); |
| 106 format_.mChannelsPerFrame = input_params.channels(); | 146 format_.mChannelsPerFrame = input_params.channels(); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 128 audio_buffer_list_.mNumberBuffers = 1; | 168 audio_buffer_list_.mNumberBuffers = 1; |
| 129 | 169 |
| 130 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; | 170 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; |
| 131 audio_buffer->mNumberChannels = input_params.channels(); | 171 audio_buffer->mNumberChannels = input_params.channels(); |
| 132 audio_buffer->mDataByteSize = data_byte_size; | 172 audio_buffer->mDataByteSize = data_byte_size; |
| 133 audio_buffer->mData = audio_data_buffer_.get(); | 173 audio_buffer->mData = audio_data_buffer_.get(); |
| 134 } | 174 } |
| 135 | 175 |
| 136 AUAudioInputStream::~AUAudioInputStream() { | 176 AUAudioInputStream::~AUAudioInputStream() { |
| 137 DVLOG(1) << "~dtor"; | 177 DVLOG(1) << "~dtor"; |
| 178 DCHECK(!device_listener_is_active_); | |
| 138 } | 179 } |
| 139 | 180 |
| 140 // Obtain and open the AUHAL AudioOutputUnit for recording. | 181 // Obtain and open the AUHAL AudioOutputUnit for recording. |
| 141 bool AUAudioInputStream::Open() { | 182 bool AUAudioInputStream::Open() { |
| 142 DCHECK(thread_checker_.CalledOnValidThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
| 143 DVLOG(1) << "Open"; | 184 DVLOG(1) << "Open"; |
| 144 DCHECK(!audio_unit_); | 185 DCHECK(!audio_unit_); |
| 145 | 186 |
| 146 // Verify that we have a valid device. Send appropriate error code to | 187 // Verify that we have a valid device. Send appropriate error code to |
| 147 // HandleError() to ensure that the error type is added to UMA stats. | 188 // HandleError() to ensure that the error type is added to UMA stats. |
| 148 if (input_device_id_ == kAudioObjectUnknown) { | 189 if (input_device_id_ == kAudioObjectUnknown) { |
| 149 NOTREACHED() << "Device ID is unknown"; | 190 NOTREACHED() << "Device ID is unknown"; |
| 150 HandleError(kAudioUnitErr_InvalidElement); | 191 HandleError(kAudioUnitErr_InvalidElement); |
| 151 return false; | 192 return false; |
| 152 } | 193 } |
| 153 | 194 |
| 195 // Start listening for changes in device properties. | |
| 196 RegisterDeviceChangeListener(); | |
| 197 | |
| 154 // The requested sample-rate must match the hardware sample-rate. | 198 // The requested sample-rate must match the hardware sample-rate. |
| 155 int sample_rate = | 199 int sample_rate = |
| 156 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_); | 200 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_); |
| 157 DCHECK_EQ(sample_rate, format_.mSampleRate); | 201 DCHECK_EQ(sample_rate, format_.mSampleRate); |
| 158 | 202 |
| 159 // Start by obtaining an AudioOuputUnit using an AUHAL component description. | 203 // Start by obtaining an AudioOuputUnit using an AUHAL component description. |
| 160 | 204 |
| 161 // Description for the Audio Unit we want to use (AUHAL in this case). | 205 // Description for the Audio Unit we want to use (AUHAL in this case). |
| 162 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device. | 206 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device. |
| 163 // The user specifies which audio device to track. The audio unit can do | 207 // The user specifies which audio device to track. The audio unit can do |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 } | 464 } |
| 421 | 465 |
| 422 void AUAudioInputStream::Close() { | 466 void AUAudioInputStream::Close() { |
| 423 DCHECK(thread_checker_.CalledOnValidThread()); | 467 DCHECK(thread_checker_.CalledOnValidThread()); |
| 424 DVLOG(1) << "Close"; | 468 DVLOG(1) << "Close"; |
| 425 // It is valid to call Close() before calling open or Start(). | 469 // It is valid to call Close() before calling open or Start(). |
| 426 // It is also valid to call Close() after Start() has been called. | 470 // It is also valid to call Close() after Start() has been called. |
| 427 if (IsRunning()) { | 471 if (IsRunning()) { |
| 428 Stop(); | 472 Stop(); |
| 429 } | 473 } |
| 474 // Uninitialize and dispose the audio unit. | |
| 430 CloseAudioUnit(); | 475 CloseAudioUnit(); |
| 476 // Disable the listener for device property changes. | |
| 477 DeRegisterDeviceChangeListener(); | |
| 478 // Check if any device property changes are added by filtering out a selected | |
| 479 // set of the |device_property_changes_map_| map. Add UMA stats if valuable | |
| 480 // data is found. | |
| 481 AddDevicePropertyChangesToUMA("Media.Audio.InputDevicePropertyChangedMac"); | |
| 431 // Inform the audio manager that we have been closed. This will cause our | 482 // Inform the audio manager that we have been closed. This will cause our |
| 432 // destruction. | 483 // destruction. |
| 433 manager_->ReleaseInputStream(this); | 484 manager_->ReleaseInputStream(this); |
| 434 } | 485 } |
| 435 | 486 |
| 436 double AUAudioInputStream::GetMaxVolume() { | 487 double AUAudioInputStream::GetMaxVolume() { |
| 437 // Verify that we have a valid device. | 488 // Verify that we have a valid device. |
| 438 if (input_device_id_ == kAudioObjectUnknown) { | 489 if (input_device_id_ == kAudioObjectUnknown) { |
| 439 NOTREACHED() << "Device ID is unknown"; | 490 NOTREACHED() << "Device ID is unknown"; |
| 440 return 0.0; | 491 return 0.0; |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); | 794 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); |
| 744 | 795 |
| 745 // Compensate the audio delay caused by the FIFO. | 796 // Compensate the audio delay caused by the FIFO. |
| 746 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; | 797 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; |
| 747 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); | 798 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); |
| 748 } | 799 } |
| 749 | 800 |
| 750 return noErr; | 801 return noErr; |
| 751 } | 802 } |
| 752 | 803 |
| 804 OSStatus AUAudioInputStream::OnDevicePropertyChanged( | |
| 805 AudioObjectID object_id, | |
| 806 UInt32 num_addresses, | |
| 807 const AudioObjectPropertyAddress addresses[], | |
| 808 void* context) { | |
| 809 AUAudioInputStream* self = static_cast<AUAudioInputStream*>(context); | |
| 810 return self->DevicePropertyChanged(object_id, num_addresses, addresses); | |
| 811 } | |
| 812 | |
| 813 OSStatus AUAudioInputStream::DevicePropertyChanged( | |
| 814 AudioObjectID object_id, | |
| 815 UInt32 num_addresses, | |
| 816 const AudioObjectPropertyAddress addresses[]) { | |
| 817 if (object_id != input_device_id_) | |
| 818 return noErr; | |
| 819 | |
| 820 // Listeners will be called when possibly many properties have changed. | |
| 821 // Consequently, the implementation of a listener must go through the array of | |
| 822 // addresses to see what exactly has changed. | |
| 823 for (UInt32 i = 0; i < num_addresses; ++i) { | |
| 824 const UInt32 property = addresses[i].mSelector; | |
| 825 // Use selector as key to a map and increase its value. We are not | |
| 826 // interested in all property changes but store all here anyhow. | |
| 827 // Filtering will be done later in AddDevicePropertyChangesToUMA(); | |
| 828 ++device_property_changes_map_[property]; | |
| 829 } | |
| 830 return noErr; | |
| 831 } | |
| 832 | |
| 833 void AUAudioInputStream::RegisterDeviceChangeListener() { | |
| 834 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 835 DCHECK(!device_listener_is_active_); | |
| 836 DVLOG(1) << "RegisterDeviceChangeListener"; | |
| 837 if (input_device_id_ == kAudioObjectUnknown) | |
| 838 return; | |
| 839 device_property_changes_map_.clear(); | |
| 840 OSStatus result = AudioObjectAddPropertyListener( | |
| 841 input_device_id_, &kDeviceChangePropertyAddress, | |
| 842 &AUAudioInputStream::OnDevicePropertyChanged, this); | |
| 843 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | |
| 844 << "AudioObjectAddPropertyListener() failed!"; | |
| 845 device_listener_is_active_ = true; | |
| 846 } | |
| 847 | |
| 848 void AUAudioInputStream::DeRegisterDeviceChangeListener() { | |
| 849 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 850 if (!device_listener_is_active_) | |
| 851 return; | |
| 852 DVLOG(1) << "DeRegisterDeviceChangeListener"; | |
| 853 if (input_device_id_ == kAudioObjectUnknown) | |
| 854 return; | |
| 855 device_listener_is_active_ = false; | |
| 856 OSStatus result = AudioObjectRemovePropertyListener( | |
| 857 input_device_id_, &kDeviceChangePropertyAddress, | |
| 858 &AUAudioInputStream::OnDevicePropertyChanged, this); | |
| 859 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | |
| 860 << "AudioObjectRemovePropertyListener() failed!"; | |
| 861 } | |
| 862 | |
| 753 int AUAudioInputStream::HardwareSampleRate() { | 863 int AUAudioInputStream::HardwareSampleRate() { |
| 754 // Determine the default input device's sample-rate. | 864 // Determine the default input device's sample-rate. |
| 755 AudioDeviceID device_id = kAudioObjectUnknown; | 865 AudioDeviceID device_id = kAudioObjectUnknown; |
| 756 UInt32 info_size = sizeof(device_id); | 866 UInt32 info_size = sizeof(device_id); |
| 757 | 867 |
| 758 AudioObjectPropertyAddress default_input_device_address = { | 868 AudioObjectPropertyAddress default_input_device_address = { |
| 759 kAudioHardwarePropertyDefaultInputDevice, | 869 kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, |
| 760 kAudioObjectPropertyScopeGlobal, | 870 kAudioObjectPropertyElementMaster}; |
| 761 kAudioObjectPropertyElementMaster | |
| 762 }; | |
| 763 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 871 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
| 764 &default_input_device_address, | 872 &default_input_device_address, 0, |
| 765 0, | 873 0, &info_size, &device_id); |
| 766 0, | |
| 767 &info_size, | |
| 768 &device_id); | |
| 769 if (result != noErr) | 874 if (result != noErr) |
| 770 return 0.0; | 875 return 0.0; |
| 771 | 876 |
| 772 Float64 nominal_sample_rate; | 877 Float64 nominal_sample_rate; |
| 773 info_size = sizeof(nominal_sample_rate); | 878 info_size = sizeof(nominal_sample_rate); |
| 774 | 879 |
| 775 AudioObjectPropertyAddress nominal_sample_rate_address = { | 880 AudioObjectPropertyAddress nominal_sample_rate_address = { |
| 776 kAudioDevicePropertyNominalSampleRate, | 881 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, |
| 777 kAudioObjectPropertyScopeGlobal, | 882 kAudioObjectPropertyElementMaster}; |
| 778 kAudioObjectPropertyElementMaster | 883 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address, |
| 779 }; | 884 0, 0, &info_size, &nominal_sample_rate); |
| 780 result = AudioObjectGetPropertyData(device_id, | |
| 781 &nominal_sample_rate_address, | |
| 782 0, | |
| 783 0, | |
| 784 &info_size, | |
| 785 &nominal_sample_rate); | |
| 786 if (result != noErr) | 885 if (result != noErr) |
| 787 return 0.0; | 886 return 0.0; |
| 788 | 887 |
| 789 return static_cast<int>(nominal_sample_rate); | 888 return static_cast<int>(nominal_sample_rate); |
| 790 } | 889 } |
| 791 | 890 |
| 792 double AUAudioInputStream::GetHardwareLatency() { | 891 double AUAudioInputStream::GetHardwareLatency() { |
| 793 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { | 892 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { |
| 794 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; | 893 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; |
| 795 return 0.0; | 894 return 0.0; |
| 796 } | 895 } |
| 797 | 896 |
| 798 // Get audio unit latency. | 897 // Get audio unit latency. |
| 799 Float64 audio_unit_latency_sec = 0.0; | 898 Float64 audio_unit_latency_sec = 0.0; |
| 800 UInt32 size = sizeof(audio_unit_latency_sec); | 899 UInt32 size = sizeof(audio_unit_latency_sec); |
| 801 OSStatus result = AudioUnitGetProperty(audio_unit_, | 900 OSStatus result = AudioUnitGetProperty( |
| 802 kAudioUnitProperty_Latency, | 901 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, |
| 803 kAudioUnitScope_Global, | 902 &audio_unit_latency_sec, &size); |
| 804 0, | |
| 805 &audio_unit_latency_sec, | |
| 806 &size); | |
| 807 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) | 903 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
| 808 << "Could not get audio unit latency"; | 904 << "Could not get audio unit latency"; |
| 809 | 905 |
| 810 // Get input audio device latency. | 906 // Get input audio device latency. |
| 811 AudioObjectPropertyAddress property_address = { | 907 AudioObjectPropertyAddress property_address = { |
| 812 kAudioDevicePropertyLatency, | 908 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput, |
| 813 kAudioDevicePropertyScopeInput, | 909 kAudioObjectPropertyElementMaster}; |
| 814 kAudioObjectPropertyElementMaster | |
| 815 }; | |
| 816 UInt32 device_latency_frames = 0; | 910 UInt32 device_latency_frames = 0; |
| 817 size = sizeof(device_latency_frames); | 911 size = sizeof(device_latency_frames); |
| 818 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, | 912 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, |
| 819 nullptr, &size, &device_latency_frames); | 913 nullptr, &size, &device_latency_frames); |
| 820 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; | 914 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; |
| 821 | 915 |
| 822 return static_cast<double>((audio_unit_latency_sec * | 916 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) + |
| 823 format_.mSampleRate) + device_latency_frames); | 917 device_latency_frames); |
| 824 } | 918 } |
| 825 | 919 |
| 826 double AUAudioInputStream::GetCaptureLatency( | 920 double AUAudioInputStream::GetCaptureLatency( |
| 827 const AudioTimeStamp* input_time_stamp) { | 921 const AudioTimeStamp* input_time_stamp) { |
| 828 // Get the delay between between the actual recording instant and the time | 922 // Get the delay between between the actual recording instant and the time |
| 829 // when the data packet is provided as a callback. | 923 // when the data packet is provided as a callback. |
| 830 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( | 924 UInt64 capture_time_ns = |
| 831 input_time_stamp->mHostTime); | 925 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime); |
| 832 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 926 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
| 833 double delay_frames = static_cast<double> | 927 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) * |
| 834 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); | 928 format_.mSampleRate); |
| 835 | 929 |
| 836 // Total latency is composed by the dynamic latency and the fixed | 930 // Total latency is composed by the dynamic latency and the fixed |
| 837 // hardware latency. | 931 // hardware latency. |
| 838 return (delay_frames + hardware_latency_frames_); | 932 return (delay_frames + hardware_latency_frames_); |
| 839 } | 933 } |
| 840 | 934 |
| 841 int AUAudioInputStream::GetNumberOfChannelsFromStream() { | 935 int AUAudioInputStream::GetNumberOfChannelsFromStream() { |
| 842 // Get the stream format, to be able to read the number of channels. | 936 // Get the stream format, to be able to read the number of channels. |
| 843 AudioObjectPropertyAddress property_address = { | 937 AudioObjectPropertyAddress property_address = { |
| 844 kAudioDevicePropertyStreamFormat, | 938 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, |
| 845 kAudioDevicePropertyScopeInput, | 939 kAudioObjectPropertyElementMaster}; |
| 846 kAudioObjectPropertyElementMaster | |
| 847 }; | |
| 848 AudioStreamBasicDescription stream_format; | 940 AudioStreamBasicDescription stream_format; |
| 849 UInt32 size = sizeof(stream_format); | 941 UInt32 size = sizeof(stream_format); |
| 850 OSStatus result = AudioObjectGetPropertyData( | 942 OSStatus result = AudioObjectGetPropertyData( |
| 851 input_device_id_, &property_address, 0, nullptr, &size, &stream_format); | 943 input_device_id_, &property_address, 0, nullptr, &size, &stream_format); |
| 852 if (result != noErr) { | 944 if (result != noErr) { |
| 853 DLOG(WARNING) << "Could not get stream format"; | 945 DLOG(WARNING) << "Could not get stream format"; |
| 854 return 0; | 946 return 0; |
| 855 } | 947 } |
| 856 | 948 |
| 857 return static_cast<int>(stream_format.mChannelsPerFrame); | 949 return static_cast<int>(stream_format.mChannelsPerFrame); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 870 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed"; | 962 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed"; |
| 871 return (error == noErr && is_running); | 963 return (error == noErr && is_running); |
| 872 } | 964 } |
| 873 | 965 |
| 874 void AUAudioInputStream::HandleError(OSStatus err) { | 966 void AUAudioInputStream::HandleError(OSStatus err) { |
| 875 // Log the latest OSStatus error message and also change the sign of the | 967 // Log the latest OSStatus error message and also change the sign of the |
| 876 // error if no callbacks are active. I.e., the sign of the error message | 968 // error if no callbacks are active. I.e., the sign of the error message |
| 877 // carries one extra level of information. | 969 // carries one extra level of information. |
| 878 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac", | 970 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac", |
| 879 GetInputCallbackIsActive() ? err : (err * -1)); | 971 GetInputCallbackIsActive() ? err : (err * -1)); |
| 880 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) | 972 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err |
| 881 << " (" << err << ")"; | 973 << ")"; |
| 882 if (sink_) | 974 if (sink_) |
| 883 sink_->OnError(this); | 975 sink_->OnError(this); |
| 884 } | 976 } |
| 885 | 977 |
| 886 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { | 978 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { |
| 887 Boolean is_settable = false; | 979 Boolean is_settable = false; |
| 888 AudioObjectPropertyAddress property_address = { | 980 AudioObjectPropertyAddress property_address = { |
| 889 kAudioDevicePropertyVolumeScalar, | 981 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, |
| 890 kAudioDevicePropertyScopeInput, | 982 static_cast<UInt32>(channel)}; |
| 891 static_cast<UInt32>(channel) | 983 OSStatus result = AudioObjectIsPropertySettable( |
| 892 }; | 984 input_device_id_, &property_address, &is_settable); |
| 893 OSStatus result = AudioObjectIsPropertySettable(input_device_id_, | |
| 894 &property_address, | |
| 895 &is_settable); | |
| 896 return (result == noErr) ? is_settable : false; | 985 return (result == noErr) ? is_settable : false; |
| 897 } | 986 } |
| 898 | 987 |
| 899 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) { | 988 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) { |
| 900 base::subtle::Release_Store(&input_callback_is_active_, enabled); | 989 base::subtle::Release_Store(&input_callback_is_active_, enabled); |
| 901 } | 990 } |
| 902 | 991 |
| 903 bool AUAudioInputStream::GetInputCallbackIsActive() { | 992 bool AUAudioInputStream::GetInputCallbackIsActive() { |
| 904 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); | 993 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); |
| 905 } | 994 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 943 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", | 1032 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", |
| 944 start_was_deferred_); | 1033 start_was_deferred_); |
| 945 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", | 1034 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", |
| 946 buffer_size_was_changed_); | 1035 buffer_size_was_changed_); |
| 947 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", | 1036 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", |
| 948 manager_->output_streams()); | 1037 manager_->output_streams()); |
| 949 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", | 1038 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", |
| 950 manager_->low_latency_input_streams()); | 1039 manager_->low_latency_input_streams()); |
| 951 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac", | 1040 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac", |
| 952 manager_->basic_input_streams()); | 1041 manager_->basic_input_streams()); |
| 953 // |number_of_frames_| is set at construction and corresponds to the requested | 1042 // |number_of_frames_| is set at construction and corresponds to the |
| 954 // (by the client) number of audio frames per I/O buffer connected to the | 1043 // requested (by the client) number of audio frames per I/O buffer connected |
| 955 // selected input device. Ideally, this size will be the same as the native | 1044 // to the selected input device. Ideally, this size will be the same as the |
| 956 // I/O buffer size given by |io_buffer_frame_size_|. | 1045 // native I/O buffer size given by |io_buffer_frame_size_|. |
| 957 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac", | 1046 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac", |
| 958 number_of_frames_); | 1047 number_of_frames_); |
| 959 DVLOG(1) << "number_of_frames_: " << number_of_frames_; | 1048 DVLOG(1) << "number_of_frames_: " << number_of_frames_; |
| 960 // This value indicates the number of frames in the IO buffers connected to | 1049 // This value indicates the number of frames in the IO buffers connected |
| 961 // the selected input device. It has been set by the audio manger in Open() | 1050 // to the selected input device. It has been set by the audio manger in |
| 962 // and can be the same as |number_of_frames_|, which is the desired buffer | 1051 // Open() and can be the same as |number_of_frames_|, which is the desired |
| 963 // size. These two values might differ if other streams are using the same | 1052 // buffer size. These two values might differ if other streams are using the |
| 964 // device and any of these streams have asked for a smaller buffer size. | 1053 // same device and any of these streams have asked for a smaller buffer size. |
| 965 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", | 1054 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", |
| 966 io_buffer_frame_size_); | 1055 io_buffer_frame_size_); |
| 967 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; | 1056 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; |
| 968 // TODO(henrika): this value will currently always report true. It should be | 1057 // TODO(henrika): this value will currently always report true. It should |
| 969 // fixed when we understand the problem better. | 1058 // be fixed when we understand the problem better. |
| 970 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", | 1059 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", |
| 971 GetAutomaticGainControl()); | 1060 GetAutomaticGainControl()); |
| 1061 // Disable the listener for device property changes. Ensures that we don't | |
| 1062 // need a lock when reading the map. | |
| 1063 DeRegisterDeviceChangeListener(); | |
| 1064 // Check if any device property changes are added by filtering out a selected | |
| 1065 // set of the |device_property_changes_map_| map. Add UMA stats if valuable | |
| 1066 // data is found. | |
| 1067 AddDevicePropertyChangesToUMA( | |
| 1068 "Media.Audio.InputDevicePropertyChangedStartupFailedMac"); | |
| 1069 } | |
| 1070 | |
| 1071 void AUAudioInputStream::AddDevicePropertyChangesToUMA( | |
| 1072 const std::string& name) { | |
| 1073 DVLOG(1) << "AddDevicePropertyChangesToUMA"; | |
| 1074 // Scan the map of all available property changes (notification types) and | |
| 1075 // filter out some that make sense to add to UMA stats. | |
| 1076 // TODO(henrika): figure out if the set of stats is sufficient or not. | |
| 1077 for (auto it = device_property_changes_map_.begin(); | |
| 1078 it != device_property_changes_map_.end(); ++it) { | |
| 1079 UInt32 device_property = it->first; | |
| 1080 int change_count = it->second; | |
| 1081 AudioDevicePropertyResult uma_result = PROPERTY_NOT_SPECIFIED; | |
| 1082 switch (device_property) { | |
| 1083 case kAudioDevicePropertyDeviceHasChanged: | |
| 1084 uma_result = PROPERTY_DEVICE_HAS_CHANGED; | |
| 1085 DVLOG(1) << "kAudioDevicePropertyDeviceHasChanged"; | |
| 1086 break; | |
| 1087 case kAudioDevicePropertyIOStoppedAbnormally: | |
| 1088 uma_result = PROPERTY_IO_STOPPED_ABNORMALLY; | |
| 1089 DVLOG(1) << "kAudioDevicePropertyIOStoppedAbnormally"; | |
| 1090 break; | |
| 1091 case kAudioDevicePropertyHogMode: | |
| 1092 uma_result = PROPERTY_HOG_MODE; | |
| 1093 DVLOG(1) << "kAudioDevicePropertyHogMode"; | |
| 1094 break; | |
| 1095 case kAudioDevicePropertyBufferFrameSize: | |
| 1096 uma_result = PROPERTY_BUFFER_FRAME_SIZE; | |
| 1097 DVLOG(1) << "kAudioDevicePropertyBufferFrameSize"; | |
| 1098 break; | |
| 1099 case kAudioDevicePropertyBufferFrameSizeRange: | |
| 1100 uma_result = PROPERTY_BUFFER_FRAME_SIZE_RANGE; | |
| 1101 DVLOG(1) << "kAudioDevicePropertyBufferFrameSizeRange"; | |
| 1102 break; | |
| 1103 case kAudioDevicePropertyStreamConfiguration: | |
| 1104 uma_result = PROPERTY_STREAM_CONFIGURATION; | |
| 1105 DVLOG(1) << "kAudioDevicePropertyStreamConfiguration"; | |
| 1106 break; | |
| 1107 case kAudioDevicePropertyActualSampleRate: | |
| 1108 uma_result = PROPERTY_ACTUAL_SAMPLE_RATE; | |
| 1109 DVLOG(1) << "kAudioDevicePropertyActualSampleRate"; | |
| 1110 break; | |
| 1111 case kAudioDevicePropertyNominalSampleRate: | |
| 1112 uma_result = PROPERTY_NOMINAL_SAMPLE_RATE; | |
| 1113 DVLOG(1) << "kAudioDevicePropertyNominalSampleRate"; | |
| 1114 break; | |
| 1115 case kAudioDevicePropertyDeviceIsRunningSomewhere: | |
| 1116 uma_result = PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE; | |
| 1117 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunningSomewhere"; | |
| 1118 break; | |
| 1119 case kAudioDevicePropertyDeviceIsRunning: | |
| 1120 uma_result = PROPERTY_DEVICE_IS_RUNNING; | |
| 1121 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunning"; | |
| 1122 break; | |
| 1123 case kAudioDevicePropertyDeviceIsAlive: | |
| 1124 uma_result = PROPERTY_DEVICE_IS_ALIVE; | |
| 1125 DVLOG(1) << "kAudioDevicePropertyDeviceIsAlive"; | |
| 1126 break; | |
| 1127 case kAudioStreamPropertyPhysicalFormat: | |
| 1128 uma_result = PROPERTY_STREAM_PHYSICAL_FORMAT; | |
| 1129 DVLOG(1) << "kAudioStreamPropertyPhysicalFormat"; | |
| 1130 break; | |
| 1131 default: | |
| 1132 uma_result = PROPERTY_NOT_SPECIFIED; | |
|
Ilya Sherman
2016/02/22 18:38:30
nit: Maybe name this "PROPERTY_OTHER" or something
henrika (OOO until Aug 14)
2016/02/22 18:51:58
Will rename to OTHER.
henrika (OOO until Aug 14)
2016/02/23 11:34:53
Done.
| |
| 1133 DVLOG(1) << "Property change is ignored"; | |
| 1134 break; | |
| 1135 } | |
| 1136 DVLOG(1) << "property: " << device_property << " (" | |
| 1137 << FourCharFormatCodeToString(device_property) << ")" | |
| 1138 << " changed: " << change_count; | |
| 1139 LogDevicePropertyChange(name, uma_result); | |
| 1140 } | |
| 1141 device_property_changes_map_.clear(); | |
| 972 } | 1142 } |
| 973 | 1143 |
| 974 } // namespace media | 1144 } // namespace media |
| OLD | NEW |