diff -r 000000000000 -r 1918ee327afb src/3rdparty/phonon/qt7/audionode.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/3rdparty/phonon/qt7/audionode.mm Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,242 @@ +/* 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 "audionode.h" +#include "audiograph.h" +#include "audioconnection.h" +#include "medianode.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace QT7 +{ + +AudioNode::AudioNode(int maxInputBusses, int maxOutputBusses) +{ + m_auNode = 0; + m_audioUnit = 0; + m_audioGraph = 0; + m_maxInputBusses = maxInputBusses; + m_maxOutputBusses = maxOutputBusses; + m_lastConnectionIn = 0; +} + +AudioNode::~AudioNode() +{ + setGraph(0); +} + +void AudioNode::setGraph(AudioGraph *audioGraph) +{ + if (m_audioGraph == audioGraph) + return; + + DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "is setting graph:" << int(audioGraph)) + if (m_auNode){ + AUGraphRemoveNode(m_audioGraph->audioGraphRef(), m_auNode); + m_auNode = 0; + } + + m_audioUnit = 0; + m_lastConnectionIn = 0; + m_audioGraph = audioGraph; +} + +void AudioNode::createAndConnectAUNodes() +{ + if (m_auNode) + return; + + ComponentDescription description = getAudioNodeDescription(); + DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AUNode" + << QString(!FindNextComponent(0, &description) ? "ERROR: COMPONENT NOT FOUND!" : "OK!")) + + OSStatus err = noErr; + + // The proper function to call here is AUGraphAddNode() but the type has + // changed between 10.5 and 10.6. it's still OK to call this function, but + // if we want to use the proper thing we need to move over to + // AudioComponentDescription everywhere, which is very similar to the + // ComponentDescription, but a different size. however, + // AudioComponentDescription only exists on 10.6+. More fun than we need to + // deal with at the moment, so we'll take the "deprecated" warning instead. + err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode); + BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR) + BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR) +} + +AUNode AudioNode::getInputAUNode() +{ + return m_auNode; +} + +AUNode AudioNode::getOutputAUNode() +{ + return m_auNode; +} + +void AudioNode::createAudioUnits() +{ + if (m_audioUnit) + return; + + DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AudioUnit") + OSStatus err = AUGraphGetNodeInfo(m_audioGraph->audioGraphRef(), m_auNode, 0, 0, 0, &m_audioUnit); + BACKEND_ASSERT2(err == noErr, "Could not get audio unit from audio node.", FATAL_ERROR) + initializeAudioUnit(); +} + +ComponentDescription AudioNode::getAudioNodeDescription() const +{ + // Override if needed. + ComponentDescription cd; + Q_UNUSED(cd); + return cd; +} + +bool AudioNode::setStreamHelp(AudioConnection *c, int bus, OSType scope, bool fromSource) +{ + if (fromSource){ + OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope, + bus, &c->m_sourceStreamDescription, sizeof(AudioStreamBasicDescription)); + if (err != noErr){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format") + return false; + } + AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, + bus, c->m_sourceChannelLayout, c->m_sourceChannelLayoutSize); + } else { + OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope, + bus, &c->m_sinkStreamDescription, sizeof(AudioStreamBasicDescription)); + if (err != noErr){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format") + return false; + } + AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, + bus, c->m_sinkChannelLayout, c->m_sourceChannelLayoutSize); + } + return true; +} + +bool AudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side) +{ + if (side == Source){ + // This object am source of connection: + if (connection->m_hasSourceSpecification){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification out" + << connection->m_sourceOutputBus << "from connection source") + return setStreamHelp(connection, connection->m_sourceOutputBus, kAudioUnitScope_Output, true); + } else { + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification out") + } + } else { + if (connection->m_hasSinkSpecification){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification" + << connection->m_sinkInputBus << "from connection sink") + return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, false); + } else if (connection->m_hasSourceSpecification){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification" + << connection->m_sinkInputBus << "from connection source") + return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, true); + } else { + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification in") + } + } + return true; +} + +bool AudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side) +{ + if (side == Source){ + // As default, use the last description to describe the source: + if (m_lastConnectionIn->m_hasSinkSpecification){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection sink.") + connection->m_sourceStreamDescription = m_lastConnectionIn->m_sinkStreamDescription; + connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sinkChannelLayoutSize); + memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sinkChannelLayout, m_lastConnectionIn->m_sinkChannelLayoutSize); + connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sinkChannelLayoutSize; + connection->m_hasSourceSpecification = true; + } else if (m_lastConnectionIn->m_hasSourceSpecification){ + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection source.") + connection->m_sourceStreamDescription = m_lastConnectionIn->m_sourceStreamDescription; + connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sourceChannelLayoutSize); + memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayoutSize); + connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sourceChannelLayoutSize; + connection->m_hasSourceSpecification = true; + } else { + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " __WARNING__: could not get stream specification...") + } + } else { + DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is sink, skips filling in stream.") + if (!connection->isSinkOnly()) + m_lastConnectionIn = connection; + } + return true; +} + +/** + Let timeProperty be one of e.g + {kAudioUnitProperty_Latency, kAudioUnitProperty_TailTime, + kAudioOutputUnitProperty_StartTime, kAudioUnitProperty_CurrentPlayTime} +*/ +Float64 AudioNode::getTimeInSamples(int timeProperty) +{ + if (!m_audioUnit) + return 0; + + AudioTimeStamp timeStamp; + UInt32 size = sizeof(timeStamp); + memset(&timeStamp, 0, sizeof(timeStamp)); + OSStatus err = AudioUnitGetProperty(m_audioUnit, + timeProperty, kAudioUnitScope_Global, + 0, &timeStamp, &size); + if (err != noErr) + return 0; + return timeStamp.mSampleTime; +} + +void AudioNode::notify(const MediaNodeEvent *event) +{ + switch(event->type()){ + case MediaNodeEvent::AudioGraphAboutToBeDeleted: + setGraph(0); + break; + case MediaNodeEvent::NewAudioGraph: + setGraph(static_cast(event->data())); + break; + default: + break; + } + + mediaNodeEvent(event); +} + +void AudioNode::mediaNodeEvent(const MediaNodeEvent */*event*/) +{ + // Override if needed +} + +void AudioNode::initializeAudioUnit() +{ + // Override if needed. +} + +}} //namespace Phonon::QT7 + +QT_END_NAMESPACE