1bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen/* 2bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * Copyright (C) 2010 Google Inc. All rights reserved. 3bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 4bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * Redistribution and use in source and binary forms, with or without 5bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * modification, are permitted provided that the following conditions 6bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * are met: 7bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 8bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 1. Redistributions of source code must retain the above copyright 9bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * notice, this list of conditions and the following disclaimer. 10bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 2. Redistributions in binary form must reproduce the above copyright 11bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * notice, this list of conditions and the following disclaimer in the 12bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * documentation and/or other materials provided with the distribution. 13bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * its contributors may be used to endorse or promote products derived 15bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * from this software without specific prior written permission. 16bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 17bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen */ 28bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 29bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "config.h" 30bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 31bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#if ENABLE(WEB_AUDIO) 32bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 33bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "AudioDestinationMac.h" 34bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 35bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "AudioSourceProvider.h" 36bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include <CoreAudio/AudioHardware.h> 37bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 38bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsennamespace WebCore { 39bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 40bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenconst int kBufferSize = 128; 41bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 42bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// Factory method: Mac-implementation 43bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian MonsenPassOwnPtr<AudioDestination> AudioDestination::create(AudioSourceProvider& provider, double sampleRate) 44bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 45bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return adoptPtr(new AudioDestinationMac(provider, sampleRate)); 46bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 47bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 48bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsendouble AudioDestination::hardwareSampleRate() 49bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 50bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Determine the default output device's sample-rate. 51bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AudioDeviceID deviceID = kAudioDeviceUnknown; 52bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen UInt32 infoSize = sizeof(deviceID); 53bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 542bde8e466a4451c7319e3a072d118917957d6554Steve Block AudioObjectPropertyAddress defaultOutputDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 552bde8e466a4451c7319e3a072d118917957d6554Steve Block OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID); 56bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (result) 57bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return 0.0; // error 58bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 59bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen Float64 nominalSampleRate; 60bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen infoSize = sizeof(Float64); 61bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 62bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AudioObjectPropertyAddress nominalSampleRateAddress = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; 63bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen result = AudioObjectGetPropertyData(deviceID, &nominalSampleRateAddress, 0, 0, &infoSize, (void*)&nominalSampleRate); 64bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (result) 65bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return 0.0; // error 66bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 67bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return nominalSampleRate; 68bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 69bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 70bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian MonsenAudioDestinationMac::AudioDestinationMac(AudioSourceProvider& provider, double sampleRate) 71bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen : m_outputUnit(0) 72bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen , m_provider(provider) 73bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen , m_renderBus(2, kBufferSize, false) 74bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen , m_sampleRate(sampleRate) 75bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen , m_isPlaying(false) 76bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 77bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Open and initialize DefaultOutputUnit 78bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen Component comp; 79bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ComponentDescription desc; 80bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 81bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen desc.componentType = kAudioUnitType_Output; 82bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen desc.componentSubType = kAudioUnitSubType_DefaultOutput; 83bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen desc.componentManufacturer = kAudioUnitManufacturer_Apple; 84bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen desc.componentFlags = 0; 85bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen desc.componentFlagsMask = 0; 86bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen comp = FindNextComponent(0, &desc); 87bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 88bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(comp); 89bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 90bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen OSStatus result = OpenAComponent(comp, &m_outputUnit); 91bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!result); 92bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 93bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen result = AudioUnitInitialize(m_outputUnit); 94bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!result); 95bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 96bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen configure(); 97bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 98bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 99bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian MonsenAudioDestinationMac::~AudioDestinationMac() 100bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 101bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (m_outputUnit) 102bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen CloseComponent(m_outputUnit); 103bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 104bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 105bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid AudioDestinationMac::configure() 106bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 107bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Set render callback 108bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AURenderCallbackStruct input; 109bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen input.inputProc = inputProc; 110bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen input.inputProcRefCon = this; 111bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen OSStatus result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)); 112bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!result); 113bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 114bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Set stream format 115bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AudioStreamBasicDescription streamFormat; 116bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mSampleRate = m_sampleRate; 117bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mFormatID = kAudioFormatLinearPCM; 118bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mFormatFlags = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved; 119bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mBitsPerChannel = 8 * sizeof(AudioSampleType); 120bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mChannelsPerFrame = 2; 121bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mFramesPerPacket = 1; 122bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mBytesPerPacket = sizeof(AudioSampleType); 123bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen streamFormat.mBytesPerFrame = sizeof(AudioSampleType); 124bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 125bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void*)&streamFormat, sizeof(AudioStreamBasicDescription)); 126bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!result); 127bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 128bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Set the buffer frame size. 129bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen UInt32 bufferSize = kBufferSize; 130bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen result = AudioUnitSetProperty(m_outputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, 0, (void*)&bufferSize, sizeof(bufferSize)); 131bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!result); 132bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 133bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 134bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid AudioDestinationMac::start() 135bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 136bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen OSStatus result = AudioOutputUnitStart(m_outputUnit); 137bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 138bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (!result) 139bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_isPlaying = true; 140bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 141bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 142bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid AudioDestinationMac::stop() 143bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 144bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen OSStatus result = AudioOutputUnitStop(m_outputUnit); 145bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 146bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (!result) 147bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_isPlaying = false; 148bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 149bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 150bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// Pulls on our provider to get rendered audio stream. 151bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian MonsenOSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioData) 152bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 153bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AudioBuffer* buffers = ioData->mBuffers; 154bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_renderBus.setChannelMemory(0, (float*)buffers[0].mData, numberOfFrames); 155bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_renderBus.setChannelMemory(1, (float*)buffers[1].mData, numberOfFrames); 156bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 157bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_provider.provideInput(&m_renderBus, numberOfFrames); 158bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 159bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return noErr; 160bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 161bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 162bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// DefaultOutputUnit callback 163bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian MonsenOSStatus AudioDestinationMac::inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 /*busNumber*/, UInt32 numberOfFrames, AudioBufferList* ioData) 164bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 165bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen AudioDestinationMac* audioOutput = static_cast<AudioDestinationMac*>(userData); 166bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return audioOutput->render(numberOfFrames, ioData); 167bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 168bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 169bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} // namespace WebCore 170bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 171bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#endif // ENABLE(WEB_AUDIO) 172