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
#import <QTKit/QTMovie.h>
19
20
#include "mediaobjectaudionode.h"
21
#include "quicktimeaudioplayer.h"
22
#include "quicktimevideoplayer.h"
23
#include "audiomixer.h"
24
25
QT_BEGIN_NAMESPACE
26
27
namespace Phonon
28
{
29
namespace QT7
30
{
31
32
MediaObjectAudioNode::MediaObjectAudioNode(QuickTimeAudioPlayer *player1, QuickTimeAudioPlayer *player2) : AudioNode(0, 1)
33
{
34
    m_mute = false;
35
    m_player1 = player1;
36
    m_player2 = player2;
37
    m_mixer = new AudioMixerAudioNode();
38
39
    m_connection1 = new AudioConnection(m_player1, 0, m_mixer, 0);
40
    m_connection2 = new AudioConnection(m_player2, 0, m_mixer, 1);
41
42
    m_fadeDuration = 0;
43
}
44
45
MediaObjectAudioNode::~MediaObjectAudioNode()
46
{
47
    setGraph(0);
48
    delete m_player1;
49
    delete m_player2;
50
    delete m_mixer;
51
    delete m_connection1;
52
    delete m_connection2;
53
}
54
55
void MediaObjectAudioNode::createAndConnectAUNodes()
56
{
57
    DEBUG_AUDIO_GRAPH("(MediaObjectAudioNode" << int(this) << "createAndConnectAUNodes called)" )
58
    m_player1->createAndConnectAUNodes();
59
    m_player2->createAndConnectAUNodes();
60
    m_mixer->createAndConnectAUNodes();
61
62
    m_connection1->connect(m_audioGraph);
63
    m_connection2->connect(m_audioGraph);
64
}
65
66
void MediaObjectAudioNode::createAudioUnits()
67
{
68
    DEBUG_AUDIO_GRAPH("(MediaObjectAudioNode" << int(this) << "createAudioUnits called)" )
69
    m_player1->createAudioUnits();
70
    m_player2->createAudioUnits();
71
    m_mixer->createAudioUnits();
72
}
73
74
void MediaObjectAudioNode::setGraph(AudioGraph *audioGraph)
75
{
76
    DEBUG_AUDIO_GRAPH("MediaObjectAudioNode" << int(this) << "is setting graph:" << int(audioGraph))
77
    m_audioGraph = audioGraph;
78
    m_player1->setGraph(audioGraph);
79
    m_player2->setGraph(audioGraph);
80
    m_mixer->setGraph(audioGraph);
81
}
82
83
AUNode MediaObjectAudioNode::getOutputAUNode()
84
{
85
    return m_mixer->getOutputAUNode();
86
}
87
88
bool MediaObjectAudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
89
{
90
    if (side == Source){
91
        DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "fillInStreamSpecification called, role = source)")
92
        return m_mixer->fillInStreamSpecification(connection, side);
93
    } else {
94
        DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "fillInStreamSpecification called, role = sink)")
95
        return (m_connection2->updateStreamSpecification() && m_connection1->updateStreamSpecification());
96
    }
97
}
98
99
bool MediaObjectAudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side)
100
{
101
    if (side == Source){
102
        DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "setStreamSpecification called, role = source)")
103
        return m_mixer->setStreamSpecification(connection, side);
104
    }
105
    return true;
106
}
107
108
void MediaObjectAudioNode::setMute(bool mute)
109
{
110
    m_mute = mute;
111
    m_mixer->setVolume(m_mute ? 0 : m_volume1, m_connection1->m_sinkInputBus);
112
    m_mixer->setVolume(m_mute ? 0 : m_volume2, m_connection2->m_sinkInputBus);
113
}
114
115
void MediaObjectAudioNode::updateVolume()
116
{
117
    if (m_mute)
118
        return;
119
        
120
    QuickTimeVideoPlayer *player1 = static_cast<QuickTimeAudioPlayer *>(m_connection1->m_sourceAudioNode)->videoPlayer();
121
    QuickTimeVideoPlayer *player2 = static_cast<QuickTimeAudioPlayer *>(m_connection2->m_sourceAudioNode)->videoPlayer();
122
    if (player1)
123
        player1->setRelativeVolume(m_volume1);
124
    if (player2)
125
        player2->setRelativeVolume(m_volume2);
126
127
    m_mixer->setVolume(m_volume1, m_connection1->m_sinkInputBus);
128
    m_mixer->setVolume(m_volume2, m_connection2->m_sinkInputBus);
129
}
130
131
void MediaObjectAudioNode::startCrossFade(qint64 duration)
132
{
133
    m_fadeDuration = duration;
134
135
    // Swap:
136
    AudioConnection *tmp = m_connection1;
137
    m_connection1 = m_connection2;
138
    m_connection2 = tmp;
139
140
    // Init volume:
141
    if (m_fadeDuration > 0){
142
        m_volume1 = 0;
143
        m_volume2 = 1;
144
    } else {
145
        m_volume1 = 1;
146
        m_volume2 = 0;
147
    }
148
    updateVolume();
149
}
150
151
float MediaObjectAudioNode::applyCurve(float volume)
152
{
153
    float newValue = 0;
154
    if (volume > 0)
155
        newValue = float(0.5f * (2 + log10(volume)));
156
    return newValue;
157
}
158
159
void MediaObjectAudioNode::updateCrossFade(qint64 currentTime)
160
{
161
    // Assume that currentTime starts at 0 and progress.
162
    if (m_fadeDuration > 0){
163
        float volume = float(currentTime) / float(m_fadeDuration);
164
        if (volume >= 1){
165
            volume = 1;
166
            m_fadeDuration = 0;
167
        }
168
        m_volume1 = applyCurve(volume);
169
        m_volume2 = 1 - volume;
170
        updateVolume();
171
    }
172
}
173
174
bool MediaObjectAudioNode::isCrossFading()
175
{
176
    return (m_fadeDuration > 0);
177
}
178
179
void MediaObjectAudioNode::cancelCrossFade()
180
{
181
    m_fadeDuration = 0;
182
    m_volume1 = 1;
183
    m_volume2 = 0;
184
    updateVolume();
185
}
186
187
void MediaObjectAudioNode::mediaNodeEvent(const MediaNodeEvent *event)
188
{
189
    switch (event->type()){
190
    case MediaNodeEvent::AudioGraphAboutToBeDeleted:
191
        m_connection1->invalidate();
192
        m_connection2->invalidate();
193
        break;
194
    case MediaNodeEvent::AudioGraphCannotPlay:
195
    case MediaNodeEvent::AudioGraphInitialized:
196
        updateVolume();
197
        break;
198
    default:
199
        break;
200
    }
201
202
    m_player1->mediaNodeEvent(event);
203
    m_player2->mediaNodeEvent(event);
204
    m_mixer->mediaNodeEvent(event);
205
}
206
207
}} //namespace Phonon::QT7
208
209
QT_END_NAMESPACE