source: trunk/src/3rdparty/phonon/qt7/audionode.mm

Last change on this file was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 8.9 KB
Line 
1/* This file is part of the KDE project.
2
3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5 This library is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 2.1 or 3 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this library. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "audionode.h"
19#include "audiograph.h"
20#include "audioconnection.h"
21#include "medianode.h"
22
23QT_BEGIN_NAMESPACE
24
25namespace Phonon
26{
27namespace QT7
28{
29
30AudioNode::AudioNode(int maxInputBusses, int maxOutputBusses)
31{
32 m_auNode = 0;
33 m_audioUnit = 0;
34 m_audioGraph = 0;
35 m_maxInputBusses = maxInputBusses;
36 m_maxOutputBusses = maxOutputBusses;
37 m_lastConnectionIn = 0;
38}
39
40AudioNode::~AudioNode()
41{
42 setGraph(0);
43}
44
45void AudioNode::setGraph(AudioGraph *audioGraph)
46{
47 if (m_audioGraph == audioGraph)
48 return;
49
50 DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "is setting graph:" << int(audioGraph))
51 if (m_auNode){
52 AUGraphRemoveNode(m_audioGraph->audioGraphRef(), m_auNode);
53 m_auNode = 0;
54 }
55
56 m_audioUnit = 0;
57 m_lastConnectionIn = 0;
58 m_audioGraph = audioGraph;
59}
60
61void AudioNode::createAndConnectAUNodes()
62{
63 if (m_auNode)
64 return;
65
66 ComponentDescription description = getAudioNodeDescription();
67 DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AUNode"
68 << QString(!FindNextComponent(0, &description) ? "ERROR: COMPONENT NOT FOUND!" : "OK!"))
69
70 OSStatus err = noErr;
71
72 // The proper function to call here is AUGraphAddNode() but the type has
73 // changed between 10.5 and 10.6. it's still OK to call this function, but
74 // if we want to use the proper thing we need to move over to
75 // AudioComponentDescription everywhere, which is very similar to the
76 // ComponentDescription, but a different size. however,
77 // AudioComponentDescription only exists on 10.6+. More fun than we need to
78 // deal with at the moment, so we'll take the "deprecated" warning instead.
79 err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode);
80
81 BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR)
82 BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR)
83}
84
85AUNode AudioNode::getInputAUNode()
86{
87 return m_auNode;
88}
89
90AUNode AudioNode::getOutputAUNode()
91{
92 return m_auNode;
93}
94
95void AudioNode::createAudioUnits()
96{
97 if (m_audioUnit)
98 return;
99
100 DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AudioUnit")
101 OSStatus err = AUGraphGetNodeInfo(m_audioGraph->audioGraphRef(), m_auNode, 0, 0, 0, &m_audioUnit);
102 BACKEND_ASSERT2(err == noErr, "Could not get audio unit from audio node.", FATAL_ERROR)
103 initializeAudioUnit();
104}
105
106ComponentDescription AudioNode::getAudioNodeDescription() const
107{
108 // Override if needed.
109 ComponentDescription cd;
110 Q_UNUSED(cd);
111 return cd;
112}
113
114bool AudioNode::setStreamHelp(AudioConnection *c, int bus, OSType scope, bool fromSource)
115{
116 if (fromSource){
117 OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
118 bus, &c->m_sourceStreamDescription, sizeof(AudioStreamBasicDescription));
119 if (err != noErr){
120 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
121 return false;
122 }
123 AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
124 bus, c->m_sourceChannelLayout, c->m_sourceChannelLayoutSize);
125 } else {
126 OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
127 bus, &c->m_sinkStreamDescription, sizeof(AudioStreamBasicDescription));
128 if (err != noErr){
129 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
130 return false;
131 }
132 AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
133 bus, c->m_sinkChannelLayout, c->m_sourceChannelLayoutSize);
134 }
135 return true;
136}
137
138bool AudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side)
139{
140 if (side == Source){
141 // This object am source of connection:
142 if (connection->m_hasSourceSpecification){
143 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification out"
144 << connection->m_sourceOutputBus << "from connection source")
145 return setStreamHelp(connection, connection->m_sourceOutputBus, kAudioUnitScope_Output, true);
146 } else {
147 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification out")
148 }
149 } else {
150 if (connection->m_hasSinkSpecification){
151 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
152 << connection->m_sinkInputBus << "from connection sink")
153 return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, false);
154 } else if (connection->m_hasSourceSpecification){
155 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
156 << connection->m_sinkInputBus << "from connection source")
157 return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, true);
158 } else {
159 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification in")
160 }
161 }
162 return true;
163}
164
165bool AudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
166{
167 if (side == Source){
168 // As default, use the last description to describe the source:
169 if (m_lastConnectionIn->m_hasSinkSpecification){
170 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection sink.")
171 connection->m_sourceStreamDescription = m_lastConnectionIn->m_sinkStreamDescription;
172 connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sinkChannelLayoutSize);
173 memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sinkChannelLayout, m_lastConnectionIn->m_sinkChannelLayoutSize);
174 connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sinkChannelLayoutSize;
175 connection->m_hasSourceSpecification = true;
176 } else if (m_lastConnectionIn->m_hasSourceSpecification){
177 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection source.")
178 connection->m_sourceStreamDescription = m_lastConnectionIn->m_sourceStreamDescription;
179 connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sourceChannelLayoutSize);
180 memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayoutSize);
181 connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sourceChannelLayoutSize;
182 connection->m_hasSourceSpecification = true;
183 } else {
184 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " __WARNING__: could not get stream specification...")
185 }
186 } else {
187 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is sink, skips filling in stream.")
188 if (!connection->isSinkOnly())
189 m_lastConnectionIn = connection;
190 }
191 return true;
192}
193
194/**
195 Let timeProperty be one of e.g
196 {kAudioUnitProperty_Latency, kAudioUnitProperty_TailTime,
197 kAudioOutputUnitProperty_StartTime, kAudioUnitProperty_CurrentPlayTime}
198*/
199Float64 AudioNode::getTimeInSamples(int timeProperty)
200{
201 if (!m_audioUnit)
202 return 0;
203
204 AudioTimeStamp timeStamp;
205 UInt32 size = sizeof(timeStamp);
206 memset(&timeStamp, 0, sizeof(timeStamp));
207 OSStatus err = AudioUnitGetProperty(m_audioUnit,
208 timeProperty, kAudioUnitScope_Global,
209 0, &timeStamp, &size);
210 if (err != noErr)
211 return 0;
212 return timeStamp.mSampleTime;
213}
214
215void AudioNode::notify(const MediaNodeEvent *event)
216{
217 switch(event->type()){
218 case MediaNodeEvent::AudioGraphAboutToBeDeleted:
219 setGraph(0);
220 break;
221 case MediaNodeEvent::NewAudioGraph:
222 setGraph(static_cast<AudioGraph *>(event->data()));
223 break;
224 default:
225 break;
226 }
227
228 mediaNodeEvent(event);
229}
230
231void AudioNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
232{
233 // Override if needed
234}
235
236void AudioNode::initializeAudioUnit()
237{
238 // Override if needed.
239}
240
241}} //namespace Phonon::QT7
242
243QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.