AudioDestinationMac.cpp [plain text]
#include "config.h"
#if ENABLE(WEB_AUDIO)
#include "AudioDestinationMac.h"
#include "AudioIOCallback.h"
#include "AudioSessionManager.h"
#include "FloatConversion.h"
#include "Logging.h"
#include "VectorMath.h"
#include <CoreAudio/AudioHardware.h>
namespace WebCore {
const int kBufferSize = 128;
const float kLowThreshold = -1;
const float kHighThreshold = 1;
PassOwnPtr<AudioDestination> AudioDestination::create(AudioIOCallback& callback, const String&, unsigned numberOfInputChannels, unsigned numberOfOutputChannels, float sampleRate)
{
if (numberOfInputChannels)
LOG(Media, "AudioDestination::create(%u, %u, %f) - unhandled input channels", numberOfInputChannels, numberOfOutputChannels, sampleRate);
if (numberOfOutputChannels != 2)
LOG(Media, "AudioDestination::create(%u, %u, %f) - unhandled output channels", numberOfInputChannels, numberOfOutputChannels, sampleRate);
return adoptPtr(new AudioDestinationMac(callback, sampleRate));
}
float AudioDestination::hardwareSampleRate()
{
return AudioSession::sharedSession().sampleRate();
}
unsigned long AudioDestination::maxChannelCount()
{
return 0;
}
AudioDestinationMac::AudioDestinationMac(AudioIOCallback& callback, float sampleRate)
: m_outputUnit(0)
, m_callback(callback)
, m_renderBus(AudioBus::create(2, kBufferSize, false))
, m_sampleRate(sampleRate)
, m_isPlaying(false)
, m_audioSessionManagerToken(AudioSessionManagerToken::create(AudioSessionManager::WebAudio))
{
AudioComponent comp;
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = AudioComponentFindNext(0, &desc);
ASSERT(comp);
OSStatus result = AudioComponentInstanceNew(comp, &m_outputUnit);
ASSERT(!result);
result = AudioUnitInitialize(m_outputUnit);
ASSERT(!result);
configure();
}
AudioDestinationMac::~AudioDestinationMac()
{
if (m_outputUnit)
AudioComponentInstanceDispose(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);
}
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_callback.render(0, m_renderBus.get(), numberOfFrames);
for (unsigned i = 0; i < m_renderBus->numberOfChannels(); ++i) {
AudioChannel* channel = m_renderBus->channel(i);
VectorMath::vclip(channel->data(), 1, &kLowThreshold, &kHighThreshold, channel->mutableData(), 1, 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)