src/3rdparty/phonon/qt7/audionode.mm
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 
       
    23 QT_BEGIN_NAMESPACE
       
    24 
       
    25 namespace Phonon
       
    26 {
       
    27 namespace QT7
       
    28 {
       
    29 
       
    30 AudioNode::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 
       
    40 AudioNode::~AudioNode()
       
    41 {
       
    42     setGraph(0);
       
    43 }
       
    44 
       
    45 void 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 
       
    61 void 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 
       
    84 AUNode AudioNode::getInputAUNode()
       
    85 {
       
    86     return m_auNode;
       
    87 }
       
    88 
       
    89 AUNode AudioNode::getOutputAUNode()
       
    90 {
       
    91     return m_auNode;
       
    92 }
       
    93 
       
    94 void 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 
       
   105 ComponentDescription AudioNode::getAudioNodeDescription() const
       
   106 {
       
   107     // Override if needed.
       
   108     ComponentDescription cd;
       
   109     Q_UNUSED(cd);
       
   110     return cd;
       
   111 }
       
   112 
       
   113 bool 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 
       
   137 bool 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 
       
   164 bool 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 */
       
   198 Float64 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 
       
   214 void 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 
       
   230 void AudioNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
       
   231 {
       
   232     // Override if needed
       
   233 }
       
   234 
       
   235 void AudioNode::initializeAudioUnit()
       
   236 {
       
   237     // Override if needed.
       
   238 }
       
   239 
       
   240 }} //namespace Phonon::QT7
       
   241 
       
   242 QT_END_NAMESPACE