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

Last change on this file since 757 was 2, checked in by Dmitry A. Kuminov, 17 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 8.8 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 BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR)
81 BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR)
82}
83
84AUNode AudioNode::getInputAUNode()
85{
86 return m_auNode;
87}
88
89AUNode AudioNode::getOutputAUNode()
90{
91 return m_auNode;
92}
93
94void AudioNode::createAudioUnits()
95{
96 if (m_audioUnit)
97 return;
98
99 DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AudioUnit")
100 OSStatus err = AUGraphGetNodeInfo(m_audioGraph->audioGraphRef(), m_auNode, 0, 0, 0, &m_audioUnit);
101 BACKEND_ASSERT2(err == noErr, "Could not get audio unit from audio node.", FATAL_ERROR)
102 initializeAudioUnit();
103}
104
105ComponentDescription AudioNode::getAudioNodeDescription() const
106{
107 // Override if needed.
108 ComponentDescription cd;
109 Q_UNUSED(cd);
110 return cd;
111}
112
113bool AudioNode::setStreamHelp(AudioConnection *c, int bus, OSType scope, bool fromSource)
114{
115 if (fromSource){
116 OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
117 bus, &c->m_sourceStreamDescription, sizeof(AudioStreamBasicDescription));
118 if (err != noErr){
119 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
120 return false;
121 }
122 AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
123 bus, c->m_sourceChannelLayout, c->m_sourceChannelLayoutSize);
124 } else {
125 OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
126 bus, &c->m_sinkStreamDescription, sizeof(AudioStreamBasicDescription));
127 if (err != noErr){
128 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
129 return false;
130 }
131 AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
132 bus, c->m_sinkChannelLayout, c->m_sourceChannelLayoutSize);
133 }
134 return true;
135}
136
137bool AudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side)
138{
139 if (side == Source){
140 // This object am source of connection:
141 if (connection->m_hasSourceSpecification){
142 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification out"
143 << connection->m_sourceOutputBus << "from connection source")
144 return setStreamHelp(connection, connection->m_sourceOutputBus, kAudioUnitScope_Output, true);
145 } else {
146 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification out")
147 }
148 } else {
149 if (connection->m_hasSinkSpecification){
150 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
151 << connection->m_sinkInputBus << "from connection sink")
152 return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, false);
153 } else if (connection->m_hasSourceSpecification){
154 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
155 << connection->m_sinkInputBus << "from connection source")
156 return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, true);
157 } else {
158 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification in")
159 }
160 }
161 return true;
162}
163
164bool AudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
165{
166 if (side == Source){
167 // As default, use the last description to describe the source:
168 if (m_lastConnectionIn->m_hasSinkSpecification){
169 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection sink.")
170 connection->m_sourceStreamDescription = m_lastConnectionIn->m_sinkStreamDescription;
171 connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sinkChannelLayoutSize);
172 memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sinkChannelLayout, m_lastConnectionIn->m_sinkChannelLayoutSize);
173 connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sinkChannelLayoutSize;
174 connection->m_hasSourceSpecification = true;
175 } else if (m_lastConnectionIn->m_hasSourceSpecification){
176 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection source.")
177 connection->m_sourceStreamDescription = m_lastConnectionIn->m_sourceStreamDescription;
178 connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sourceChannelLayoutSize);
179 memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayoutSize);
180 connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sourceChannelLayoutSize;
181 connection->m_hasSourceSpecification = true;
182 } else {
183 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " __WARNING__: could not get stream specification...")
184 }
185 } else {
186 DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is sink, skips filling in stream.")
187 if (!connection->isSinkOnly())
188 m_lastConnectionIn = connection;
189 }
190 return true;
191}
192
193/**
194 Let timeProperty be one of e.g
195 {kAudioUnitProperty_Latency, kAudioUnitProperty_TailTime,
196 kAudioOutputUnitProperty_StartTime, kAudioUnitProperty_CurrentPlayTime}
197*/
198Float64 AudioNode::getTimeInSamples(int timeProperty)
199{
200 if (!m_audioUnit)
201 return 0;
202
203 AudioTimeStamp timeStamp;
204 UInt32 size = sizeof(timeStamp);
205 memset(&timeStamp, 0, sizeof(timeStamp));
206 OSStatus err = AudioUnitGetProperty(m_audioUnit,
207 timeProperty, kAudioUnitScope_Global,
208 0, &timeStamp, &size);
209 if (err != noErr)
210 return 0;
211 return timeStamp.mSampleTime;
212}
213
214void AudioNode::notify(const MediaNodeEvent *event)
215{
216 switch(event->type()){
217 case MediaNodeEvent::AudioGraphAboutToBeDeleted:
218 setGraph(0);
219 break;
220 case MediaNodeEvent::NewAudioGraph:
221 setGraph(static_cast<AudioGraph *>(event->data()));
222 break;
223 default:
224 break;
225 }
226
227 mediaNodeEvent(event);
228}
229
230void AudioNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
231{
232 // Override if needed
233}
234
235void AudioNode::initializeAudioUnit()
236{
237 // Override if needed.
238}
239
240}} //namespace Phonon::QT7
241
242QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.