| Index: media/audio/mac/audio_unified_mac.cc
|
| diff --git a/media/audio/mac/audio_unified_mac.cc b/media/audio/mac/audio_unified_mac.cc
|
| deleted file mode 100644
|
| index d1dc007e6a847ca86d97d8921c53b676903138e6..0000000000000000000000000000000000000000
|
| --- a/media/audio/mac/audio_unified_mac.cc
|
| +++ /dev/null
|
| @@ -1,397 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "media/audio/mac/audio_unified_mac.h"
|
| -
|
| -#include <CoreServices/CoreServices.h>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/mac_logging.h"
|
| -#include "media/audio/mac/audio_manager_mac.h"
|
| -
|
| -namespace media {
|
| -
|
| -// TODO(crogers): support more than hard-coded stereo input.
|
| -// Ideally we would like to receive this value as a constructor argument.
|
| -static const int kDefaultInputChannels = 2;
|
| -
|
| -AudioHardwareUnifiedStream::AudioHardwareUnifiedStream(
|
| - AudioManagerMac* manager, const AudioParameters& params)
|
| - : manager_(manager),
|
| - source_(NULL),
|
| - client_input_channels_(kDefaultInputChannels),
|
| - volume_(1.0f),
|
| - input_channels_(0),
|
| - output_channels_(0),
|
| - input_channels_per_frame_(0),
|
| - output_channels_per_frame_(0),
|
| - io_proc_id_(0),
|
| - device_(kAudioObjectUnknown),
|
| - is_playing_(false) {
|
| - DCHECK(manager_);
|
| -
|
| - // A frame is one sample across all channels. In interleaved audio the per
|
| - // frame fields identify the set of n |channels|. In uncompressed audio, a
|
| - // packet is always one frame.
|
| - format_.mSampleRate = params.sample_rate();
|
| - format_.mFormatID = kAudioFormatLinearPCM;
|
| - format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
|
| - kLinearPCMFormatFlagIsSignedInteger;
|
| - format_.mBitsPerChannel = params.bits_per_sample();
|
| - format_.mChannelsPerFrame = params.channels();
|
| - format_.mFramesPerPacket = 1;
|
| - format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels()) / 8;
|
| - format_.mBytesPerFrame = format_.mBytesPerPacket;
|
| - format_.mReserved = 0;
|
| -
|
| - // Calculate the number of sample frames per callback.
|
| - number_of_frames_ = params.GetBytesPerBuffer() / format_.mBytesPerPacket;
|
| -
|
| - input_bus_ = AudioBus::Create(client_input_channels_,
|
| - params.frames_per_buffer());
|
| - output_bus_ = AudioBus::Create(params);
|
| -}
|
| -
|
| -AudioHardwareUnifiedStream::~AudioHardwareUnifiedStream() {
|
| - DCHECK_EQ(device_, kAudioObjectUnknown);
|
| -}
|
| -
|
| -bool AudioHardwareUnifiedStream::Open() {
|
| - // Obtain the current output device selected by the user.
|
| - AudioObjectPropertyAddress pa;
|
| - pa.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
| - pa.mScope = kAudioObjectPropertyScopeGlobal;
|
| - pa.mElement = kAudioObjectPropertyElementMaster;
|
| -
|
| - UInt32 size = sizeof(device_);
|
| -
|
| - OSStatus result = AudioObjectGetPropertyData(
|
| - kAudioObjectSystemObject,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - &size,
|
| - &device_);
|
| -
|
| - if ((result != kAudioHardwareNoError) || (device_ == kAudioDeviceUnknown)) {
|
| - LOG(ERROR) << "Cannot open unified AudioDevice.";
|
| - return false;
|
| - }
|
| -
|
| - // The requested sample-rate must match the hardware sample-rate.
|
| - Float64 sample_rate = 0.0;
|
| - size = sizeof(sample_rate);
|
| -
|
| - pa.mSelector = kAudioDevicePropertyNominalSampleRate;
|
| - pa.mScope = kAudioObjectPropertyScopeWildcard;
|
| - pa.mElement = kAudioObjectPropertyElementMaster;
|
| -
|
| - result = AudioObjectGetPropertyData(
|
| - device_,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - &size,
|
| - &sample_rate);
|
| -
|
| - if (result != noErr || sample_rate != format_.mSampleRate) {
|
| - LOG(ERROR) << "Requested sample-rate: " << format_.mSampleRate
|
| - << " must match the hardware sample-rate: " << sample_rate;
|
| - return false;
|
| - }
|
| -
|
| - // Configure buffer frame size.
|
| - UInt32 frame_size = number_of_frames_;
|
| -
|
| - pa.mSelector = kAudioDevicePropertyBufferFrameSize;
|
| - pa.mScope = kAudioDevicePropertyScopeInput;
|
| - pa.mElement = kAudioObjectPropertyElementMaster;
|
| - result = AudioObjectSetPropertyData(
|
| - device_,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - sizeof(frame_size),
|
| - &frame_size);
|
| -
|
| - if (result != noErr) {
|
| - LOG(ERROR) << "Unable to set input buffer frame size: " << frame_size;
|
| - return false;
|
| - }
|
| -
|
| - pa.mScope = kAudioDevicePropertyScopeOutput;
|
| - result = AudioObjectSetPropertyData(
|
| - device_,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - sizeof(frame_size),
|
| - &frame_size);
|
| -
|
| - if (result != noErr) {
|
| - LOG(ERROR) << "Unable to set output buffer frame size: " << frame_size;
|
| - return false;
|
| - }
|
| -
|
| - DVLOG(1) << "Sample rate: " << sample_rate;
|
| - DVLOG(1) << "Frame size: " << frame_size;
|
| -
|
| - // Determine the number of input and output channels.
|
| - // We handle both the interleaved and non-interleaved cases.
|
| -
|
| - // Get input stream configuration.
|
| - pa.mSelector = kAudioDevicePropertyStreamConfiguration;
|
| - pa.mScope = kAudioDevicePropertyScopeInput;
|
| - pa.mElement = kAudioObjectPropertyElementMaster;
|
| -
|
| - result = AudioObjectGetPropertyDataSize(device_, &pa, 0, 0, &size);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - if (result == noErr && size > 0) {
|
| - // Allocate storage.
|
| - scoped_ptr<uint8[]> input_list_storage(new uint8[size]);
|
| - AudioBufferList& input_list =
|
| - *reinterpret_cast<AudioBufferList*>(input_list_storage.get());
|
| -
|
| - result = AudioObjectGetPropertyData(
|
| - device_,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - &size,
|
| - &input_list);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - if (result == noErr) {
|
| - // Determine number of input channels.
|
| - input_channels_per_frame_ = input_list.mNumberBuffers > 0 ?
|
| - input_list.mBuffers[0].mNumberChannels : 0;
|
| - if (input_channels_per_frame_ == 1 && input_list.mNumberBuffers > 1) {
|
| - // Non-interleaved.
|
| - input_channels_ = input_list.mNumberBuffers;
|
| - } else {
|
| - // Interleaved.
|
| - input_channels_ = input_channels_per_frame_;
|
| - }
|
| - }
|
| - }
|
| -
|
| - DVLOG(1) << "Input channels: " << input_channels_;
|
| - DVLOG(1) << "Input channels per frame: " << input_channels_per_frame_;
|
| -
|
| - // The hardware must have at least the requested input channels.
|
| - if (result != noErr || client_input_channels_ > input_channels_) {
|
| - LOG(ERROR) << "AudioDevice does not support requested input channels.";
|
| - return false;
|
| - }
|
| -
|
| - // Get output stream configuration.
|
| - pa.mSelector = kAudioDevicePropertyStreamConfiguration;
|
| - pa.mScope = kAudioDevicePropertyScopeOutput;
|
| - pa.mElement = kAudioObjectPropertyElementMaster;
|
| -
|
| - result = AudioObjectGetPropertyDataSize(device_, &pa, 0, 0, &size);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - if (result == noErr && size > 0) {
|
| - // Allocate storage.
|
| - scoped_ptr<uint8[]> output_list_storage(new uint8[size]);
|
| - AudioBufferList& output_list =
|
| - *reinterpret_cast<AudioBufferList*>(output_list_storage.get());
|
| -
|
| - result = AudioObjectGetPropertyData(
|
| - device_,
|
| - &pa,
|
| - 0,
|
| - 0,
|
| - &size,
|
| - &output_list);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - if (result == noErr) {
|
| - // Determine number of output channels.
|
| - output_channels_per_frame_ = output_list.mBuffers[0].mNumberChannels;
|
| - if (output_channels_per_frame_ == 1 && output_list.mNumberBuffers > 1) {
|
| - // Non-interleaved.
|
| - output_channels_ = output_list.mNumberBuffers;
|
| - } else {
|
| - // Interleaved.
|
| - output_channels_ = output_channels_per_frame_;
|
| - }
|
| - }
|
| - }
|
| -
|
| - DVLOG(1) << "Output channels: " << output_channels_;
|
| - DVLOG(1) << "Output channels per frame: " << output_channels_per_frame_;
|
| -
|
| - // The hardware must have at least the requested output channels.
|
| - if (result != noErr ||
|
| - output_channels_ < static_cast<int>(format_.mChannelsPerFrame)) {
|
| - LOG(ERROR) << "AudioDevice does not support requested output channels.";
|
| - return false;
|
| - }
|
| -
|
| - // Setup the I/O proc.
|
| - result = AudioDeviceCreateIOProcID(device_, RenderProc, this, &io_proc_id_);
|
| - if (result != noErr) {
|
| - LOG(ERROR) << "Error creating IOProc.";
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void AudioHardwareUnifiedStream::Close() {
|
| - DCHECK(!is_playing_);
|
| -
|
| - OSStatus result = AudioDeviceDestroyIOProcID(device_, io_proc_id_);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - io_proc_id_ = 0;
|
| - device_ = kAudioObjectUnknown;
|
| -
|
| - // Inform the audio manager that we have been closed. This can cause our
|
| - // destruction.
|
| - manager_->ReleaseOutputStream(this);
|
| -}
|
| -
|
| -void AudioHardwareUnifiedStream::Start(AudioSourceCallback* callback) {
|
| - DCHECK(callback);
|
| - DCHECK_NE(device_, kAudioObjectUnknown);
|
| - DCHECK(!is_playing_);
|
| - if (device_ == kAudioObjectUnknown || is_playing_)
|
| - return;
|
| -
|
| - source_ = callback;
|
| -
|
| - OSStatus result = AudioDeviceStart(device_, io_proc_id_);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| -
|
| - if (result == noErr)
|
| - is_playing_ = true;
|
| -}
|
| -
|
| -void AudioHardwareUnifiedStream::Stop() {
|
| - if (!is_playing_)
|
| - return;
|
| -
|
| - if (device_ != kAudioObjectUnknown) {
|
| - OSStatus result = AudioDeviceStop(device_, io_proc_id_);
|
| - OSSTATUS_DCHECK(result == noErr, result);
|
| - }
|
| -
|
| - is_playing_ = false;
|
| - source_ = NULL;
|
| -}
|
| -
|
| -void AudioHardwareUnifiedStream::SetVolume(double volume) {
|
| - volume_ = static_cast<float>(volume);
|
| - // TODO(crogers): set volume property
|
| -}
|
| -
|
| -void AudioHardwareUnifiedStream::GetVolume(double* volume) {
|
| - *volume = volume_;
|
| -}
|
| -
|
| -// Pulls on our provider with optional input, asking it to render output.
|
| -// Note to future hackers of this function: Do not add locks here because this
|
| -// is running on a real-time thread (for low-latency).
|
| -OSStatus AudioHardwareUnifiedStream::Render(
|
| - AudioDeviceID device,
|
| - const AudioTimeStamp* now,
|
| - const AudioBufferList* input_data,
|
| - const AudioTimeStamp* input_time,
|
| - AudioBufferList* output_data,
|
| - const AudioTimeStamp* output_time) {
|
| - // Convert the input data accounting for possible interleaving.
|
| - // TODO(crogers): it's better to simply memcpy() if source is already planar.
|
| - if (input_channels_ >= client_input_channels_) {
|
| - for (int channel_index = 0; channel_index < client_input_channels_;
|
| - ++channel_index) {
|
| - float* source;
|
| -
|
| - int source_channel_index = channel_index;
|
| -
|
| - if (input_channels_per_frame_ > 1) {
|
| - // Interleaved.
|
| - source = static_cast<float*>(input_data->mBuffers[0].mData) +
|
| - source_channel_index;
|
| - } else {
|
| - // Non-interleaved.
|
| - source = static_cast<float*>(
|
| - input_data->mBuffers[source_channel_index].mData);
|
| - }
|
| -
|
| - float* p = input_bus_->channel(channel_index);
|
| - for (int i = 0; i < number_of_frames_; ++i) {
|
| - p[i] = *source;
|
| - source += input_channels_per_frame_;
|
| - }
|
| - }
|
| - } else if (input_channels_) {
|
| - input_bus_->Zero();
|
| - }
|
| -
|
| - // Give the client optional input data and have it render the output data.
|
| - source_->OnMoreIOData(input_bus_.get(),
|
| - output_bus_.get(),
|
| - AudioBuffersState(0, 0));
|
| -
|
| - // TODO(crogers): handle final Core Audio 5.1 layout for 5.1 audio.
|
| -
|
| - // Handle interleaving as necessary.
|
| - // TODO(crogers): it's better to simply memcpy() if dest is already planar.
|
| -
|
| - for (int channel_index = 0;
|
| - channel_index < static_cast<int>(format_.mChannelsPerFrame);
|
| - ++channel_index) {
|
| - float* dest;
|
| -
|
| - int dest_channel_index = channel_index;
|
| -
|
| - if (output_channels_per_frame_ > 1) {
|
| - // Interleaved.
|
| - dest = static_cast<float*>(output_data->mBuffers[0].mData) +
|
| - dest_channel_index;
|
| - } else {
|
| - // Non-interleaved.
|
| - dest = static_cast<float*>(
|
| - output_data->mBuffers[dest_channel_index].mData);
|
| - }
|
| -
|
| - float* p = output_bus_->channel(channel_index);
|
| - for (int i = 0; i < number_of_frames_; ++i) {
|
| - *dest = p[i];
|
| - dest += output_channels_per_frame_;
|
| - }
|
| - }
|
| -
|
| - return noErr;
|
| -}
|
| -
|
| -OSStatus AudioHardwareUnifiedStream::RenderProc(
|
| - AudioDeviceID device,
|
| - const AudioTimeStamp* now,
|
| - const AudioBufferList* input_data,
|
| - const AudioTimeStamp* input_time,
|
| - AudioBufferList* output_data,
|
| - const AudioTimeStamp* output_time,
|
| - void* user_data) {
|
| - AudioHardwareUnifiedStream* audio_output =
|
| - static_cast<AudioHardwareUnifiedStream*>(user_data);
|
| - DCHECK(audio_output);
|
| - if (!audio_output)
|
| - return -1;
|
| -
|
| - return audio_output->Render(
|
| - device,
|
| - now,
|
| - input_data,
|
| - input_time,
|
| - output_data,
|
| - output_time);
|
| -}
|
| -
|
| -} // namespace media
|
|
|