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

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: My own XML parts 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
« no previous file with comments | « media/audio/mac/audio_low_latency_input_mac.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
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 base::AutoLock auto_lock(lock_);
821 // Listeners will be called when possibly many properties have changed.
822 // Consequently, the implementation of a listener must go through the array of
823 // addresses to see what exactly has changed.
824 for (UInt32 i = 0; i < num_addresses; ++i) {
825 const UInt32 property = addresses[i].mSelector;
826 // Use selector as key to a map and increase its value. We are not
827 // interested in all property changes but store all here anyhow.
828 // Filtering will be done later in AddDevicePropertyChangesToUMA();
829 ++device_property_changes_map_[property];
830 }
831 return noErr;
832 }
833
834 void AUAudioInputStream::RegisterDeviceChangeListener() {
835 DCHECK(thread_checker_.CalledOnValidThread());
836 DCHECK(!device_listener_is_active_);
837 DVLOG(1) << "RegisterDeviceChangeListener";
838 if (input_device_id_ == kAudioObjectUnknown)
839 return;
840 device_property_changes_map_.clear();
841 OSStatus result = AudioObjectAddPropertyListener(
842 input_device_id_, &kDeviceChangePropertyAddress,
843 &AUAudioInputStream::OnDevicePropertyChanged, this);
844 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
845 << "AudioObjectAddPropertyListener() failed!";
846 device_listener_is_active_ = true;
847 }
848
849 void AUAudioInputStream::DeRegisterDeviceChangeListener() {
850 DCHECK(thread_checker_.CalledOnValidThread());
851 if (!device_listener_is_active_)
852 return;
853 DVLOG(1) << "DeRegisterDeviceChangeListener";
854 if (input_device_id_ == kAudioObjectUnknown)
855 return;
856 device_listener_is_active_ = false;
857 OSStatus result = AudioObjectRemovePropertyListener(
858 input_device_id_, &kDeviceChangePropertyAddress,
859 &AUAudioInputStream::OnDevicePropertyChanged, this);
860 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
861 << "AudioObjectRemovePropertyListener() failed!";
862 }
863
753 int AUAudioInputStream::HardwareSampleRate() { 864 int AUAudioInputStream::HardwareSampleRate() {
754 // Determine the default input device's sample-rate. 865 // Determine the default input device's sample-rate.
755 AudioDeviceID device_id = kAudioObjectUnknown; 866 AudioDeviceID device_id = kAudioObjectUnknown;
756 UInt32 info_size = sizeof(device_id); 867 UInt32 info_size = sizeof(device_id);
757 868
758 AudioObjectPropertyAddress default_input_device_address = { 869 AudioObjectPropertyAddress default_input_device_address = {
759 kAudioHardwarePropertyDefaultInputDevice, 870 kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
760 kAudioObjectPropertyScopeGlobal, 871 kAudioObjectPropertyElementMaster};
761 kAudioObjectPropertyElementMaster
762 };
763 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 872 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
764 &default_input_device_address, 873 &default_input_device_address, 0,
765 0, 874 0, &info_size, &device_id);
766 0,
767 &info_size,
768 &device_id);
769 if (result != noErr) 875 if (result != noErr)
770 return 0.0; 876 return 0.0;
771 877
772 Float64 nominal_sample_rate; 878 Float64 nominal_sample_rate;
773 info_size = sizeof(nominal_sample_rate); 879 info_size = sizeof(nominal_sample_rate);
774 880
775 AudioObjectPropertyAddress nominal_sample_rate_address = { 881 AudioObjectPropertyAddress nominal_sample_rate_address = {
776 kAudioDevicePropertyNominalSampleRate, 882 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
777 kAudioObjectPropertyScopeGlobal, 883 kAudioObjectPropertyElementMaster};
778 kAudioObjectPropertyElementMaster 884 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address,
779 }; 885 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) 886 if (result != noErr)
787 return 0.0; 887 return 0.0;
788 888
789 return static_cast<int>(nominal_sample_rate); 889 return static_cast<int>(nominal_sample_rate);
790 } 890 }
791 891
792 double AUAudioInputStream::GetHardwareLatency() { 892 double AUAudioInputStream::GetHardwareLatency() {
793 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { 893 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
794 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; 894 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
795 return 0.0; 895 return 0.0;
796 } 896 }
797 897
798 // Get audio unit latency. 898 // Get audio unit latency.
799 Float64 audio_unit_latency_sec = 0.0; 899 Float64 audio_unit_latency_sec = 0.0;
800 UInt32 size = sizeof(audio_unit_latency_sec); 900 UInt32 size = sizeof(audio_unit_latency_sec);
801 OSStatus result = AudioUnitGetProperty(audio_unit_, 901 OSStatus result = AudioUnitGetProperty(
802 kAudioUnitProperty_Latency, 902 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,
803 kAudioUnitScope_Global, 903 &audio_unit_latency_sec, &size);
804 0,
805 &audio_unit_latency_sec,
806 &size);
807 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) 904 OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
808 << "Could not get audio unit latency"; 905 << "Could not get audio unit latency";
809 906
810 // Get input audio device latency. 907 // Get input audio device latency.
811 AudioObjectPropertyAddress property_address = { 908 AudioObjectPropertyAddress property_address = {
812 kAudioDevicePropertyLatency, 909 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput,
813 kAudioDevicePropertyScopeInput, 910 kAudioObjectPropertyElementMaster};
814 kAudioObjectPropertyElementMaster
815 };
816 UInt32 device_latency_frames = 0; 911 UInt32 device_latency_frames = 0;
817 size = sizeof(device_latency_frames); 912 size = sizeof(device_latency_frames);
818 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, 913 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
819 nullptr, &size, &device_latency_frames); 914 nullptr, &size, &device_latency_frames);
820 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; 915 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
821 916
822 return static_cast<double>((audio_unit_latency_sec * 917 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) +
823 format_.mSampleRate) + device_latency_frames); 918 device_latency_frames);
824 } 919 }
825 920
826 double AUAudioInputStream::GetCaptureLatency( 921 double AUAudioInputStream::GetCaptureLatency(
827 const AudioTimeStamp* input_time_stamp) { 922 const AudioTimeStamp* input_time_stamp) {
828 // Get the delay between between the actual recording instant and the time 923 // Get the delay between between the actual recording instant and the time
829 // when the data packet is provided as a callback. 924 // when the data packet is provided as a callback.
830 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( 925 UInt64 capture_time_ns =
831 input_time_stamp->mHostTime); 926 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime);
832 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 927 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
833 double delay_frames = static_cast<double> 928 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) *
834 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 929 format_.mSampleRate);
835 930
836 // Total latency is composed by the dynamic latency and the fixed 931 // Total latency is composed by the dynamic latency and the fixed
837 // hardware latency. 932 // hardware latency.
838 return (delay_frames + hardware_latency_frames_); 933 return (delay_frames + hardware_latency_frames_);
839 } 934 }
840 935
841 int AUAudioInputStream::GetNumberOfChannelsFromStream() { 936 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
842 // Get the stream format, to be able to read the number of channels. 937 // Get the stream format, to be able to read the number of channels.
843 AudioObjectPropertyAddress property_address = { 938 AudioObjectPropertyAddress property_address = {
844 kAudioDevicePropertyStreamFormat, 939 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput,
845 kAudioDevicePropertyScopeInput, 940 kAudioObjectPropertyElementMaster};
846 kAudioObjectPropertyElementMaster
847 };
848 AudioStreamBasicDescription stream_format; 941 AudioStreamBasicDescription stream_format;
849 UInt32 size = sizeof(stream_format); 942 UInt32 size = sizeof(stream_format);
850 OSStatus result = AudioObjectGetPropertyData( 943 OSStatus result = AudioObjectGetPropertyData(
851 input_device_id_, &property_address, 0, nullptr, &size, &stream_format); 944 input_device_id_, &property_address, 0, nullptr, &size, &stream_format);
852 if (result != noErr) { 945 if (result != noErr) {
853 DLOG(WARNING) << "Could not get stream format"; 946 DLOG(WARNING) << "Could not get stream format";
854 return 0; 947 return 0;
855 } 948 }
856 949
857 return static_cast<int>(stream_format.mChannelsPerFrame); 950 return static_cast<int>(stream_format.mChannelsPerFrame);
(...skipping 12 matching lines...) Expand all
870 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed"; 963 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed";
871 return (error == noErr && is_running); 964 return (error == noErr && is_running);
872 } 965 }
873 966
874 void AUAudioInputStream::HandleError(OSStatus err) { 967 void AUAudioInputStream::HandleError(OSStatus err) {
875 // Log the latest OSStatus error message and also change the sign of the 968 // 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 969 // error if no callbacks are active. I.e., the sign of the error message
877 // carries one extra level of information. 970 // carries one extra level of information.
878 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac", 971 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac",
879 GetInputCallbackIsActive() ? err : (err * -1)); 972 GetInputCallbackIsActive() ? err : (err * -1));
880 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 973 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err
881 << " (" << err << ")"; 974 << ")";
882 if (sink_) 975 if (sink_)
883 sink_->OnError(this); 976 sink_->OnError(this);
884 } 977 }
885 978
886 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { 979 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
887 Boolean is_settable = false; 980 Boolean is_settable = false;
888 AudioObjectPropertyAddress property_address = { 981 AudioObjectPropertyAddress property_address = {
889 kAudioDevicePropertyVolumeScalar, 982 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
890 kAudioDevicePropertyScopeInput, 983 static_cast<UInt32>(channel)};
891 static_cast<UInt32>(channel) 984 OSStatus result = AudioObjectIsPropertySettable(
892 }; 985 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; 986 return (result == noErr) ? is_settable : false;
897 } 987 }
898 988
899 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) { 989 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) {
900 base::subtle::Release_Store(&input_callback_is_active_, enabled); 990 base::subtle::Release_Store(&input_callback_is_active_, enabled);
901 } 991 }
902 992
903 bool AUAudioInputStream::GetInputCallbackIsActive() { 993 bool AUAudioInputStream::GetInputCallbackIsActive() {
904 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); 994 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false);
905 } 995 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", 1033 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac",
944 start_was_deferred_); 1034 start_was_deferred_);
945 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", 1035 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac",
946 buffer_size_was_changed_); 1036 buffer_size_was_changed_);
947 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", 1037 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac",
948 manager_->output_streams()); 1038 manager_->output_streams());
949 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", 1039 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac",
950 manager_->low_latency_input_streams()); 1040 manager_->low_latency_input_streams());
951 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac", 1041 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac",
952 manager_->basic_input_streams()); 1042 manager_->basic_input_streams());
953 // |number_of_frames_| is set at construction and corresponds to the requested 1043 // |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 1044 // 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 1045 // 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_|. 1046 // native I/O buffer size given by |io_buffer_frame_size_|.
957 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac", 1047 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac",
958 number_of_frames_); 1048 number_of_frames_);
959 DVLOG(1) << "number_of_frames_: " << number_of_frames_; 1049 DVLOG(1) << "number_of_frames_: " << number_of_frames_;
960 // This value indicates the number of frames in the IO buffers connected to 1050 // 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() 1051 // 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 1052 // 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 1053 // 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. 1054 // same device and any of these streams have asked for a smaller buffer size.
965 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", 1055 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac",
966 io_buffer_frame_size_); 1056 io_buffer_frame_size_);
967 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; 1057 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_;
968 // TODO(henrika): this value will currently always report true. It should be 1058 // TODO(henrika): this value will currently always report true. It should
969 // fixed when we understand the problem better. 1059 // be fixed when we understand the problem better.
970 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", 1060 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac",
971 GetAutomaticGainControl()); 1061 GetAutomaticGainControl());
1062 // Check if any device property changes are added by filtering out a selected
1063 // set of the |device_property_changes_map_| map. Add UMA stats if valuable
1064 // data is found.
1065 AddDevicePropertyChangesToUMA(
1066 "Media.Audio.InputDevicePropertyChangedStartupFailedMac");
1067 }
1068
1069 void AUAudioInputStream::AddDevicePropertyChangesToUMA(
1070 const std::string& name) {
1071 DVLOG(1) << "AddDevicePropertyChangesToUMA";
1072 base::AutoLock auto_lock(lock_);
1073 // Scan the map of all available property changes (notification types) and
1074 // filter out some that make sense to add to UMA stats.
1075 // TODO(henrika): figure out if the set of stats is sufficient or not.
1076 for (auto it = device_property_changes_map_.begin();
1077 it != device_property_changes_map_.end(); ++it) {
1078 UInt32 device_property = it->first;
1079 int change_count = it->second;
1080 AudioDevicePropertyResult uma_result = PROPERTY_NOT_SPECIFIED;
1081 switch (device_property) {
1082 case kAudioDevicePropertyDeviceHasChanged:
1083 uma_result = PROPERTY_DEVICE_HAS_CHANGED;
1084 DVLOG(1) << "kAudioDevicePropertyDeviceHasChanged";
1085 break;
1086 case kAudioDevicePropertyIOStoppedAbnormally:
1087 uma_result = PROPERTY_IO_STOPPED_ABNORMALLY;
1088 DVLOG(1) << "kAudioDevicePropertyIOStoppedAbnormally";
1089 break;
1090 case kAudioDevicePropertyHogMode:
1091 uma_result = PROPERTY_HOG_MODE;
1092 DVLOG(1) << "kAudioDevicePropertyHogMode";
1093 break;
1094 case kAudioDevicePropertyBufferFrameSize:
1095 uma_result = PROPERTY_BUFFER_FRAME_SIZE;
1096 DVLOG(1) << "kAudioDevicePropertyBufferFrameSize";
1097 break;
1098 case kAudioDevicePropertyBufferFrameSizeRange:
1099 uma_result = PROPERTY_BUFFER_FRAME_SIZE_RANGE;
1100 DVLOG(1) << "kAudioDevicePropertyBufferFrameSizeRange";
1101 break;
1102 case kAudioDevicePropertyStreamConfiguration:
1103 uma_result = PROPERTY_STREAM_CONFIGURATION;
1104 DVLOG(1) << "kAudioDevicePropertyStreamConfiguration";
1105 break;
1106 case kAudioDevicePropertyActualSampleRate:
1107 uma_result = PROPERTY_ACTUAL_SAMPLE_RATE;
1108 DVLOG(1) << "kAudioDevicePropertyActualSampleRate";
1109 break;
1110 case kAudioDevicePropertyNominalSampleRate:
1111 uma_result = PROPERTY_NOMINAL_SAMPLE_RATE;
1112 DVLOG(1) << "kAudioDevicePropertyNominalSampleRate";
1113 break;
1114 case kAudioDevicePropertyDeviceIsRunningSomewhere:
1115 uma_result = PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE;
1116 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunningSomewhere";
1117 break;
1118 case kAudioDevicePropertyDeviceIsRunning:
1119 uma_result = PROPERTY_DEVICE_IS_RUNNING;
1120 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunning";
1121 break;
1122 case kAudioDevicePropertyDeviceIsAlive:
1123 uma_result = PROPERTY_DEVICE_IS_ALIVE;
1124 DVLOG(1) << "kAudioDevicePropertyDeviceIsAlive";
1125 break;
1126 case kAudioStreamPropertyPhysicalFormat:
1127 uma_result = PROPERTY_STREAM_PHYSICAL_FORMAT;
1128 DVLOG(1) << "kAudioStreamPropertyPhysicalFormat";
1129 break;
1130 default:
1131 uma_result = PROPERTY_NOT_SPECIFIED;
1132 DVLOG(1) << "Property change is ignored";
1133 break;
1134 }
1135 DVLOG(1) << "property: " << device_property << " ("
1136 << FourCharFormatCodeToString(device_property) << ")"
1137 << " changed: " << change_count;
1138 LogDevicePropertyChange(name, uma_result);
1139 }
1140 device_property_changes_map_.clear();
tommi (sloooow) - chröme 2016/02/22 14:16:43 if it turns out we really need the lock, what abou
henrika (OOO until Aug 14) 2016/02/22 15:09:58 Thanks for the idea. Let me see if I can remove th
972 } 1141 }
973 1142
974 } // namespace media 1143 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_low_latency_input_mac.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698