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 "medianode.h"
19
#include "audiograph.h"
20
#include "audionode.h"
21
#include "backendheader.h"
22
23
#include "mediaobject.h"
24
#include "audiooutput.h"
25
#include "quicktimevideoplayer.h"
26
27
QT_BEGIN_NAMESPACE
28
29
namespace Phonon
30
{
31
namespace QT7
32
{
33
34
MediaNode::MediaNode(NodeDescription description, QObject *parent)
35
    : QObject(parent), m_audioGraph(0), m_audioNode(0), m_description(description), m_owningMediaObject(0)
36
{
37
}
38
39
MediaNode::MediaNode(NodeDescription description, AudioNode *audioPart, QObject *parent)
40
    : QObject(parent), m_audioGraph(0), m_audioNode(audioPart), m_description(description)
41
{
42
}
43
44
void MediaNode::setAudioNode(AudioNode *audioPart)
45
{
46
    if (m_audioNode)
47
        delete m_audioNode;
48
    m_audioNode = audioPart;
49
}
50
51
MediaNode::~MediaNode()
52
{
53
   delete m_audioNode;
54
   qDeleteAll(m_audioSinkList);
55
}
56
57
AudioConnection *MediaNode::getAudioConnectionToSink(MediaNode *sink)
58
{
59
    AudioConnection *connection = 0;
60
    for (int i=0; i<m_audioSinkList.size(); ++i){
61
        if (m_audioSinkList[i]->isBetween(this, sink)){
62
            connection = m_audioSinkList[i];
63
            break;
64
        }
65
    }
66
    return connection;
67
}
68
69
bool MediaNode::connectToSink(MediaNode *sink)
70
{
71
    if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
72
        // Check that they don't belong to different graphs. If they do, but
73
        // sink is not connected to any source, accept it:
74
        if (m_owningMediaObject && sink->m_owningMediaObject
75
            && m_owningMediaObject != sink->m_owningMediaObject
76
            && !sink->m_audioSourceList.isEmpty()){
77
            return false;
78
        }
79
80
        // Check that the connection doesn't already exists:
81
        AudioConnection *connection = getAudioConnectionToSink(sink);
82
        if (connection)
83
            return true;
84
85
        // Check that there are awailable input/output busses:
86
        int inputBus = sink->availableAudioInputBus();
87
        int outputBus = availableAudioOutputBus();
88
        if (inputBus >= sink->m_audioNode->m_maxInputBusses || outputBus >= m_audioNode->m_maxOutputBusses)
89
            return false;
90
91
        // All OK. Create connection:
92
        connection = new AudioConnection(this, outputBus, sink, inputBus);
93
        m_audioSinkList << connection;
94
        sink->m_audioSourceList << connection;
95
96
        if (m_audioNode->m_audioGraph)
97
            m_audioNode->m_audioGraph->connectLate(connection);
98
99
        MediaNodeEvent event1(MediaNodeEvent::AudioSinkAdded, connection);
100
        notify(&event1, false);
101
        MediaNodeEvent event2(MediaNodeEvent::AudioSourceAdded, connection);
102
        sink->notify(&event2, false);
103
        return true;
104
    }
105
106
    if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
107
        // Check that the connection doesn't already exists:
108
        if (m_videoSinkList.contains(sink))
109
            return true;
110
111
        m_videoSinkList << sink;
112
        MediaNodeEvent event1(MediaNodeEvent::VideoSinkAdded, sink);
113
        notify(&event1, false);
114
        MediaNodeEvent event2(MediaNodeEvent::VideoSourceAdded, this);
115
        sink->notify(&event2, false);
116
        return true;
117
    }
118
119
    return false;
120
}
121
122
bool MediaNode::disconnectToSink(MediaNode *sink)
123
{
124
    if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
125
        AudioConnection *connection = getAudioConnectionToSink(sink);
126
        if (!connection)
127
            return false;
128
129
        m_audioSinkList.removeOne(connection);
130
        sink->m_audioSourceList.removeOne(connection);
131
132
        if (m_audioNode->m_audioGraph)
133
            m_audioNode->m_audioGraph->disconnectLate(connection);
134
135
        MediaNodeEvent event1(MediaNodeEvent::AudioSinkRemoved, connection);
136
        notify(&event1, false);
137
        MediaNodeEvent event2(MediaNodeEvent::AudioSourceRemoved, connection);
138
        sink->notify(&event2, false);
139
        
140
        delete connection;
141
        return true;
142
    }
143
144
    if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
145
        m_videoSinkList.removeOne(sink);
146
147
        MediaNodeEvent event1(MediaNodeEvent::VideoSinkRemoved, sink);
148
        notify(&event1, false);
149
        MediaNodeEvent event2(MediaNodeEvent::VideoSourceRemoved, this);
150
        sink->notify(&event2, false);
151
        return true;
152
    }
153
154
    return false;
155
}
156
157
int MediaNode::availableAudioInputBus()
158
{
159
    // Scan through all the connection <u>in</u> to this
160
    // node, and find an awailable index:
161
    int index = -1;
162
    bool available = false;
163
164
    while (!available){
165
        ++index;
166
        available = true;
167
        for (int i=0; i<m_audioSourceList.size(); ++i){
168
            if (m_audioSourceList[i]->m_sinkInputBus == index){
169
                available = false;
170
                break;
171
            }
172
        }
173
    }
174
    return index;
175
}
176
177
int MediaNode::availableAudioOutputBus()
178
{
179
    // Scan through all the connection <u>out</u> from this
180
    // node, and find an awailable index:
181
    int bus = -1;
182
    bool available = false;
183
184
    while (!available){
185
        ++bus;
186
        available = true;
187
        for (int i=0; i<m_audioSinkList.size(); ++i){
188
            if (m_audioSinkList[i]->m_sourceOutputBus == bus){
189
                available = false;
190
                break;
191
            }
192
        }
193
    }
194
    return bus;
195
}
196
197
void MediaNode::notify(const MediaNodeEvent *event, bool propagate)
198
{
199
    // Let subclass handle the event first:
200
    mediaNodeEvent(event);
201
202
    switch(event->type()){
203
    case MediaNodeEvent::AudioGraphAboutToBeDeleted:
204
        if (m_audioNode){
205
            foreach(AudioConnection *connection, m_audioSinkList)
206
                connection->invalidate();
207
        }
208
        break;
209
    case MediaNodeEvent::NewAudioGraph:
210
        m_audioGraph = static_cast<AudioGraph *>(event->data());
211
        break;
212
    case MediaNodeEvent::AudioSinkAdded:
213
    case MediaNodeEvent::VideoSinkAdded:
214
        if (m_owningMediaObject){
215
            MediaNodeEvent e1(MediaNodeEvent::SetMediaObject, m_owningMediaObject);
216
            sendEventToSinks(&e1);
217
            QRect videoRect = m_owningMediaObject->videoPlayer()->videoRect();
218
            MediaNodeEvent e2(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
219
            sendEventToSinks(&e2);
220
        }
221
        break;
222
    case MediaNodeEvent::SetMediaObject:
223
        m_owningMediaObject = static_cast<MediaObject *>(event->data());
224
        break;
225
    default:
226
        break;
227
    }
228
229
    // Inform the audio node as well:
230
    if (m_audioNode)
231
        m_audioNode->notify(event);
232
233
    // And perhaps the sinks:
234
    if (propagate)
235
        sendEventToSinks(event);
236
}
237
238
void MediaNode::sendEventToSinks(const MediaNodeEvent *event)
239
{
240
    for (int i=0; i<m_audioSinkList.size(); ++i)
241
        m_audioSinkList[i]->m_sink->notify(event);
242
    for (int i=0; i<m_videoSinkList.size(); ++i)
243
        m_videoSinkList[i]->notify(event);
244
}
245
246
void MediaNode::updateVideo(VideoFrame &frame){
247
    for (int i=0; i<m_videoSinkList.size(); ++i)
248
        m_videoSinkList[i]->updateVideo(frame);
249
}
250
251
void MediaNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
252
{
253
   // Override if needed.
254
}
255
256
}} //namespace Phonon::QT7
257
258
QT_END_NAMESPACE
259
260
#include "moc_medianode.cpp"