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

Side by Side Diff: media/audio/mac/audio_low_latency_input_mac.cc

Issue 1695303002: Adds Media.Audio.InputDevicePropertyChangedMac UMA stat on Mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed lock Created 4 years, 10 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 // 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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698