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