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