Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 // Log if the input device is used exclusively (~hogged) by us or any other | |
| 62 // process in the system. | |
| 63 enum InputAudioDeviceHogResult { | |
| 64 DEVICE_IS_NOT_HOGGED = 0, | |
| 65 DEVICE_IS_HOGGED_BY_OTHER_PROCESS = 1, | |
| 66 DEVICE_IS_HOGGED_BY_OWN_PROCESS = 2, | |
| 67 DEVICE_IS_HOGGED_MAX = DEVICE_IS_HOGGED_BY_OWN_PROCESS | |
| 68 }; | |
| 69 | |
| 70 static void InputAudioDeviceHogResult(InputAudioDeviceHogResult result) { | |
| 71 UMA_HISTOGRAM_ENUMERATION("Media.Audio.InputDeviceIsHoggedMac", result, | |
| 72 DEVICE_IS_HOGGED_MAX + 1); | |
| 73 } | |
| 74 | |
| 61 static OSStatus GetInputDeviceStreamFormat( | 75 static OSStatus GetInputDeviceStreamFormat( |
| 62 AudioUnit audio_unit, | 76 AudioUnit audio_unit, |
| 63 AudioStreamBasicDescription* format) { | 77 AudioStreamBasicDescription* format) { |
| 64 DCHECK(audio_unit); | 78 DCHECK(audio_unit); |
| 65 UInt32 property_size = sizeof(*format); | 79 UInt32 property_size = sizeof(*format); |
| 66 // Get the audio stream data format on the input scope of the input element | 80 // Get the audio stream data format on the input scope of the input element |
| 67 // since it is connected to the current input device. | 81 // since it is connected to the current input device. |
| 68 OSStatus result = | 82 OSStatus result = |
| 69 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, | 83 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, |
| 70 kAudioUnitScope_Input, 1, format, &property_size); | 84 kAudioUnitScope_Input, 1, format, &property_size); |
| 71 DVLOG(1) << "Input device stream format: " << *format; | 85 DVLOG(1) << "Input device stream format: " << *format; |
| 72 return result; | 86 return result; |
| 73 } | 87 } |
| 74 | 88 |
| 89 static void CheckAudioDeviceProperties(AudioDeviceID device_id) { | |
| 90 DVLOG(1) << "CheckAudioDeviceProperties(device ID: 0x" << std::hex | |
| 91 << device_id << ")"; | |
| 92 // Check if the specified audio device is running in at least one process | |
| 93 // on the system. A value of 0 means that it is not running at all. | |
| 94 // The idea of checking this state is to see if the device is "alive" or not. | |
| 95 AudioObjectPropertyAddress address = { | |
| 96 kAudioDevicePropertyDeviceIsRunningSomewhere, | |
| 97 kAudioObjectPropertyScopeInput, kAudioObjectPropertyElementMaster}; | |
| 98 UInt32 is_running_somewhere = 0; | |
| 99 UInt32 data_size = sizeof(is_running_somewhere); | |
| 100 OSStatus error = AudioObjectGetPropertyData( | |
| 101 device_id, &address, 0, NULL, &data_size, &is_running_somewhere); | |
| 102 DVLOG_IF(1, !error) << "kAudioDevicePropertyDeviceIsRunningSomewhere: " | |
| 103 << is_running_somewhere; | |
| 104 // TOOD(henrika): consider if it is worth adding this state to UMA. | |
| 105 | |
| 106 // Check if there is any device conflict, i.e., if the device is currently | |
| 107 // owned exclusively by any other process than our own. | |
| 108 address.mSelector = kAudioDevicePropertyHogMode; | |
| 109 pid_t hog_pid = -1; | |
| 110 data_size = sizeof(hog_pid); | |
| 111 error = AudioObjectGetPropertyData(device_id, &address, 0, NULL, &data_size, | |
| 112 &hog_pid); | |
| 113 if (!error) { | |
| 114 if (hog_pid == -1) { | |
| 115 InputAudioDeviceHogResult(DEVICE_IS_NOT_HOGGED); | |
| 116 DVLOG(1) << "Device is available to all processes"; | |
| 117 } else { | |
| 118 hog_pid != getpid() | |
| 119 ? InputAudioDeviceHogResult(DEVICE_IS_HOGGED_BY_OTHER_PROCESS) | |
| 120 : InputAudioDeviceHogResult(DEVICE_IS_HOGGED_BY_OWN_PROCESS); | |
| 121 DVLOG(1) << "Process with PID=" << hog_pid << " has exclusive access" | |
| 122 << " (our own PID=" << getpid() << ")"; | |
| 123 } | |
| 124 } | |
| 125 } | |
| 126 | |
| 75 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" | 127 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" |
| 76 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html | 128 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html |
| 77 // for more details and background regarding this implementation. | 129 // for more details and background regarding this implementation. |
| 78 | 130 |
| 79 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager, | 131 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager, |
| 80 const AudioParameters& input_params, | 132 const AudioParameters& input_params, |
| 81 AudioDeviceID audio_device_id) | 133 AudioDeviceID audio_device_id) |
| 82 : manager_(manager), | 134 : manager_(manager), |
| 83 number_of_frames_(input_params.frames_per_buffer()), | 135 number_of_frames_(input_params.frames_per_buffer()), |
| 84 io_buffer_frame_size_(0), | 136 io_buffer_frame_size_(0), |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 deferred_start_cb_.callback(), | 417 deferred_start_cb_.callback(), |
| 366 base::TimeDelta::FromSeconds( | 418 base::TimeDelta::FromSeconds( |
| 367 AudioManagerMac::kStartDelayInSecsForPowerEvents)); | 419 AudioManagerMac::kStartDelayInSecsForPowerEvents)); |
| 368 return; | 420 return; |
| 369 } | 421 } |
| 370 | 422 |
| 371 sink_ = callback; | 423 sink_ = callback; |
| 372 last_success_time_ = base::TimeTicks::Now(); | 424 last_success_time_ = base::TimeTicks::Now(); |
| 373 audio_unit_render_has_worked_ = false; | 425 audio_unit_render_has_worked_ = false; |
| 374 StartAgc(); | 426 StartAgc(); |
| 375 OSStatus result = AudioOutputUnitStart(audio_unit_); | 427 // OSStatus result = AudioOutputUnitStart(audio_unit_); |
| 428 OSStatus result = noErr; | |
| 376 if (result == noErr) { | 429 if (result == noErr) { |
| 377 // For UMA stat purposes, start a one-shot timer which detects when input | 430 // For UMA stat purposes, start a one-shot timer which detects when input |
| 378 // callbacks starts indicating if input audio recording works as intended. | 431 // callbacks starts indicating if input audio recording works as intended. |
| 379 // CheckInputStartupSuccess() will check if |input_callback_is_active_| is | 432 // CheckInputStartupSuccess() will check if |input_callback_is_active_| is |
| 380 // true when the timer expires. This timer delay is currently set to | 433 // true when the timer expires. This timer delay is currently set to |
| 381 // 5 seconds to avoid false alarms. | 434 // 5 seconds to avoid false alarms. |
| 382 input_callback_timer_.reset(new base::OneShotTimer()); | 435 input_callback_timer_.reset(new base::OneShotTimer()); |
| 383 input_callback_timer_->Start( | 436 input_callback_timer_->Start( |
| 384 FROM_HERE, | 437 FROM_HERE, |
| 385 base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this, | 438 base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this, |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 } | 950 } |
| 898 | 951 |
| 899 bool AUAudioInputStream::GetInputCallbackIsActive() { | 952 bool AUAudioInputStream::GetInputCallbackIsActive() { |
| 900 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); | 953 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false); |
| 901 } | 954 } |
| 902 | 955 |
| 903 void AUAudioInputStream::CheckInputStartupSuccess() { | 956 void AUAudioInputStream::CheckInputStartupSuccess() { |
| 904 DCHECK(thread_checker_.CalledOnValidThread()); | 957 DCHECK(thread_checker_.CalledOnValidThread()); |
| 905 // Only add UMA stat related to failing input audio for streams where | 958 // Only add UMA stat related to failing input audio for streams where |
| 906 // the AGC has been enabled, e.g. WebRTC audio input streams. | 959 // the AGC has been enabled, e.g. WebRTC audio input streams. |
| 907 if (IsRunning() && GetAutomaticGainControl()) { | 960 if (/*IsRunning() &&*/ GetAutomaticGainControl()) { |
|
tommi (sloooow) - chröme
2016/02/15 15:30:12
unintentional?
| |
| 908 // Check if we have called Start() and input callbacks have actually | 961 // Check if we have called Start() and input callbacks have actually |
| 909 // started in time as they should. If that is not the case, we have a | 962 // started in time as they should. If that is not the case, we have a |
| 910 // problem and the stream is considered dead. | 963 // problem and the stream is considered dead. |
| 911 const bool input_callback_is_active = GetInputCallbackIsActive(); | 964 const bool input_callback_is_active = GetInputCallbackIsActive(); |
| 912 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartupSuccessMac", | 965 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartupSuccessMac", |
| 913 input_callback_is_active); | 966 input_callback_is_active); |
| 914 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active; | 967 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active; |
| 915 if (!input_callback_is_active) { | 968 if (!input_callback_is_active) { |
| 916 // Now when we know that startup has failed for some reason, add extra | 969 // Now when we know that startup has failed for some reason, add extra |
| 917 // UMA stats in an attempt to figure out the exact reason. | 970 // UMA stats in an attempt to figure out the exact reason. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 958 // and can be the same as |number_of_frames_|, which is the desired buffer | 1011 // and can be the same as |number_of_frames_|, which is the desired buffer |
| 959 // size. These two values might differ if other streams are using the same | 1012 // size. These two values might differ if other streams are using the same |
| 960 // device and any of these streams have asked for a smaller buffer size. | 1013 // device and any of these streams have asked for a smaller buffer size. |
| 961 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", | 1014 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac", |
| 962 io_buffer_frame_size_); | 1015 io_buffer_frame_size_); |
| 963 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; | 1016 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_; |
| 964 // TODO(henrika): this value will currently always report true. It should be | 1017 // TODO(henrika): this value will currently always report true. It should be |
| 965 // fixed when we understand the problem better. | 1018 // fixed when we understand the problem better. |
| 966 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", | 1019 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac", |
| 967 GetAutomaticGainControl()); | 1020 GetAutomaticGainControl()); |
| 1021 // Check some extra device properties and add more UMA stats if needed. | |
| 1022 CheckAudioDeviceProperties(input_device_id_); | |
| 968 } | 1023 } |
| 969 | 1024 |
| 970 } // namespace media | 1025 } // namespace media |
| OLD | NEW |