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

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

Powered by Google App Engine
This is Rietveld 408576698