AudioDestinationMac.cpp [plain text]
#include "config.h"
#if ENABLE(WEB_AUDIO)
#include "AudioDestinationMac.h"
#include "AudioSourceProvider.h"
#include <CoreAudio/AudioHardware.h>
namespace WebCore {
const int kBufferSize = 128;
PassOwnPtr<AudioDestination> AudioDestination::create(AudioSourceProvider& provider, double sampleRate)
{
return adoptPtr(new AudioDestinationMac(provider, sampleRate));
}
double AudioDestination::hardwareSampleRate()
{
AudioDeviceID deviceID = kAudioDeviceUnknown;
UInt32 infoSize = sizeof(deviceID);
AudioObjectPropertyAddress defaultOutputDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID);
if (result)
return 0.0;
Float64 nominalSampleRate;
infoSize = sizeof(Float64);
AudioObjectPropertyAddress nominalSampleRateAddress = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
result = AudioObjectGetPropertyData(deviceID, &nominalSampleRateAddress, 0, 0, &infoSize, (void*)&nominalSampleRate);
if (result)
return 0.0;
return nominalSampleRate;
}
AudioDestinationMac::AudioDestinationMac(AudioSourceProvider& provider, double sampleRate)
: m_outputUnit(0)
, m_provider(provider)
, m_renderBus(2, kBufferSize, false)
, m_sampleRate(sampleRate)
, m_isPlaying(false)
{
Component comp;
ComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = FindNextComponent(0, &desc);
ASSERT(comp);
OSStatus result = OpenAComponent(comp, &m_outputUnit);
ASSERT(!result);
result = AudioUnitInitialize(m_outputUnit);
ASSERT(!result);
configure();
}
AudioDestinationMac::~AudioDestinationMac()
{
if (m_outputUnit)
CloseComponent(m_outputUnit);
}
void AudioDestinationMac::configure()
{
AURenderCallbackStruct input;
input.inputProc = inputProc;
input.inputProcRefCon = this;
OSStatus result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input));
ASSERT(!result);
AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = m_sampleRate;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved;
streamFormat.mBitsPerChannel = 8 * sizeof(AudioSampleType);
streamFormat.mChannelsPerFrame = 2;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerPacket = sizeof(AudioSampleType);
streamFormat.mBytesPerFrame = sizeof(AudioSampleType);
result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void*)&streamFormat, sizeof(AudioStreamBasicDescription));
ASSERT(!result);
UInt32 bufferSize = kBufferSize;
result = AudioUnitSetProperty(m_outputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, 0, (void*)&bufferSize, sizeof(bufferSize));
ASSERT(!result);
}
void AudioDestinationMac::start()
{
OSStatus result = AudioOutputUnitStart(m_outputUnit);
if (!result)
m_isPlaying = true;
}
void AudioDestinationMac::stop()
{
OSStatus result = AudioOutputUnitStop(m_outputUnit);
if (!result)
m_isPlaying = false;
}
OSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioData)
{
AudioBuffer* buffers = ioData->mBuffers;
m_renderBus.setChannelMemory(0, (float*)buffers[0].mData, numberOfFrames);
m_renderBus.setChannelMemory(1, (float*)buffers[1].mData, numberOfFrames);
m_provider.provideInput(&m_renderBus, numberOfFrames);
return noErr;
}
OSStatus AudioDestinationMac::inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 , UInt32 numberOfFrames, AudioBufferList* ioData)
{
AudioDestinationMac* audioOutput = static_cast<AudioDestinationMac*>(userData);
return audioOutput->render(numberOfFrames, ioData);
}
}
#endif // ENABLE(WEB_AUDIO)