/* This file is part of the KDE project.
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library. If not, see .
*/
#include "medianode.h"
#include "audiograph.h"
#include "audionode.h"
#include "backendheader.h"
#include "mediaobject.h"
#include "audiooutput.h"
#include "quicktimevideoplayer.h"
QT_BEGIN_NAMESPACE
namespace Phonon
{
namespace QT7
{
MediaNode::MediaNode(NodeDescription description, QObject *parent)
: QObject(parent), m_audioGraph(0), m_audioNode(0), m_description(description), m_owningMediaObject(0)
{
}
MediaNode::MediaNode(NodeDescription description, AudioNode *audioPart, QObject *parent)
: QObject(parent), m_audioGraph(0), m_audioNode(audioPart), m_description(description)
{
}
void MediaNode::setAudioNode(AudioNode *audioPart)
{
if (m_audioNode)
delete m_audioNode;
m_audioNode = audioPart;
}
MediaNode::~MediaNode()
{
delete m_audioNode;
qDeleteAll(m_audioSinkList);
}
AudioConnection *MediaNode::getAudioConnectionToSink(MediaNode *sink)
{
AudioConnection *connection = 0;
for (int i=0; iisBetween(this, sink)){
connection = m_audioSinkList[i];
break;
}
}
return connection;
}
bool MediaNode::connectToSink(MediaNode *sink)
{
if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
// Check that they don't belong to different graphs. If they do, but
// sink is not connected to any source, accept it:
if (m_owningMediaObject && sink->m_owningMediaObject
&& m_owningMediaObject != sink->m_owningMediaObject
&& !sink->m_audioSourceList.isEmpty()){
return false;
}
// Check that the connection doesn't already exists:
AudioConnection *connection = getAudioConnectionToSink(sink);
if (connection)
return true;
// Check that there are awailable input/output busses:
int inputBus = sink->availableAudioInputBus();
int outputBus = availableAudioOutputBus();
if (inputBus >= sink->m_audioNode->m_maxInputBusses || outputBus >= m_audioNode->m_maxOutputBusses)
return false;
// All OK. Create connection:
connection = new AudioConnection(this, outputBus, sink, inputBus);
m_audioSinkList << connection;
sink->m_audioSourceList << connection;
if (m_audioNode->m_audioGraph)
m_audioNode->m_audioGraph->connectLate(connection);
MediaNodeEvent event1(MediaNodeEvent::AudioSinkAdded, connection);
notify(&event1, false);
MediaNodeEvent event2(MediaNodeEvent::AudioSourceAdded, connection);
sink->notify(&event2, false);
return true;
}
if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
// Check that the connection doesn't already exists:
if (m_videoSinkList.contains(sink))
return true;
m_videoSinkList << sink;
MediaNodeEvent event1(MediaNodeEvent::VideoSinkAdded, sink);
notify(&event1, false);
MediaNodeEvent event2(MediaNodeEvent::VideoSourceAdded, this);
sink->notify(&event2, false);
return true;
}
return false;
}
bool MediaNode::disconnectToSink(MediaNode *sink)
{
if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
AudioConnection *connection = getAudioConnectionToSink(sink);
if (!connection)
return false;
m_audioSinkList.removeOne(connection);
sink->m_audioSourceList.removeOne(connection);
if (m_audioNode->m_audioGraph)
m_audioNode->m_audioGraph->disconnectLate(connection);
MediaNodeEvent event1(MediaNodeEvent::AudioSinkRemoved, connection);
notify(&event1, false);
MediaNodeEvent event2(MediaNodeEvent::AudioSourceRemoved, connection);
sink->notify(&event2, false);
delete connection;
return true;
}
if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
m_videoSinkList.removeOne(sink);
MediaNodeEvent event1(MediaNodeEvent::VideoSinkRemoved, sink);
notify(&event1, false);
MediaNodeEvent event2(MediaNodeEvent::VideoSourceRemoved, this);
sink->notify(&event2, false);
return true;
}
return false;
}
int MediaNode::availableAudioInputBus()
{
// Scan through all the connection in to this
// node, and find an awailable index:
int index = -1;
bool available = false;
while (!available){
++index;
available = true;
for (int i=0; im_sinkInputBus == index){
available = false;
break;
}
}
}
return index;
}
int MediaNode::availableAudioOutputBus()
{
// Scan through all the connection out from this
// node, and find an awailable index:
int bus = -1;
bool available = false;
while (!available){
++bus;
available = true;
for (int i=0; im_sourceOutputBus == bus){
available = false;
break;
}
}
}
return bus;
}
void MediaNode::notify(const MediaNodeEvent *event, bool propagate)
{
// Let subclass handle the event first:
mediaNodeEvent(event);
switch(event->type()){
case MediaNodeEvent::AudioGraphAboutToBeDeleted:
if (m_audioNode){
foreach(AudioConnection *connection, m_audioSinkList)
connection->invalidate();
}
break;
case MediaNodeEvent::NewAudioGraph:
m_audioGraph = static_cast(event->data());
break;
case MediaNodeEvent::AudioSinkAdded:
case MediaNodeEvent::VideoSinkAdded:
if (m_owningMediaObject){
MediaNodeEvent e1(MediaNodeEvent::SetMediaObject, m_owningMediaObject);
sendEventToSinks(&e1);
QRect videoRect = m_owningMediaObject->videoPlayer()->videoRect();
MediaNodeEvent e2(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
sendEventToSinks(&e2);
}
break;
case MediaNodeEvent::SetMediaObject:
m_owningMediaObject = static_cast(event->data());
break;
default:
break;
}
// Inform the audio node as well:
if (m_audioNode)
m_audioNode->notify(event);
// And perhaps the sinks:
if (propagate)
sendEventToSinks(event);
}
void MediaNode::sendEventToSinks(const MediaNodeEvent *event)
{
for (int i=0; im_sink->notify(event);
for (int i=0; inotify(event);
}
void MediaNode::updateVideo(VideoFrame &frame){
for (int i=0; iupdateVideo(frame);
}
void MediaNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
{
// Override if needed.
}
}} //namespace Phonon::QT7
QT_END_NAMESPACE
#include "moc_medianode.cpp"