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 #include <CoreServices/CoreServices.h> | 6 #include <CoreServices/CoreServices.h> |
| 7 #include <mach/mach.h> | 7 #include <mach/mach.h> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 const AudioParameters& input_params, | 243 const AudioParameters& input_params, |
| 244 AudioDeviceID audio_device_id, | 244 AudioDeviceID audio_device_id, |
| 245 const AudioManager::LogCallback& log_callback) | 245 const AudioManager::LogCallback& log_callback) |
| 246 : manager_(manager), | 246 : manager_(manager), |
| 247 number_of_frames_(input_params.frames_per_buffer()), | 247 number_of_frames_(input_params.frames_per_buffer()), |
| 248 number_of_frames_provided_(0), | 248 number_of_frames_provided_(0), |
| 249 io_buffer_frame_size_(0), | 249 io_buffer_frame_size_(0), |
| 250 sink_(nullptr), | 250 sink_(nullptr), |
| 251 audio_unit_(0), | 251 audio_unit_(0), |
| 252 input_device_id_(audio_device_id), | 252 input_device_id_(audio_device_id), |
| 253 hardware_latency_frames_(0), | |
| 254 number_of_channels_in_frame_(0), | 253 number_of_channels_in_frame_(0), |
| 255 fifo_(input_params.channels(), | 254 fifo_(input_params.channels(), |
| 256 number_of_frames_, | 255 number_of_frames_, |
| 257 kNumberOfBlocksBufferInFifo), | 256 kNumberOfBlocksBufferInFifo), |
| 258 input_callback_is_active_(false), | 257 input_callback_is_active_(false), |
| 259 start_was_deferred_(false), | 258 start_was_deferred_(false), |
| 260 buffer_size_was_changed_(false), | 259 buffer_size_was_changed_(false), |
| 261 audio_unit_render_has_worked_(false), | 260 audio_unit_render_has_worked_(false), |
| 262 device_listener_is_active_(false), | 261 device_listener_is_active_(false), |
| 263 last_sample_time_(0.0), | 262 last_sample_time_(0.0), |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 // Finally, initialize the audio unit and ensure that it is ready to render. | 509 // Finally, initialize the audio unit and ensure that it is ready to render. |
| 511 // Allocates memory according to the maximum number of audio frames | 510 // Allocates memory according to the maximum number of audio frames |
| 512 // it can produce in response to a single render call. | 511 // it can produce in response to a single render call. |
| 513 result = AudioUnitInitialize(audio_unit_); | 512 result = AudioUnitInitialize(audio_unit_); |
| 514 if (result != noErr) { | 513 if (result != noErr) { |
| 515 HandleError(result); | 514 HandleError(result); |
| 516 return false; | 515 return false; |
| 517 } | 516 } |
| 518 | 517 |
| 519 // The hardware latency is fixed and will not change during the call. | 518 // The hardware latency is fixed and will not change during the call. |
| 520 hardware_latency_frames_ = GetHardwareLatency(); | 519 hardware_latency_ = GetHardwareLatency(); |
| 521 | 520 |
| 522 // The master channel is 0, Left and right are channels 1 and 2. | 521 // The master channel is 0, Left and right are channels 1 and 2. |
| 523 // And the master channel is not counted in |number_of_channels_in_frame_|. | 522 // And the master channel is not counted in |number_of_channels_in_frame_|. |
| 524 number_of_channels_in_frame_ = GetNumberOfChannelsFromStream(); | 523 number_of_channels_in_frame_ = GetNumberOfChannelsFromStream(); |
| 525 | 524 |
| 526 return true; | 525 return true; |
| 527 } | 526 } |
| 528 | 527 |
| 529 void AUAudioInputStream::Start(AudioInputCallback* callback) { | 528 void AUAudioInputStream::Start(AudioInputCallback* callback) { |
| 530 DCHECK(thread_checker_.CalledOnValidThread()); | 529 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 953 UpdateCaptureTimestamp(time_stamp); | 952 UpdateCaptureTimestamp(time_stamp); |
| 954 last_number_of_frames_ = number_of_frames; | 953 last_number_of_frames_ = number_of_frames; |
| 955 | 954 |
| 956 // TODO(grunell): We'll only care about the first buffer size change, any | 955 // TODO(grunell): We'll only care about the first buffer size change, any |
| 957 // further changes will be ignored. This is in line with output side stats. | 956 // further changes will be ignored. This is in line with output side stats. |
| 958 // It would be nice to have all changes reflected in UMA stats. | 957 // It would be nice to have all changes reflected in UMA stats. |
| 959 if (number_of_frames != number_of_frames_ && number_of_frames_provided_ == 0) | 958 if (number_of_frames != number_of_frames_ && number_of_frames_provided_ == 0) |
| 960 number_of_frames_provided_ = number_of_frames; | 959 number_of_frames_provided_ = number_of_frames; |
| 961 | 960 |
| 962 // Update the capture latency. | 961 // Update the capture latency. |
| 963 double capture_latency_frames = GetCaptureLatency(time_stamp); | 962 base::TimeDelta capture_latency = GetCaptureLatency(time_stamp); |
| 963 base::TimeDelta delay_timestamp = base::TimeTicks::Now(); | |
| 964 | 964 |
| 965 // The AGC volume level is updated once every second on a separate thread. | 965 // The AGC volume level is updated once every second on a separate thread. |
| 966 // Note that, |volume| is also updated each time SetVolume() is called | 966 // Note that, |volume| is also updated each time SetVolume() is called |
| 967 // through IPC by the render-side AGC. | 967 // through IPC by the render-side AGC. |
| 968 double normalized_volume = 0.0; | 968 double normalized_volume = 0.0; |
| 969 GetAgcVolume(&normalized_volume); | 969 GetAgcVolume(&normalized_volume); |
| 970 | 970 |
| 971 AudioBuffer& buffer = io_data->mBuffers[0]; | 971 AudioBuffer& buffer = io_data->mBuffers[0]; |
| 972 uint8_t* audio_data = reinterpret_cast<uint8_t*>(buffer.mData); | 972 uint8_t* audio_data = reinterpret_cast<uint8_t*>(buffer.mData); |
| 973 uint32_t capture_delay_bytes = static_cast<uint32_t>( | |
| 974 (capture_latency_frames + 0.5) * format_.mBytesPerFrame); | |
| 975 DCHECK(audio_data); | 973 DCHECK(audio_data); |
| 976 if (!audio_data) | 974 if (!audio_data) |
| 977 return kAudioUnitErr_InvalidElement; | 975 return kAudioUnitErr_InvalidElement; |
| 978 | 976 |
| 979 // Dynamically increase capacity of the FIFO to handle larger buffers from | 977 // Dynamically increase capacity of the FIFO to handle larger buffers from |
| 980 // CoreAudio. This can happen in combination with Apple Thunderbolt Displays | 978 // CoreAudio. This can happen in combination with Apple Thunderbolt Displays |
| 981 // when the Display Audio is used as capture source and the cable is first | 979 // when the Display Audio is used as capture source and the cable is first |
| 982 // remove and then inserted again. | 980 // remove and then inserted again. |
| 983 // See http://www.crbug.com/434681 for details. | 981 // See http://www.crbug.com/434681 for details. |
| 984 if (static_cast<int>(number_of_frames) > fifo_.GetUnfilledFrames()) { | 982 if (static_cast<int>(number_of_frames) > fifo_.GetUnfilledFrames()) { |
| 985 // Derive required increase in number of FIFO blocks. The increase is | 983 // Derive required increase in number of FIFO blocks. The increase is |
| 986 // typically one block. | 984 // typically one block. |
| 987 const int blocks = | 985 const int blocks = |
| 988 static_cast<int>((number_of_frames - fifo_.GetUnfilledFrames()) / | 986 static_cast<int>((number_of_frames - fifo_.GetUnfilledFrames()) / |
| 989 number_of_frames_) + 1; | 987 number_of_frames_) + 1; |
| 990 DLOG(WARNING) << "Increasing FIFO capacity by " << blocks << " blocks"; | 988 DLOG(WARNING) << "Increasing FIFO capacity by " << blocks << " blocks"; |
| 991 TRACE_EVENT_INSTANT1("audio", "Increasing FIFO capacity", | 989 TRACE_EVENT_INSTANT1("audio", "Increasing FIFO capacity", |
| 992 TRACE_EVENT_SCOPE_THREAD, "increased by", blocks); | 990 TRACE_EVENT_SCOPE_THREAD, "increased by", blocks); |
| 993 fifo_.IncreaseCapacity(blocks); | 991 fifo_.IncreaseCapacity(blocks); |
| 994 } | 992 } |
| 995 | 993 |
| 996 // Copy captured (and interleaved) data into FIFO. | 994 // Copy captured (and interleaved) data into FIFO. |
| 997 fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8); | 995 fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8); |
|
o1ka
2017/02/10 13:28:50
Shouldn't we push latency and timestamp info the F
| |
| 998 | 996 |
| 999 // Consume and deliver the data when the FIFO has a block of available data. | 997 // Consume and deliver the data when the FIFO has a block of available data. |
| 1000 while (fifo_.available_blocks()) { | 998 while (fifo_.available_blocks()) { |
| 1001 const AudioBus* audio_bus = fifo_.Consume(); | 999 const AudioBus* audio_bus = fifo_.Consume(); |
| 1002 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); | 1000 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); |
| 1003 | 1001 |
| 1004 // Compensate the audio delay caused by the FIFO. | 1002 // Compensate the audio delay caused by the FIFO. |
| 1005 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; | 1003 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; |
|
o1ka
2017/02/10 13:28:50
Hmm.. does it really compile? :)
DaleCurtis
2017/02/11 01:43:13
Like I said, not done yet :)
| |
| 1006 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); | 1004 sink_->OnData(this, audio_bus, capture_latency, delay_timestamp, |
|
o1ka
2017/02/10 13:28:50
Shouldn't we adjust latency and timestamp values t
| |
| 1005 normalized_volume); | |
| 1007 } | 1006 } |
| 1008 | 1007 |
| 1009 return noErr; | 1008 return noErr; |
| 1010 } | 1009 } |
| 1011 | 1010 |
| 1012 void AUAudioInputStream::DevicePropertyChangedOnMainThread( | 1011 void AUAudioInputStream::DevicePropertyChangedOnMainThread( |
| 1013 const std::vector<UInt32>& properties) { | 1012 const std::vector<UInt32>& properties) { |
| 1014 DCHECK(thread_checker_.CalledOnValidThread()); | 1013 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1015 DCHECK(device_listener_is_active_); | 1014 DCHECK(device_listener_is_active_); |
| 1016 // Use property as key to a map and increase its value. We are not | 1015 // Use property as key to a map and increase its value. We are not |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1106 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, | 1105 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, |
| 1107 kAudioObjectPropertyElementMaster}; | 1106 kAudioObjectPropertyElementMaster}; |
| 1108 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address, | 1107 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address, |
| 1109 0, 0, &info_size, &nominal_sample_rate); | 1108 0, 0, &info_size, &nominal_sample_rate); |
| 1110 if (result != noErr) | 1109 if (result != noErr) |
| 1111 return 0.0; | 1110 return 0.0; |
| 1112 | 1111 |
| 1113 return static_cast<int>(nominal_sample_rate); | 1112 return static_cast<int>(nominal_sample_rate); |
| 1114 } | 1113 } |
| 1115 | 1114 |
| 1116 double AUAudioInputStream::GetHardwareLatency() { | 1115 base::TimeDelta AUAudioInputStream::GetHardwareLatency() { |
| 1117 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { | 1116 if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) { |
| 1118 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; | 1117 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; |
| 1119 return 0.0; | 1118 return base::TimeDelta(); |
| 1120 } | 1119 } |
| 1121 | 1120 |
| 1122 // Get audio unit latency. | 1121 // Get audio unit latency. |
| 1123 Float64 audio_unit_latency_sec = 0.0; | 1122 Float64 audio_unit_latency_sec = 0.0; |
| 1124 UInt32 size = sizeof(audio_unit_latency_sec); | 1123 UInt32 size = sizeof(audio_unit_latency_sec); |
| 1125 OSStatus result = AudioUnitGetProperty( | 1124 OSStatus result = AudioUnitGetProperty( |
| 1126 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, | 1125 audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, |
| 1127 &audio_unit_latency_sec, &size); | 1126 &audio_unit_latency_sec, &size); |
| 1128 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) | 1127 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
| 1129 << "Could not get audio unit latency"; | 1128 << "Could not get audio unit latency"; |
| 1130 | 1129 |
| 1131 // Get input audio device latency. | 1130 // Get input audio device latency. |
| 1132 AudioObjectPropertyAddress property_address = { | 1131 AudioObjectPropertyAddress property_address = { |
| 1133 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput, | 1132 kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput, |
| 1134 kAudioObjectPropertyElementMaster}; | 1133 kAudioObjectPropertyElementMaster}; |
| 1135 UInt32 device_latency_frames = 0; | 1134 UInt32 device_latency_frames = 0; |
| 1136 size = sizeof(device_latency_frames); | 1135 size = sizeof(device_latency_frames); |
| 1137 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, | 1136 result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0, |
| 1138 nullptr, &size, &device_latency_frames); | 1137 nullptr, &size, &device_latency_frames); |
| 1139 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; | 1138 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; |
| 1140 | 1139 |
| 1141 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) + | 1140 return base::TimeDelta::FromSecondsD( |
| 1142 device_latency_frames); | 1141 audio_unit_latency_sec + |
| 1142 device_latency_frames / static_cast<double>(format_.mSampleRate)); | |
| 1143 } | 1143 } |
| 1144 | 1144 |
| 1145 double AUAudioInputStream::GetCaptureLatency( | 1145 base::TimeDelta AUAudioInputStream::GetCaptureLatency( |
| 1146 const AudioTimeStamp* input_time_stamp) { | 1146 const AudioTimeStamp* input_time_stamp) { |
| 1147 // Get the delay between between the actual recording instant and the time | 1147 // Get the delay between between the actual recording instant and the time |
| 1148 // when the data packet is provided as a callback. | 1148 // when the data packet is provided as a callback. |
| 1149 UInt64 capture_time_ns = | 1149 UInt64 capture_time_ns = |
| 1150 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime); | 1150 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime); |
| 1151 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 1151 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
| 1152 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) * | |
| 1153 format_.mSampleRate); | |
| 1154 | 1152 |
| 1155 // Total latency is composed by the dynamic latency and the fixed | 1153 // Total latency is composed by the dynamic latency and the fixed |
| 1156 // hardware latency. | 1154 // hardware latency. |
| 1157 return (delay_frames + hardware_latency_frames_); | 1155 return hardware_latency_ + |
| 1156 base::TimeDelta::FromMicroseconds((now_ns - capture_time_ns) / | |
| 1157 kNanosecondsPerMicrosecond); | |
| 1158 } | 1158 } |
| 1159 | 1159 |
| 1160 int AUAudioInputStream::GetNumberOfChannelsFromStream() { | 1160 int AUAudioInputStream::GetNumberOfChannelsFromStream() { |
| 1161 // Get the stream format, to be able to read the number of channels. | 1161 // Get the stream format, to be able to read the number of channels. |
| 1162 AudioObjectPropertyAddress property_address = { | 1162 AudioObjectPropertyAddress property_address = { |
| 1163 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, | 1163 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, |
| 1164 kAudioObjectPropertyElementMaster}; | 1164 kAudioObjectPropertyElementMaster}; |
| 1165 AudioStreamBasicDescription stream_format; | 1165 AudioStreamBasicDescription stream_format; |
| 1166 UInt32 size = sizeof(stream_format); | 1166 UInt32 size = sizeof(stream_format); |
| 1167 OSStatus result = AudioObjectGetPropertyData( | 1167 OSStatus result = AudioObjectGetPropertyData( |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1681 | 1681 |
| 1682 number_of_frames_provided_ = 0; | 1682 number_of_frames_provided_ = 0; |
| 1683 glitches_detected_ = 0; | 1683 glitches_detected_ = 0; |
| 1684 last_sample_time_ = 0; | 1684 last_sample_time_ = 0; |
| 1685 last_number_of_frames_ = 0; | 1685 last_number_of_frames_ = 0; |
| 1686 total_lost_frames_ = 0; | 1686 total_lost_frames_ = 0; |
| 1687 largest_glitch_frames_ = 0; | 1687 largest_glitch_frames_ = 0; |
| 1688 } | 1688 } |
| 1689 | 1689 |
| 1690 } // namespace media | 1690 } // namespace media |
| OLD | NEW |