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

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: nit 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_OTHER = 0, // Use for all non-supported property changes
79 PROPERTY_DEVICE_HAS_CHANGED = 1,
80 PROPERTY_IO_STOPPED_ABNORMALLY = 2,
81 PROPERTY_HOG_MODE = 3,
82 PROPERTY_BUFFER_FRAME_SIZE = 4,
83 PROPERTY_BUFFER_FRAME_SIZE_RANGE = 5,
84 PROPERTY_STREAM_CONFIGURATION = 6,
85 PROPERTY_ACTUAL_SAMPLE_RATE = 7,
86 PROPERTY_NOMINAL_SAMPLE_RATE = 8,
87 PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE = 9,
88 PROPERTY_DEVICE_IS_RUNNING = 10,
89 PROPERTY_DEVICE_IS_ALIVE = 11,
90 PROPERTY_STREAM_PHYSICAL_FORMAT = 12,
91 PROPERTY_MAX = PROPERTY_STREAM_PHYSICAL_FORMAT
92 };
93
94 // Add the provided value in |result| to a UMA histogram.
95 static void LogDevicePropertyChange(bool startup_failed,
96 AudioDevicePropertyResult result) {
97 if (startup_failed) {
98 UMA_HISTOGRAM_ENUMERATION(
99 "Media.Audio.InputDevicePropertyChangedStartupFailedMac", result,
100 PROPERTY_MAX + 1);
101 } else {
102 UMA_HISTOGRAM_ENUMERATION("Media.Audio.InputDevicePropertyChangedMac",
103 result, PROPERTY_MAX + 1);
104 }
105 }
106
61 static OSStatus GetInputDeviceStreamFormat( 107 static OSStatus GetInputDeviceStreamFormat(
62 AudioUnit audio_unit, 108 AudioUnit audio_unit,
63 AudioStreamBasicDescription* format) { 109 AudioStreamBasicDescription* format) {
64 DCHECK(audio_unit); 110 DCHECK(audio_unit);
65 UInt32 property_size = sizeof(*format); 111 UInt32 property_size = sizeof(*format);
66 // Get the audio stream data format on the input scope of the input element 112 // Get the audio stream data format on the input scope of the input element
67 // since it is connected to the current input device. 113 // since it is connected to the current input device.
68 OSStatus result = 114 OSStatus result =
69 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, 115 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat,
70 kAudioUnitScope_Input, 1, format, &property_size); 116 kAudioUnitScope_Input, 1, format, &property_size);
(...skipping 15 matching lines...) Expand all
86 audio_unit_(0), 132 audio_unit_(0),
87 input_device_id_(audio_device_id), 133 input_device_id_(audio_device_id),
88 hardware_latency_frames_(0), 134 hardware_latency_frames_(0),
89 number_of_channels_in_frame_(0), 135 number_of_channels_in_frame_(0),
90 fifo_(input_params.channels(), 136 fifo_(input_params.channels(),
91 number_of_frames_, 137 number_of_frames_,
92 kNumberOfBlocksBufferInFifo), 138 kNumberOfBlocksBufferInFifo),
93 input_callback_is_active_(false), 139 input_callback_is_active_(false),
94 start_was_deferred_(false), 140 start_was_deferred_(false),
95 buffer_size_was_changed_(false), 141 buffer_size_was_changed_(false),
96 audio_unit_render_has_worked_(false) { 142 audio_unit_render_has_worked_(false),
143 device_listener_is_active_(false) {
97 DCHECK(manager_); 144 DCHECK(manager_);
98 145
99 // Set up the desired (output) format specified by the client. 146 // Set up the desired (output) format specified by the client.
100 format_.mSampleRate = input_params.sample_rate(); 147 format_.mSampleRate = input_params.sample_rate();
101 format_.mFormatID = kAudioFormatLinearPCM; 148 format_.mFormatID = kAudioFormatLinearPCM;
102 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 149 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
103 kLinearPCMFormatFlagIsSignedInteger; 150 kLinearPCMFormatFlagIsSignedInteger;
104 DCHECK(FormatIsInterleaved(format_.mFormatFlags)); 151 DCHECK(FormatIsInterleaved(format_.mFormatFlags));
105 format_.mBitsPerChannel = input_params.bits_per_sample(); 152 format_.mBitsPerChannel = input_params.bits_per_sample();
106 format_.mChannelsPerFrame = input_params.channels(); 153 format_.mChannelsPerFrame = input_params.channels();
(...skipping 21 matching lines...) Expand all
128 audio_buffer_list_.mNumberBuffers = 1; 175 audio_buffer_list_.mNumberBuffers = 1;
129 176
130 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; 177 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
131 audio_buffer->mNumberChannels = input_params.channels(); 178 audio_buffer->mNumberChannels = input_params.channels();
132 audio_buffer->mDataByteSize = data_byte_size; 179 audio_buffer->mDataByteSize = data_byte_size;
133 audio_buffer->mData = audio_data_buffer_.get(); 180 audio_buffer->mData = audio_data_buffer_.get();
134 } 181 }
135 182
136 AUAudioInputStream::~AUAudioInputStream() { 183 AUAudioInputStream::~AUAudioInputStream() {
137 DVLOG(1) << "~dtor"; 184 DVLOG(1) << "~dtor";
185 DCHECK(!device_listener_is_active_);
138 } 186 }
139 187
140 // Obtain and open the AUHAL AudioOutputUnit for recording. 188 // Obtain and open the AUHAL AudioOutputUnit for recording.
141 bool AUAudioInputStream::Open() { 189 bool AUAudioInputStream::Open() {
142 DCHECK(thread_checker_.CalledOnValidThread()); 190 DCHECK(thread_checker_.CalledOnValidThread());
143 DVLOG(1) << "Open"; 191 DVLOG(1) << "Open";
144 DCHECK(!audio_unit_); 192 DCHECK(!audio_unit_);
145 193
146 // Verify that we have a valid device. Send appropriate error code to 194 // 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. 195 // HandleError() to ensure that the error type is added to UMA stats.
148 if (input_device_id_ == kAudioObjectUnknown) { 196 if (input_device_id_ == kAudioObjectUnknown) {
149 NOTREACHED() << "Device ID is unknown"; 197 NOTREACHED() << "Device ID is unknown";
150 HandleError(kAudioUnitErr_InvalidElement); 198 HandleError(kAudioUnitErr_InvalidElement);
151 return false; 199 return false;
152 } 200 }
153 201
202 // Start listening for changes in device properties.
203 RegisterDeviceChangeListener();
204
154 // The requested sample-rate must match the hardware sample-rate. 205 // The requested sample-rate must match the hardware sample-rate.
155 int sample_rate = 206 int sample_rate =
156 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_); 207 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_);
157 DCHECK_EQ(sample_rate, format_.mSampleRate); 208 DCHECK_EQ(sample_rate, format_.mSampleRate);
158 209
159 // Start by obtaining an AudioOuputUnit using an AUHAL component description. 210 // Start by obtaining an AudioOuputUnit using an AUHAL component description.
160 211
161 // Description for the Audio Unit we want to use (AUHAL in this case). 212 // Description for the Audio Unit we want to use (AUHAL in this case).
162 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device. 213 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device.
163 // The user specifies which audio device to track. The audio unit can do 214 // 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 } 471 }
421 472
422 void AUAudioInputStream::Close() { 473 void AUAudioInputStream::Close() {
423 DCHECK(thread_checker_.CalledOnValidThread()); 474 DCHECK(thread_checker_.CalledOnValidThread());
424 DVLOG(1) << "Close"; 475 DVLOG(1) << "Close";
425 // It is valid to call Close() before calling open or Start(). 476 // It is valid to call Close() before calling open or Start().
426 // It is also valid to call Close() after Start() has been called. 477 // It is also valid to call Close() after Start() has been called.
427 if (IsRunning()) { 478 if (IsRunning()) {
428 Stop(); 479 Stop();
429 } 480 }
481 // Uninitialize and dispose the audio unit.
430 CloseAudioUnit(); 482 CloseAudioUnit();
483 // Disable the listener for device property changes.
484 DeRegisterDeviceChangeListener();
485 // Check if any device property changes are added by filtering out a selected
486 // set of the |device_property_changes_map_| map. Add UMA stats if valuable
487 // data is found.
488 AddDevicePropertyChangesToUMA(false);
431 // Inform the audio manager that we have been closed. This will cause our 489 // Inform the audio manager that we have been closed. This will cause our
432 // destruction. 490 // destruction.
433 manager_->ReleaseInputStream(this); 491 manager_->ReleaseInputStream(this);
434 } 492 }
435 493
436 double AUAudioInputStream::GetMaxVolume() { 494 double AUAudioInputStream::GetMaxVolume() {
437 // Verify that we have a valid device. 495 // Verify that we have a valid device.
438 if (input_device_id_ == kAudioObjectUnknown) { 496 if (input_device_id_ == kAudioObjectUnknown) {
439 NOTREACHED() << "Device ID is unknown"; 497 NOTREACHED() << "Device ID is unknown";
440 return 0.0; 498 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_)); 801 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_));
744 802
745 // Compensate the audio delay caused by the FIFO. 803 // Compensate the audio delay caused by the FIFO.
746 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; 804 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame;
747 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); 805 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume);
748 } 806 }
749 807
750 return noErr; 808 return noErr;
751 } 809 }
752 810
811 OSStatus AUAudioInputStream::OnDevicePropertyChanged(
812 AudioObjectID object_id,
813 UInt32 num_addresses,
814 const AudioObjectPropertyAddress addresses[],
815 void* context) {
816 AUAudioInputStream* self = static_cast<AUAudioInputStream*>(context);
817 return self->DevicePropertyChanged(object_id, num_addresses, addresses);
818 }
819
820 OSStatus AUAudioInputStream::DevicePropertyChanged(
tommi (sloooow) - chröme 2016/02/23 16:24:59 can we add a thread checker that we detach before
henrika (OOO until Aug 14) 2016/02/24 09:49:45 Thanks but I can't since it will not happen on the
821 AudioObjectID object_id,
822 UInt32 num_addresses,
823 const AudioObjectPropertyAddress addresses[]) {
824 if (object_id != input_device_id_)
825 return noErr;
826
827 // Listeners will be called when possibly many properties have changed.
828 // Consequently, the implementation of a listener must go through the array of
829 // addresses to see what exactly has changed.
830 for (UInt32 i = 0; i < num_addresses; ++i) {
831 const UInt32 property = addresses[i].mSelector;
832 // Use selector as key to a map and increase its value. We are not
833 // interested in all property changes but store all here anyhow.
834 // Filtering will be done later in AddDevicePropertyChangesToUMA();
835 ++device_property_changes_map_[property];
836 }
837 return noErr;
838 }
839
840 void AUAudioInputStream::RegisterDeviceChangeListener() {
841 DCHECK(thread_checker_.CalledOnValidThread());
842 DCHECK(!device_listener_is_active_);
843 DVLOG(1) << "RegisterDeviceChangeListener";
844 if (input_device_id_ == kAudioObjectUnknown)
845 return;
846 device_property_changes_map_.clear();
847 OSStatus result = AudioObjectAddPropertyListener(
848 input_device_id_, &kDeviceChangePropertyAddress,
849 &AUAudioInputStream::OnDevicePropertyChanged, this);
850 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
851 << "AudioObjectAddPropertyListener() failed!";
852 device_listener_is_active_ = true;
tommi (sloooow) - chröme 2016/02/23 16:24:59 should this be: device_listener_is_active_ = (res
henrika (OOO until Aug 14) 2016/02/24 09:49:46 Done.
853 }
854
855 void AUAudioInputStream::DeRegisterDeviceChangeListener() {
856 DCHECK(thread_checker_.CalledOnValidThread());
857 if (!device_listener_is_active_)
858 return;
859 DVLOG(1) << "DeRegisterDeviceChangeListener";
860 if (input_device_id_ == kAudioObjectUnknown)
861 return;
862 device_listener_is_active_ = false;
863 OSStatus result = AudioObjectRemovePropertyListener(
864 input_device_id_, &kDeviceChangePropertyAddress,
865 &AUAudioInputStream::OnDevicePropertyChanged, this);
866 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
867 << "AudioObjectRemovePropertyListener() failed!";
868 }
869
753 int AUAudioInputStream::HardwareSampleRate() { 870 int AUAudioInputStream::HardwareSampleRate() {
754 // Determine the default input device's sample-rate. 871 // Determine the default input device's sample-rate.
755 AudioDeviceID device_id = kAudioObjectUnknown; 872 AudioDeviceID device_id = kAudioObjectUnknown;
756 UInt32 info_size = sizeof(device_id); 873 UInt32 info_size = sizeof(device_id);
757 874
758 AudioObjectPropertyAddress default_input_device_address = { 875 AudioObjectPropertyAddress default_input_device_address = {
759 kAudioHardwarePropertyDefaultInputDevice, 876 kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
760 kAudioObjectPropertyScopeGlobal, 877 kAudioObjectPropertyElementMaster};
761 kAudioObjectPropertyElementMaster
762 };
763 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 878 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
764 &default_input_device_address, 879 &default_input_device_address, 0,
765 0, 880 0, &info_size, &device_id);
766 0,
767 &info_size,
768 &device_id);
769 if (result != noErr) 881 if (result != noErr)
770 return 0.0; 882 return 0.0;
771 883
772 Float64 nominal_sample_rate; 884 Float64 nominal_sample_rate;
773 info_size = sizeof(nominal_sample_rate); 885 info_size = sizeof(nominal_sample_rate);
774 886
775 AudioObjectPropertyAddress nominal_sample_rate_address = { 887 AudioObjectPropertyAddress nominal_sample_rate_address = {
776 kAudioDevicePropertyNominalSampleRate, 888 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
777 kAudioObjectPropertyScopeGlobal, 889 kAudioObjectPropertyElementMaster};
778 kAudioObjectPropertyElementMaster 890 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address,
779 }; 891 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) 892 if (result != noErr)
787 return 0.0; 893 return 0.0;
788 894
789 return static_cast<int>(nominal_sample_rate); 895 return static_cast<int>(nominal_sample_rate);
790 } 896 }
791 897
792 double AUAudioInputStream::GetHardwareLatency() { 898 double AUAudioInputStream::GetHardwareLatency() {
793 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { 899 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
794 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; 900 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
795 return 0.0; 901 return 0.0;
796 } 902 }
797 903
798 // Get audio unit latency. 904 // Get audio unit latency.
799 Float64 audio_unit_latency_sec = 0.0; 905 Float64 audio_unit_latency_sec = 0.0;
800 UInt32 size = sizeof(audio_unit_latency_sec); 906 UInt32 size = sizeof(audio_unit_latency_sec);
801 OSStatus result = AudioUnitGetProperty(audio_unit_, 907 OSStatus result = AudioUnitGetProperty(
802 kAudioUnitProperty_Latency, 908 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,
803 kAudioUnitScope_Global, 909 &audio_unit_latency_sec, &size);
804 0,
805 &audio_unit_latency_sec,
806 &size);
807 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) 910 OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
808 << "Could not get audio unit latency"; 911 << "Could not get audio unit latency";
809 912
810 // Get input audio device latency. 913 // Get input audio device latency.
811 AudioObjectPropertyAddress property_address = { 914 AudioObjectPropertyAddress property_address = {
812 kAudioDevicePropertyLatency, 915 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput,
813 kAudioDevicePropertyScopeInput, 916 kAudioObjectPropertyElementMaster};
814 kAudioObjectPropertyElementMaster
815 };
816 UInt32 device_latency_frames = 0; 917 UInt32 device_latency_frames = 0;
817 size = sizeof(device_latency_frames); 918 size = sizeof(device_latency_frames);
818 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, 919 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
819 nullptr, &size, &device_latency_frames); 920 nullptr, &size, &device_latency_frames);
820 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; 921 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
821 922
822 return static_cast<double>((audio_unit_latency_sec * 923 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) +
823 format_.mSampleRate) + device_latency_frames); 924 device_latency_frames);
824 } 925 }
825 926
826 double AUAudioInputStream::GetCaptureLatency( 927 double AUAudioInputStream::GetCaptureLatency(
827 const AudioTimeStamp* input_time_stamp) { 928 const AudioTimeStamp* input_time_stamp) {
828 // Get the delay between between the actual recording instant and the time 929 // Get the delay between between the actual recording instant and the time
829 // when the data packet is provided as a callback. 930 // when the data packet is provided as a callback.
830 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( 931 UInt64 capture_time_ns =
831 input_time_stamp->mHostTime); 932 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime);
832 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 933 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
833 double delay_frames = static_cast<double> 934 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) *
834 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 935 format_.mSampleRate);
835 936
836 // Total latency is composed by the dynamic latency and the fixed 937 // Total latency is composed by the dynamic latency and the fixed
837 // hardware latency. 938 // hardware latency.
838 return (delay_frames + hardware_latency_frames_); 939 return (delay_frames + hardware_latency_frames_);
839 } 940 }
840 941
841 int AUAudioInputStream::GetNumberOfChannelsFromStream() { 942 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
842 // Get the stream format, to be able to read the number of channels. 943 // Get the stream format, to be able to read the number of channels.
843 AudioObjectPropertyAddress property_address = { 944 AudioObjectPropertyAddress property_address = {
844 kAudioDevicePropertyStreamFormat, 945 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput,
845 kAudioDevicePropertyScopeInput, 946 kAudioObjectPropertyElementMaster};
846 kAudioObjectPropertyElementMaster
847 };
848 AudioStreamBasicDescription stream_format; 947 AudioStreamBasicDescription stream_format;
849 UInt32 size = sizeof(stream_format); 948 UInt32 size = sizeof(stream_format);
850 OSStatus result = AudioObjectGetPropertyData( 949 OSStatus result = AudioObjectGetPropertyData(
851 input_device_id_, &property_address, 0, nullptr, &size, &stream_format); 950 input_device_id_, &property_address, 0, nullptr, &size, &stream_format);
852 if (result != noErr) { 951 if (result != noErr) {
853 DLOG(WARNING) << "Could not get stream format"; 952 DLOG(WARNING) << "Could not get stream format";
854 return 0; 953 return 0;
855 } 954 }
856 955
857 return static_cast<int>(stream_format.mChannelsPerFrame); 956 return static_cast<int>(stream_format.mChannelsPerFrame);
(...skipping 12 matching lines...) Expand all
870 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed"; 969 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed";
871 return (error == noErr && is_running); 970 return (error == noErr && is_running);
872 } 971 }
873 972
874 void AUAudioInputStream::HandleError(OSStatus err) { 973 void AUAudioInputStream::HandleError(OSStatus err) {
875 // Log the latest OSStatus error message and also change the sign of the 974 // 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 975 // error if no callbacks are active. I.e., the sign of the error message
877 // carries one extra level of information. 976 // carries one extra level of information.
878 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac", 977 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac",
879 GetInputCallbackIsActive() ? err : (err * -1)); 978 GetInputCallbackIsActive() ? err : (err * -1));
880 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 979 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err
881 << " (" << err << ")"; 980 << ")";
882 if (sink_) 981 if (sink_)
883 sink_->OnError(this); 982 sink_->OnError(this);
884 } 983 }
885 984
886 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { 985 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
887 Boolean is_settable = false; 986 Boolean is_settable = false;
888 AudioObjectPropertyAddress property_address = { 987 AudioObjectPropertyAddress property_address = {
889 kAudioDevicePropertyVolumeScalar, 988 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
890 kAudioDevicePropertyScopeInput, 989 static_cast<UInt32>(channel)};
891 static_cast<UInt32>(channel) 990 OSStatus result = AudioObjectIsPropertySettable(
892 }; 991 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; 992 return (result == noErr) ? is_settable : false;
897 } 993 }
898 994
899 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) { 995 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) {
900 base::subtle::Release_Store(&input_callback_is_active_, enabled); 996 base::subtle::Release_Store(&input_callback_is_active_, enabled);
901 } 997 }
902 998
903 bool AUAudioInputStream::GetInputCallbackIsActive() { 999 bool AUAudioInputStream::GetInputCallbackIsActive() {
904 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); 1000 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false);
905 } 1001 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", 1039 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac",
944 start_was_deferred_); 1040 start_was_deferred_);
945 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", 1041 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac",
946 buffer_size_was_changed_); 1042 buffer_size_was_changed_);
947 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", 1043 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac",
948 manager_->output_streams()); 1044 manager_->output_streams());
949 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", 1045 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac",
950 manager_->low_latency_input_streams()); 1046 manager_->low_latency_input_streams());
951 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac", 1047 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac",
952 manager_->basic_input_streams()); 1048 manager_->basic_input_streams());
953 // |number_of_frames_| is set at construction and corresponds to the requested 1049 // |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 1050 // 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 1051 // 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_|. 1052 // native I/O buffer size given by |io_buffer_frame_size_|.
957 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac", 1053 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac",
958 number_of_frames_); 1054 number_of_frames_);
959 DVLOG(1) << "number_of_frames_: " << number_of_frames_; 1055 DVLOG(1) << "number_of_frames_: " << number_of_frames_;
960 // This value indicates the number of frames in the IO buffers connected to 1056 // 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() 1057 // 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 1058 // 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 1059 // 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. 1060 // same device and any of these streams have asked for a smaller buffer size.
965 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", 1061 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac",
966 io_buffer_frame_size_); 1062 io_buffer_frame_size_);
967 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; 1063 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_;
968 // TODO(henrika): this value will currently always report true. It should be 1064 // TODO(henrika): this value will currently always report true. It should
969 // fixed when we understand the problem better. 1065 // be fixed when we understand the problem better.
970 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", 1066 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac",
971 GetAutomaticGainControl()); 1067 GetAutomaticGainControl());
1068 // Disable the listener for device property changes. Ensures that we don't
1069 // need a lock when reading the map.
1070 DeRegisterDeviceChangeListener();
1071 // Check if any device property changes are added by filtering out a selected
1072 // set of the |device_property_changes_map_| map. Add UMA stats if valuable
1073 // data is found.
1074 AddDevicePropertyChangesToUMA(true);
1075 }
1076
1077 void AUAudioInputStream::AddDevicePropertyChangesToUMA(bool startup_failed) {
tommi (sloooow) - chröme 2016/02/23 16:24:59 dcheck that monitoring is not active?
henrika (OOO until Aug 14) 2016/02/24 09:49:46 Good point. Thanks.
1078 DVLOG(1) << "AddDevicePropertyChangesToUMA";
1079 // Scan the map of all available property changes (notification types) and
1080 // filter out some that make sense to add to UMA stats.
1081 // TODO(henrika): figure out if the set of stats is sufficient or not.
1082 for (auto it = device_property_changes_map_.begin();
1083 it != device_property_changes_map_.end(); ++it) {
1084 UInt32 device_property = it->first;
1085 int change_count = it->second;
1086 AudioDevicePropertyResult uma_result = PROPERTY_OTHER;
1087 switch (device_property) {
1088 case kAudioDevicePropertyDeviceHasChanged:
1089 uma_result = PROPERTY_DEVICE_HAS_CHANGED;
1090 DVLOG(1) << "kAudioDevicePropertyDeviceHasChanged";
1091 break;
1092 case kAudioDevicePropertyIOStoppedAbnormally:
1093 uma_result = PROPERTY_IO_STOPPED_ABNORMALLY;
1094 DVLOG(1) << "kAudioDevicePropertyIOStoppedAbnormally";
1095 break;
1096 case kAudioDevicePropertyHogMode:
1097 uma_result = PROPERTY_HOG_MODE;
1098 DVLOG(1) << "kAudioDevicePropertyHogMode";
1099 break;
1100 case kAudioDevicePropertyBufferFrameSize:
1101 uma_result = PROPERTY_BUFFER_FRAME_SIZE;
1102 DVLOG(1) << "kAudioDevicePropertyBufferFrameSize";
1103 break;
1104 case kAudioDevicePropertyBufferFrameSizeRange:
1105 uma_result = PROPERTY_BUFFER_FRAME_SIZE_RANGE;
1106 DVLOG(1) << "kAudioDevicePropertyBufferFrameSizeRange";
1107 break;
1108 case kAudioDevicePropertyStreamConfiguration:
1109 uma_result = PROPERTY_STREAM_CONFIGURATION;
1110 DVLOG(1) << "kAudioDevicePropertyStreamConfiguration";
1111 break;
1112 case kAudioDevicePropertyActualSampleRate:
1113 uma_result = PROPERTY_ACTUAL_SAMPLE_RATE;
1114 DVLOG(1) << "kAudioDevicePropertyActualSampleRate";
1115 break;
1116 case kAudioDevicePropertyNominalSampleRate:
1117 uma_result = PROPERTY_NOMINAL_SAMPLE_RATE;
1118 DVLOG(1) << "kAudioDevicePropertyNominalSampleRate";
1119 break;
1120 case kAudioDevicePropertyDeviceIsRunningSomewhere:
1121 uma_result = PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE;
1122 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunningSomewhere";
1123 break;
1124 case kAudioDevicePropertyDeviceIsRunning:
1125 uma_result = PROPERTY_DEVICE_IS_RUNNING;
1126 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunning";
1127 break;
1128 case kAudioDevicePropertyDeviceIsAlive:
1129 uma_result = PROPERTY_DEVICE_IS_ALIVE;
1130 DVLOG(1) << "kAudioDevicePropertyDeviceIsAlive";
1131 break;
1132 case kAudioStreamPropertyPhysicalFormat:
1133 uma_result = PROPERTY_STREAM_PHYSICAL_FORMAT;
1134 DVLOG(1) << "kAudioStreamPropertyPhysicalFormat";
1135 break;
1136 default:
1137 uma_result = PROPERTY_OTHER;
1138 DVLOG(1) << "Property change is ignored";
1139 break;
1140 }
1141 DVLOG(1) << "property: " << device_property << " ("
1142 << FourCharFormatCodeToString(device_property) << ")"
1143 << " changed: " << change_count;
1144 LogDevicePropertyChange(startup_failed, uma_result);
1145 }
1146 device_property_changes_map_.clear();
972 } 1147 }
973 1148
974 } // namespace media 1149 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698