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

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: Modified when device notification is started and stopped 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') | no next file » | 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 6
7 #include <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/mac/mac_logging.h" 10 #include "base/mac/mac_logging.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 << "frames per packet : " << format.mFramesPerPacket << std::endl 51 << "frames per packet : " << format.mFramesPerPacket << std::endl
52 << "bytes per frame : " << format.mBytesPerFrame << std::endl 52 << "bytes per frame : " << format.mBytesPerFrame << std::endl
53 << "channels per frame: " << format.mChannelsPerFrame << std::endl 53 << "channels per frame: " << format.mChannelsPerFrame << std::endl
54 << "bits per channel : " << format.mBitsPerChannel << std::endl 54 << "bits per channel : " << format.mBitsPerChannel << std::endl
55 << "reserved : " << format.mReserved << std::endl 55 << "reserved : " << format.mReserved << std::endl
56 << "interleaved : " 56 << "interleaved : "
57 << (FormatIsInterleaved(format.mFormatFlags) ? "yes" : "no"); 57 << (FormatIsInterleaved(format.mFormatFlags) ? "yes" : "no");
58 return os; 58 return os;
59 } 59 }
60 60
61 // Property address to monitor device changes. Use wildcards to match any and
62 // all values for their associated type. Filtering for device-specific
63 // notifications will take place in the callback.
64 const AudioObjectPropertyAddress
65 AUAudioInputStream::kDeviceChangePropertyAddress = {
66 kAudioObjectPropertySelectorWildcard, kAudioObjectPropertyScopeWildcard,
67 kAudioObjectPropertyElementWildcard};
68
69 // TODO(henrika): add comments...
70 enum AudioDevicePropertyResult {
71 PROPERTY_DEVICE_HAS_CHANGED = 0,
72 PROPERTY_IO_STOPPED_ABNORMALLY = 1,
o1ka 2016/02/18 13:46:23 I would not assign values to any but the first one
henrika (OOO until Aug 14) 2016/02/18 15:58:03 This style is used all over Chrome in combination
o1ka 2016/02/18 16:54:30 Thank you for the info, will save me some time in
henrika (OOO until Aug 14) 2016/02/19 12:46:11 Acknowledged.
73 PROPERTY_HOG_MODE = 2,
74 PROPERTY_BUFFER_FRAME_SIZE = 3,
75 PROPERTY_BUFFER_FRAME_SIZE_RANGE = 4,
76 PROPERTY_STREAM_CONFIGURATION = 5,
77 PROPERTY_ACTUAL_SAMPLE_RATE = 6,
78 PROPERTY_NOMINAL_SAMPLE_RATE = 7,
79 PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE = 8,
80 PROPERTY_DEVICE_IS_RUNNING = 9,
81 PROPERTY_DEVICE_IS_ALIVE = 10,
82 PROPERTY_MAX = PROPERTY_DEVICE_IS_ALIVE
83 };
84
85 // TODO(henrika): add comments...
86 static void LogDevicePropertyChange(AudioDevicePropertyResult result) {
87 UMA_HISTOGRAM_ENUMERATION("Media.Audio.InputDevicePropertyChangedMac", result,
88 PROPERTY_MAX + 1);
89 }
90
61 static OSStatus GetInputDeviceStreamFormat( 91 static OSStatus GetInputDeviceStreamFormat(
62 AudioUnit audio_unit, 92 AudioUnit audio_unit,
63 AudioStreamBasicDescription* format) { 93 AudioStreamBasicDescription* format) {
64 DCHECK(audio_unit); 94 DCHECK(audio_unit);
65 UInt32 property_size = sizeof(*format); 95 UInt32 property_size = sizeof(*format);
66 // Get the audio stream data format on the input scope of the input element 96 // Get the audio stream data format on the input scope of the input element
67 // since it is connected to the current input device. 97 // since it is connected to the current input device.
68 OSStatus result = 98 OSStatus result =
69 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, 99 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat,
70 kAudioUnitScope_Input, 1, format, &property_size); 100 kAudioUnitScope_Input, 1, format, &property_size);
(...skipping 15 matching lines...) Expand all
86 audio_unit_(0), 116 audio_unit_(0),
87 input_device_id_(audio_device_id), 117 input_device_id_(audio_device_id),
88 hardware_latency_frames_(0), 118 hardware_latency_frames_(0),
89 number_of_channels_in_frame_(0), 119 number_of_channels_in_frame_(0),
90 fifo_(input_params.channels(), 120 fifo_(input_params.channels(),
91 number_of_frames_, 121 number_of_frames_,
92 kNumberOfBlocksBufferInFifo), 122 kNumberOfBlocksBufferInFifo),
93 input_callback_is_active_(false), 123 input_callback_is_active_(false),
94 start_was_deferred_(false), 124 start_was_deferred_(false),
95 buffer_size_was_changed_(false), 125 buffer_size_was_changed_(false),
96 audio_unit_render_has_worked_(false) { 126 audio_unit_render_has_worked_(false),
127 device_listener_is_active_(false) {
97 DCHECK(manager_); 128 DCHECK(manager_);
98 129
99 // Set up the desired (output) format specified by the client. 130 // Set up the desired (output) format specified by the client.
100 format_.mSampleRate = input_params.sample_rate(); 131 format_.mSampleRate = input_params.sample_rate();
101 format_.mFormatID = kAudioFormatLinearPCM; 132 format_.mFormatID = kAudioFormatLinearPCM;
102 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 133 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
103 kLinearPCMFormatFlagIsSignedInteger; 134 kLinearPCMFormatFlagIsSignedInteger;
104 DCHECK(FormatIsInterleaved(format_.mFormatFlags)); 135 DCHECK(FormatIsInterleaved(format_.mFormatFlags));
105 format_.mBitsPerChannel = input_params.bits_per_sample(); 136 format_.mBitsPerChannel = input_params.bits_per_sample();
106 format_.mChannelsPerFrame = input_params.channels(); 137 format_.mChannelsPerFrame = input_params.channels();
(...skipping 21 matching lines...) Expand all
128 audio_buffer_list_.mNumberBuffers = 1; 159 audio_buffer_list_.mNumberBuffers = 1;
129 160
130 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; 161 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
131 audio_buffer->mNumberChannels = input_params.channels(); 162 audio_buffer->mNumberChannels = input_params.channels();
132 audio_buffer->mDataByteSize = data_byte_size; 163 audio_buffer->mDataByteSize = data_byte_size;
133 audio_buffer->mData = audio_data_buffer_.get(); 164 audio_buffer->mData = audio_data_buffer_.get();
134 } 165 }
135 166
136 AUAudioInputStream::~AUAudioInputStream() { 167 AUAudioInputStream::~AUAudioInputStream() {
137 DVLOG(1) << "~dtor"; 168 DVLOG(1) << "~dtor";
169 DeRegisterDeviceChangeListener();
138 } 170 }
139 171
140 // Obtain and open the AUHAL AudioOutputUnit for recording. 172 // Obtain and open the AUHAL AudioOutputUnit for recording.
141 bool AUAudioInputStream::Open() { 173 bool AUAudioInputStream::Open() {
142 DCHECK(thread_checker_.CalledOnValidThread()); 174 DCHECK(thread_checker_.CalledOnValidThread());
143 DVLOG(1) << "Open"; 175 DVLOG(1) << "Open";
144 DCHECK(!audio_unit_); 176 DCHECK(!audio_unit_);
145 177
146 // Verify that we have a valid device. Send appropriate error code to 178 // 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. 179 // HandleError() to ensure that the error type is added to UMA stats.
148 if (input_device_id_ == kAudioObjectUnknown) { 180 if (input_device_id_ == kAudioObjectUnknown) {
149 NOTREACHED() << "Device ID is unknown"; 181 NOTREACHED() << "Device ID is unknown";
150 HandleError(kAudioUnitErr_InvalidElement); 182 HandleError(kAudioUnitErr_InvalidElement);
151 return false; 183 return false;
152 } 184 }
153 185
186 RegisterDeviceChangeListener();
187
154 // The requested sample-rate must match the hardware sample-rate. 188 // The requested sample-rate must match the hardware sample-rate.
155 int sample_rate = 189 int sample_rate =
156 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_); 190 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_);
157 DCHECK_EQ(sample_rate, format_.mSampleRate); 191 DCHECK_EQ(sample_rate, format_.mSampleRate);
158 192
159 // Start by obtaining an AudioOuputUnit using an AUHAL component description. 193 // Start by obtaining an AudioOuputUnit using an AUHAL component description.
160 194
161 // Description for the Audio Unit we want to use (AUHAL in this case). 195 // Description for the Audio Unit we want to use (AUHAL in this case).
162 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device. 196 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device.
163 // The user specifies which audio device to track. The audio unit can do 197 // The user specifies which audio device to track. The audio unit can do
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 455
422 void AUAudioInputStream::Close() { 456 void AUAudioInputStream::Close() {
423 DCHECK(thread_checker_.CalledOnValidThread()); 457 DCHECK(thread_checker_.CalledOnValidThread());
424 DVLOG(1) << "Close"; 458 DVLOG(1) << "Close";
425 // It is valid to call Close() before calling open or Start(). 459 // It is valid to call Close() before calling open or Start().
426 // It is also valid to call Close() after Start() has been called. 460 // It is also valid to call Close() after Start() has been called.
427 if (IsRunning()) { 461 if (IsRunning()) {
428 Stop(); 462 Stop();
429 } 463 }
430 CloseAudioUnit(); 464 CloseAudioUnit();
465 DeRegisterDeviceChangeListener();
431 // Inform the audio manager that we have been closed. This will cause our 466 // Inform the audio manager that we have been closed. This will cause our
432 // destruction. 467 // destruction.
433 manager_->ReleaseInputStream(this); 468 manager_->ReleaseInputStream(this);
434 } 469 }
435 470
436 double AUAudioInputStream::GetMaxVolume() { 471 double AUAudioInputStream::GetMaxVolume() {
437 // Verify that we have a valid device. 472 // Verify that we have a valid device.
438 if (input_device_id_ == kAudioObjectUnknown) { 473 if (input_device_id_ == kAudioObjectUnknown) {
439 NOTREACHED() << "Device ID is unknown"; 474 NOTREACHED() << "Device ID is unknown";
440 return 0.0; 475 return 0.0;
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 UInt32 bus_number, 640 UInt32 bus_number,
606 UInt32 number_of_frames) { 641 UInt32 number_of_frames) {
607 // Indicate that input callbacks have started on the internal AUHAL IO 642 // Indicate that input callbacks have started on the internal AUHAL IO
608 // thread. The |input_callback_is_active_| member is read from the creating 643 // thread. The |input_callback_is_active_| member is read from the creating
609 // thread when a timer fires once and set to false in Stop() on the same 644 // thread when a timer fires once and set to false in Stop() on the same
610 // thread. It means that this thread is the only writer of 645 // thread. It means that this thread is the only writer of
611 // |input_callback_is_active_| once the tread starts and it should therefore 646 // |input_callback_is_active_| once the tread starts and it should therefore
612 // be safe to modify. 647 // be safe to modify.
613 SetInputCallbackIsActive(true); 648 SetInputCallbackIsActive(true);
614 649
650 // We are only interested in device property changes in combination with
651 // failing input callbacks. Hence, might as well disable the listener now.
652 DeRegisterDeviceChangeListener();
653
615 // Update the |mDataByteSize| value in the audio_buffer_list() since 654 // Update the |mDataByteSize| value in the audio_buffer_list() since
616 // |number_of_frames| can be changed on the fly. 655 // |number_of_frames| can be changed on the fly.
617 // |mDataByteSize| needs to be exactly mapping to |number_of_frames|, 656 // |mDataByteSize| needs to be exactly mapping to |number_of_frames|,
618 // otherwise it will put CoreAudio into bad state and results in 657 // otherwise it will put CoreAudio into bad state and results in
619 // AudioUnitRender() returning -50 for the new created stream. 658 // AudioUnitRender() returning -50 for the new created stream.
620 // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and 659 // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and
621 // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes. 660 // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes.
622 // See crbug/428706 for details. 661 // See crbug/428706 for details.
623 UInt32 new_size = number_of_frames * format_.mBytesPerFrame; 662 UInt32 new_size = number_of_frames * format_.mBytesPerFrame;
624 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; 663 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); 782 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_));
744 783
745 // Compensate the audio delay caused by the FIFO. 784 // Compensate the audio delay caused by the FIFO.
746 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; 785 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame;
747 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); 786 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume);
748 } 787 }
749 788
750 return noErr; 789 return noErr;
751 } 790 }
752 791
792 OSStatus AUAudioInputStream::OnDevicePropertyChanged(
o1ka 2016/02/18 13:46:22 Can there be a race between this call and deregist
henrika (OOO until Aug 14) 2016/02/18 15:58:03 The call in the destructor is invalid (not needed)
793 AudioObjectID object_id,
794 UInt32 num_addresses,
795 const AudioObjectPropertyAddress addresses[],
796 void* context) {
797 AUAudioInputStream* self = static_cast<AUAudioInputStream*>(context);
798 return self->DevicePropertyChanged(object_id, num_addresses, addresses);
799 }
800
801 OSStatus AUAudioInputStream::DevicePropertyChanged(
802 AudioObjectID object_id,
803 UInt32 num_addresses,
804 const AudioObjectPropertyAddress addresses[]) {
805 if (object_id != input_device_id_)
806 return noErr;
807
808 // Listeners will be called when possibly many properties have changed.
o1ka 2016/02/18 13:46:22 Can the same listener be called concurrently?
henrika (OOO until Aug 14) 2016/02/18 15:58:03 The documentation does not say anything about that
809 // Consequently, the implementation of a listener must go through the array of
810 // addresses to see what exactly has changed.
811 for (UInt32 i = 0; i < num_addresses; ++i) {
812 const UInt32 property = addresses[i].mSelector;
813 switch (property) {
814 // Filter out and store certain property values provided by the
815 // AudioDevice class.
816 case kAudioDevicePropertyDeviceHasChanged:
o1ka 2016/02/18 13:46:22 I would say that having both 'switch' and map is a
henrika (OOO until Aug 14) 2016/02/18 15:58:03 Great comment, thanks. Will add all to the map and
817 case kAudioDevicePropertyIOStoppedAbnormally:
818 case kAudioDevicePropertyHogMode:
819 case kAudioDevicePropertyBufferFrameSize:
820 case kAudioDevicePropertyBufferFrameSizeRange:
821 case kAudioDevicePropertyStreamConfiguration:
822 case kAudioDevicePropertyActualSampleRate:
823 case kAudioDevicePropertyNominalSampleRate:
824 case kAudioDevicePropertyDeviceIsRunningSomewhere:
825 case kAudioDevicePropertyDeviceIsRunning:
826 case kAudioDevicePropertyDeviceIsAlive:
827 // Use selector as key to a map and increase its value.
828 device_property_changes_map_[property]++;
829 break;
830 default:
831 // TODO(henrika): figure out if more property changes should be tracked.
832 DVLOG(1) << "No action for kAudioDeviceProperty: " << property;
833 break;
834 }
835 }
836 return noErr;
837 }
838
839 void AUAudioInputStream::RegisterDeviceChangeListener() {
840 DCHECK(thread_checker_.CalledOnValidThread());
841 DVLOG(1) << "RegisterDeviceChangeListener";
842 if (input_device_id_ == kAudioObjectUnknown)
843 return;
844
845 device_property_changes_map_.clear();
846
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 SetDeviceListenerIsActive(result == noErr);
853 }
854
855 void AUAudioInputStream::DeRegisterDeviceChangeListener() {
856 if (!GetDeviceListenerIsActive())
857 return;
858 DVLOG(1) << "DeRegisterDeviceChangeListener";
859 if (input_device_id_ == kAudioObjectUnknown)
860 return;
861 OSStatus result = AudioObjectRemovePropertyListener(
o1ka 2016/02/18 13:46:23 Is it safe to call it second time if the first att
henrika (OOO until Aug 14) 2016/02/18 15:58:03 I don't know since I've never been able to make th
o1ka 2016/02/18 16:54:30 Yes, I have the same feeling. In this case, it sho
henrika (OOO until Aug 14) 2016/02/19 12:46:12 Done.
862 input_device_id_, &kDeviceChangePropertyAddress,
863 &AUAudioInputStream::OnDevicePropertyChanged, this);
864 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
865 << "AudioObjectRemovePropertyListener() failed!";
866 SetDeviceListenerIsActive(!(result == noErr));
867 }
868
753 int AUAudioInputStream::HardwareSampleRate() { 869 int AUAudioInputStream::HardwareSampleRate() {
754 // Determine the default input device's sample-rate. 870 // Determine the default input device's sample-rate.
755 AudioDeviceID device_id = kAudioObjectUnknown; 871 AudioDeviceID device_id = kAudioObjectUnknown;
756 UInt32 info_size = sizeof(device_id); 872 UInt32 info_size = sizeof(device_id);
757 873
758 AudioObjectPropertyAddress default_input_device_address = { 874 AudioObjectPropertyAddress default_input_device_address = {
759 kAudioHardwarePropertyDefaultInputDevice, 875 kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
760 kAudioObjectPropertyScopeGlobal, 876 kAudioObjectPropertyElementMaster};
761 kAudioObjectPropertyElementMaster
762 };
763 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 877 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
764 &default_input_device_address, 878 &default_input_device_address, 0,
765 0, 879 0, &info_size, &device_id);
766 0,
767 &info_size,
768 &device_id);
769 if (result != noErr) 880 if (result != noErr)
770 return 0.0; 881 return 0.0;
771 882
772 Float64 nominal_sample_rate; 883 Float64 nominal_sample_rate;
773 info_size = sizeof(nominal_sample_rate); 884 info_size = sizeof(nominal_sample_rate);
774 885
775 AudioObjectPropertyAddress nominal_sample_rate_address = { 886 AudioObjectPropertyAddress nominal_sample_rate_address = {
776 kAudioDevicePropertyNominalSampleRate, 887 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
777 kAudioObjectPropertyScopeGlobal, 888 kAudioObjectPropertyElementMaster};
778 kAudioObjectPropertyElementMaster 889 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address,
779 }; 890 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) 891 if (result != noErr)
787 return 0.0; 892 return 0.0;
788 893
789 return static_cast<int>(nominal_sample_rate); 894 return static_cast<int>(nominal_sample_rate);
790 } 895 }
791 896
792 double AUAudioInputStream::GetHardwareLatency() { 897 double AUAudioInputStream::GetHardwareLatency() {
793 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { 898 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
794 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; 899 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
795 return 0.0; 900 return 0.0;
796 } 901 }
797 902
798 // Get audio unit latency. 903 // Get audio unit latency.
799 Float64 audio_unit_latency_sec = 0.0; 904 Float64 audio_unit_latency_sec = 0.0;
800 UInt32 size = sizeof(audio_unit_latency_sec); 905 UInt32 size = sizeof(audio_unit_latency_sec);
801 OSStatus result = AudioUnitGetProperty(audio_unit_, 906 OSStatus result = AudioUnitGetProperty(
802 kAudioUnitProperty_Latency, 907 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,
803 kAudioUnitScope_Global, 908 &audio_unit_latency_sec, &size);
804 0,
805 &audio_unit_latency_sec,
806 &size);
807 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) 909 OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
808 << "Could not get audio unit latency"; 910 << "Could not get audio unit latency";
809 911
810 // Get input audio device latency. 912 // Get input audio device latency.
811 AudioObjectPropertyAddress property_address = { 913 AudioObjectPropertyAddress property_address = {
812 kAudioDevicePropertyLatency, 914 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput,
813 kAudioDevicePropertyScopeInput, 915 kAudioObjectPropertyElementMaster};
814 kAudioObjectPropertyElementMaster
815 };
816 UInt32 device_latency_frames = 0; 916 UInt32 device_latency_frames = 0;
817 size = sizeof(device_latency_frames); 917 size = sizeof(device_latency_frames);
818 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, 918 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
819 nullptr, &size, &device_latency_frames); 919 nullptr, &size, &device_latency_frames);
820 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; 920 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
821 921
822 return static_cast<double>((audio_unit_latency_sec * 922 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) +
823 format_.mSampleRate) + device_latency_frames); 923 device_latency_frames);
824 } 924 }
825 925
826 double AUAudioInputStream::GetCaptureLatency( 926 double AUAudioInputStream::GetCaptureLatency(
827 const AudioTimeStamp* input_time_stamp) { 927 const AudioTimeStamp* input_time_stamp) {
828 // Get the delay between between the actual recording instant and the time 928 // Get the delay between between the actual recording instant and the time
829 // when the data packet is provided as a callback. 929 // when the data packet is provided as a callback.
830 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( 930 UInt64 capture_time_ns =
831 input_time_stamp->mHostTime); 931 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime);
832 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 932 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
833 double delay_frames = static_cast<double> 933 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) *
834 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 934 format_.mSampleRate);
835 935
836 // Total latency is composed by the dynamic latency and the fixed 936 // Total latency is composed by the dynamic latency and the fixed
837 // hardware latency. 937 // hardware latency.
838 return (delay_frames + hardware_latency_frames_); 938 return (delay_frames + hardware_latency_frames_);
839 } 939 }
840 940
841 int AUAudioInputStream::GetNumberOfChannelsFromStream() { 941 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
842 // Get the stream format, to be able to read the number of channels. 942 // Get the stream format, to be able to read the number of channels.
843 AudioObjectPropertyAddress property_address = { 943 AudioObjectPropertyAddress property_address = {
844 kAudioDevicePropertyStreamFormat, 944 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput,
845 kAudioDevicePropertyScopeInput, 945 kAudioObjectPropertyElementMaster};
846 kAudioObjectPropertyElementMaster
847 };
848 AudioStreamBasicDescription stream_format; 946 AudioStreamBasicDescription stream_format;
849 UInt32 size = sizeof(stream_format); 947 UInt32 size = sizeof(stream_format);
850 OSStatus result = AudioObjectGetPropertyData( 948 OSStatus result = AudioObjectGetPropertyData(
851 input_device_id_, &property_address, 0, nullptr, &size, &stream_format); 949 input_device_id_, &property_address, 0, nullptr, &size, &stream_format);
852 if (result != noErr) { 950 if (result != noErr) {
853 DLOG(WARNING) << "Could not get stream format"; 951 DLOG(WARNING) << "Could not get stream format";
854 return 0; 952 return 0;
855 } 953 }
856 954
857 return static_cast<int>(stream_format.mChannelsPerFrame); 955 return static_cast<int>(stream_format.mChannelsPerFrame);
(...skipping 12 matching lines...) Expand all
870 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed"; 968 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed";
871 return (error == noErr && is_running); 969 return (error == noErr && is_running);
872 } 970 }
873 971
874 void AUAudioInputStream::HandleError(OSStatus err) { 972 void AUAudioInputStream::HandleError(OSStatus err) {
875 // Log the latest OSStatus error message and also change the sign of the 973 // 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 974 // error if no callbacks are active. I.e., the sign of the error message
877 // carries one extra level of information. 975 // carries one extra level of information.
878 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac", 976 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac",
879 GetInputCallbackIsActive() ? err : (err * -1)); 977 GetInputCallbackIsActive() ? err : (err * -1));
880 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 978 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err
881 << " (" << err << ")"; 979 << ")";
882 if (sink_) 980 if (sink_)
883 sink_->OnError(this); 981 sink_->OnError(this);
884 } 982 }
885 983
886 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { 984 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
887 Boolean is_settable = false; 985 Boolean is_settable = false;
888 AudioObjectPropertyAddress property_address = { 986 AudioObjectPropertyAddress property_address = {
889 kAudioDevicePropertyVolumeScalar, 987 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
890 kAudioDevicePropertyScopeInput, 988 static_cast<UInt32>(channel)};
891 static_cast<UInt32>(channel) 989 OSStatus result = AudioObjectIsPropertySettable(
892 }; 990 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; 991 return (result == noErr) ? is_settable : false;
897 } 992 }
898 993
899 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) { 994 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) {
900 base::subtle::Release_Store(&input_callback_is_active_, enabled); 995 base::subtle::Release_Store(&input_callback_is_active_, enabled);
901 } 996 }
902 997
903 bool AUAudioInputStream::GetInputCallbackIsActive() { 998 bool AUAudioInputStream::GetInputCallbackIsActive() {
904 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); 999 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false);
905 } 1000 }
906 1001
1002 void AUAudioInputStream::SetDeviceListenerIsActive(bool enabled) {
1003 base::subtle::Release_Store(&device_listener_is_active_, enabled);
1004 }
1005
1006 bool AUAudioInputStream::GetDeviceListenerIsActive() {
1007 return (base::subtle::Acquire_Load(&device_listener_is_active_) != false);
1008 }
1009
907 void AUAudioInputStream::CheckInputStartupSuccess() { 1010 void AUAudioInputStream::CheckInputStartupSuccess() {
908 DCHECK(thread_checker_.CalledOnValidThread()); 1011 DCHECK(thread_checker_.CalledOnValidThread());
1012 // Remove the observer for changes in device properties. The notifier is
1013 // currently only used to track down events that might lead to failure in
1014 // starting input audio. Don't keep the observer alive longer than needed.
1015 DeRegisterDeviceChangeListener();
909 // Only add UMA stat related to failing input audio for streams where 1016 // Only add UMA stat related to failing input audio for streams where
910 // the AGC has been enabled, e.g. WebRTC audio input streams. 1017 // the AGC has been enabled, e.g. WebRTC audio input streams.
911 if (IsRunning() && GetAutomaticGainControl()) { 1018 if (IsRunning() && GetAutomaticGainControl()) {
912 // Check if we have called Start() and input callbacks have actually 1019 // Check if we have called Start() and input callbacks have actually
913 // started in time as they should. If that is not the case, we have a 1020 // started in time as they should. If that is not the case, we have a
914 // problem and the stream is considered dead. 1021 // problem and the stream is considered dead.
915 const bool input_callback_is_active = GetInputCallbackIsActive(); 1022 const bool input_callback_is_active = GetInputCallbackIsActive();
916 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartupSuccessMac", 1023 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartupSuccessMac",
917 input_callback_is_active); 1024 input_callback_is_active);
918 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active; 1025 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active;
(...skipping 24 matching lines...) Expand all
943 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", 1050 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac",
944 start_was_deferred_); 1051 start_was_deferred_);
945 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", 1052 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac",
946 buffer_size_was_changed_); 1053 buffer_size_was_changed_);
947 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", 1054 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac",
948 manager_->output_streams()); 1055 manager_->output_streams());
949 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", 1056 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac",
950 manager_->low_latency_input_streams()); 1057 manager_->low_latency_input_streams());
951 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac", 1058 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac",
952 manager_->basic_input_streams()); 1059 manager_->basic_input_streams());
953 // |number_of_frames_| is set at construction and corresponds to the requested 1060 // |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 1061 // 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 1062 // 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_|. 1063 // native I/O buffer size given by |io_buffer_frame_size_|.
957 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac", 1064 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac",
958 number_of_frames_); 1065 number_of_frames_);
959 DVLOG(1) << "number_of_frames_: " << number_of_frames_; 1066 DVLOG(1) << "number_of_frames_: " << number_of_frames_;
960 // This value indicates the number of frames in the IO buffers connected to 1067 // 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() 1068 // 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 1069 // 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 1070 // 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. 1071 // same device and any of these streams have asked for a smaller buffer size.
965 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", 1072 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac",
966 io_buffer_frame_size_); 1073 io_buffer_frame_size_);
967 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; 1074 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_;
968 // TODO(henrika): this value will currently always report true. It should be 1075 // TODO(henrika): this value will currently always report true. It should
1076 // be
969 // fixed when we understand the problem better. 1077 // fixed when we understand the problem better.
970 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", 1078 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac",
971 GetAutomaticGainControl()); 1079 GetAutomaticGainControl());
1080 // TODO(henrika): add comments...
1081 AddDevicePropertyChangesToUMA();
1082 }
1083
1084 void AUAudioInputStream::AddDevicePropertyChangesToUMA() {
1085 DVLOG(1) << "AddDevicePropertyChangesToUMA";
1086 while (!device_property_changes_map_.empty()) {
o1ka 2016/02/18 13:46:22 You could just iterate through the map from the be
henrika (OOO until Aug 14) 2016/02/18 15:58:03 Thanks. Will change.
1087 UInt32 device_property = device_property_changes_map_.begin()->first;
1088 int change_count = device_property_changes_map_.begin()->second;
1089 DVLOG(1) << "property: " << device_property << " changed: " << change_count;
1090 AudioDevicePropertyResult uma_result = PROPERTY_MAX;
1091 switch (device_property) {
1092 case kAudioDevicePropertyDeviceHasChanged:
1093 uma_result = PROPERTY_DEVICE_HAS_CHANGED;
1094 DVLOG(1) << "kAudioDevicePropertyDeviceHasChanged";
1095 break;
1096 case kAudioDevicePropertyIOStoppedAbnormally:
1097 uma_result = PROPERTY_IO_STOPPED_ABNORMALLY;
1098 DVLOG(1) << "kAudioDevicePropertyIOStoppedAbnormally";
1099 break;
1100 case kAudioDevicePropertyHogMode:
1101 uma_result = PROPERTY_HOG_MODE;
1102 DVLOG(1) << "kAudioDevicePropertyHogMode";
1103 break;
1104 case kAudioDevicePropertyBufferFrameSize:
1105 uma_result = PROPERTY_BUFFER_FRAME_SIZE;
1106 DVLOG(1) << "kAudioDevicePropertyBufferFrameSize";
1107 break;
1108 case kAudioDevicePropertyBufferFrameSizeRange:
1109 uma_result = PROPERTY_BUFFER_FRAME_SIZE_RANGE;
1110 DVLOG(1) << "kAudioDevicePropertyBufferFrameSizeRange";
1111 break;
1112 case kAudioDevicePropertyStreamConfiguration:
1113 uma_result = PROPERTY_STREAM_CONFIGURATION;
1114 DVLOG(1) << "kAudioDevicePropertyStreamConfiguration";
1115 break;
1116 case kAudioDevicePropertyActualSampleRate:
1117 uma_result = PROPERTY_ACTUAL_SAMPLE_RATE;
1118 DVLOG(1) << "kAudioDevicePropertyActualSampleRate";
1119 break;
1120 case kAudioDevicePropertyNominalSampleRate:
1121 uma_result = PROPERTY_NOMINAL_SAMPLE_RATE;
1122 DVLOG(1) << "kAudioDevicePropertyNominalSampleRate";
1123 break;
1124 case kAudioDevicePropertyDeviceIsRunningSomewhere:
1125 uma_result = PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE;
1126 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunningSomewhere";
1127 break;
1128 case kAudioDevicePropertyDeviceIsRunning:
1129 uma_result = PROPERTY_DEVICE_IS_RUNNING;
1130 DVLOG(1) << "kAudioDevicePropertyDeviceIsRunning";
1131 break;
1132 case kAudioDevicePropertyDeviceIsAlive:
1133 uma_result = PROPERTY_DEVICE_IS_ALIVE;
1134 DVLOG(1) << "kAudioDevicePropertyDeviceIsAlive";
1135 break;
1136 default:
1137 LOG(ERROR) << "Invalid device property change";
1138 break;
1139 }
1140 LogDevicePropertyChange(uma_result);
1141 device_property_changes_map_.erase(device_property_changes_map_.begin());
1142 }
972 } 1143 }
973 1144
974 } // namespace media 1145 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_low_latency_input_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698