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

Last change on this file 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.5 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 "audiograph.h"
19#include "quicktimeaudioplayer.h"
20#include "medianode.h"
21
22QT_BEGIN_NAMESPACE
23
24namespace Phonon
25{
26namespace QT7
27{
28
29AudioGraph::AudioGraph(MediaNode *root) : MediaNode(AudioGraphNode, 0, root), m_root(root)
30{
31 m_audioGraphRef = 0;
32 m_initialized = false;
33 m_startedLogically = false;
34 m_graphCannotPlay = false;
35 m_paused = false;
36}
37
38AudioGraph::~AudioGraph()
39{
40 deleteGraph();
41}
42
43void AudioGraph::startAllOverFromScratch()
44{
45 MediaNodeEvent event(MediaNodeEvent::AudioGraphAboutToBeDeleted, this);
46 m_root->notify(&event);
47 deleteGraph();
48}
49
50void AudioGraph::deleteGraph()
51{
52 if (m_audioGraphRef){
53 AUGraphStop(m_audioGraphRef);
54 AUGraphUninitialize(m_audioGraphRef);
55 AUGraphClose(m_audioGraphRef);
56 DisposeAUGraph(m_audioGraphRef);
57 m_initialized = false;
58 m_graphCannotPlay = false;
59 DEBUG_AUDIO_GRAPH("Graph ref in" << int(this) << "is deleted")
60 }
61}
62
63MediaNode *AudioGraph::root()
64{
65 return m_root;
66}
67
68AUGraph AudioGraph::audioGraphRef()
69{
70 return m_audioGraphRef;
71}
72
73void AudioGraph::setStatusCannotPlay()
74{
75 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "received 'cannot play' request")
76 if (!m_graphCannotPlay){
77 stop();
78 m_graphCannotPlay = true;
79 MediaNodeEvent e(MediaNodeEvent::AudioGraphCannotPlay, this);
80 m_root->notify(&e);
81 }
82}
83
84void AudioGraph::rebuildGraph()
85{
86 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "is rebuilding")
87 startAllOverFromScratch();
88 if (!openAndInit()){
89 setStatusCannotPlay();
90 } else {
91 tryStartGraph();
92 m_graphCannotPlay = false;
93 }
94}
95
96bool AudioGraph::graphCannotPlay()
97{
98 return m_graphCannotPlay;
99}
100
101void AudioGraph::updateStreamSpecifications()
102{
103 if (!m_initialized){
104 if (m_graphCannotPlay)
105 rebuildGraph();
106 return;
107 }
108
109 AudioConnection rootConnection(m_root);
110 bool updateOk = updateStreamSpecificationRecursive(&rootConnection);
111 if (!updateOk){
112 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not update stream specification. Rebuild.")
113 rebuildGraph();
114 }
115}
116
117bool AudioGraph::updateStreamSpecificationRecursive(AudioConnection *connection)
118{
119 bool updateOk = connection->updateStreamSpecification();
120 if (!updateOk)
121 return false;
122
123 for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
124 if (!updateStreamSpecificationRecursive(connection->m_sink->m_audioSinkList[i]))
125 return false;
126 }
127 return true;
128}
129
130bool AudioGraph::openAndInit()
131{
132 OSStatus err;
133 err = NewAUGraph(&m_audioGraphRef);
134 BACKEND_ASSERT3(err == noErr, "Could not create audio graph.", NORMAL_ERROR, false)
135
136 MediaNodeEvent eventNew(MediaNodeEvent::NewAudioGraph, this);
137 m_root->notify(&eventNew);
138
139 AudioConnection rootConnection(m_root);
140 createAndConnectAuNodesRecursive(&rootConnection);
141 err = AUGraphOpen(m_audioGraphRef);
142 BACKEND_ASSERT3(err == noErr, "Could not create audio graph.", NORMAL_ERROR, false)
143
144 if (!createAudioUnitsRecursive(&rootConnection))
145 return false;
146
147 err = AUGraphInitialize(m_audioGraphRef);
148 BACKEND_ASSERT3(err == noErr, "Could not initialize audio graph.", NORMAL_ERROR, false)
149
150 m_initialized = true;
151 MediaNodeEvent eventInit(MediaNodeEvent::AudioGraphInitialized, this);
152 m_root->notify(&eventInit);
153 return true;
154}
155
156void AudioGraph::createAndConnectAuNodesRecursive(AudioConnection *connection)
157{
158 connection->m_sink->m_audioNode->createAndConnectAUNodes();
159 for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
160 AudioConnection *c = connection->m_sink->m_audioSinkList[i];
161 createAndConnectAuNodesRecursive(c);
162 bool ok = c->connect(this);
163 BACKEND_ASSERT2(ok, "Could not connect an audio nodes pair in the audio graph.", NORMAL_ERROR)
164 }
165}
166
167bool AudioGraph::createAudioUnitsRecursive(AudioConnection *connection)
168{
169 connection->m_sink->m_audioNode->createAudioUnits();
170 bool ok = connection->updateStreamSpecification();
171 if (!ok)
172 return false;
173 for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
174 if (!createAudioUnitsRecursive(connection->m_sink->m_audioSinkList[i]))
175 return false;
176 }
177 return true;
178}
179
180void AudioGraph::tryStartGraph()
181{
182 // The graph will only start if the background AUGraph
183 // is valid. Therefore we just try. If it fails, user
184 // actions like connect etc. migh make the graph valid
185 // at a later point.
186 if (m_startedLogically && !isRunning()){
187 OSStatus err = AUGraphStart(m_audioGraphRef);
188 if (err == noErr)
189 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "started")
190 else
191 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not start")
192 }
193}
194
195bool AudioGraph::isRunning()
196{
197 Boolean running = false;
198 AUGraphIsRunning(m_audioGraphRef, &running);
199 return running;
200}
201
202void AudioGraph::setPaused(bool pause)
203{
204 // This function should only make
205 // a difference if the graph is
206 // running before pausing.
207 if (pause){
208 if (isRunning()){
209 stop();
210 m_paused = true;
211 }
212 } else if (m_paused){
213 start();
214 m_paused = false;
215 }
216}
217
218void AudioGraph::connectLate(AudioConnection *connection)
219{
220 MediaNodeEvent event(MediaNodeEvent::NewAudioGraph, this);
221 connection->m_sink->notify(&event);
222
223 if (!m_initialized)
224 return;
225
226 DEBUG_AUDIO_GRAPH("Graph:" << int(this) << "create and connect audio sink after init:" << int(connection->m_sink->m_audioNode))
227 AudioConnection startConnection(connection->m_source);
228 createAndConnectAuNodesRecursive(&startConnection);
229
230 if (!createAudioUnitsRecursive(&startConnection)){
231 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not update stream specification. Rebuild.")
232 rebuildGraph();
233 }
234}
235
236void AudioGraph::disconnectLate(AudioConnection *connection)
237{
238 if (!m_initialized)
239 return;
240
241 DEBUG_AUDIO_GRAPH("Graph:" << int(this) << "disconnect audio sink after init:" << int(connection->m_sink->m_audioNode))
242
243 if (!connection->disconnect(this)){
244 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not disconnect audio sink. Rebuild.")
245 rebuildGraph();
246 }
247}
248
249void AudioGraph::update()
250{
251 if (m_startedLogically){
252 if (m_initialized){
253 // Quick solution:
254 AUGraphUpdate(m_audioGraphRef, 0);
255 tryStartGraph();
256 } else
257 rebuildGraph();
258 }
259}
260
261int AudioGraph::nodeCount()
262{
263 if (!m_audioGraphRef)
264 return 0;
265 UInt32 count;
266 AUGraphGetNodeCount(m_audioGraphRef, &count);
267 return int(count);
268}
269
270void AudioGraph::prepare()
271{
272 if (!m_initialized)
273 rebuildGraph();
274}
275
276void AudioGraph::start()
277{
278 // Start does not mean 'start to play
279 // music'. It means 'prepare to receive
280 // audio from the player units'.
281 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "asked to start (cannot play:" << m_graphCannotPlay << ")")
282 m_startedLogically = true;
283
284 if (m_graphCannotPlay)
285 return;
286
287 if (!m_initialized)
288 rebuildGraph();
289
290 if (!m_graphCannotPlay)
291 tryStartGraph();
292}
293
294void AudioGraph::stop()
295{
296 DEBUG_AUDIO_GRAPH("Graph" << int(this) << "asked to stop")
297 if (m_audioGraphRef)
298 AUGraphStop(m_audioGraphRef);
299 m_startedLogically = false;
300}
301
302void AudioGraph::notify(const MediaNodeEvent *event, bool propagate)
303{
304 switch (event->type()){
305 case MediaNodeEvent::StartConnectionChange:
306 if (m_graphCannotPlay)
307 startAllOverFromScratch();
308 break;
309 case MediaNodeEvent::EndConnectionChange:
310 update();
311 break;
312 default:
313 break;
314 }
315 m_root->notify(event, propagate);
316}
317
318}} // namespace Phonon::QT7
319
320QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.