~ubuntu-branches/ubuntu/natty/phonon/natty

« back to all changes in this revision

Viewing changes to gstreamer/audiooutput.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2011-01-24 10:12:11 UTC
  • mfrom: (0.5.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110124101211-w9rew7q0dmwbwhqx
Tags: 4:4.7.0really4.4.4-0ubuntu1
* New upstream release
* Xine and GStreamer backends now split out source, remove build-deps and
  binary packages from debian/control
* Remove 02_no_rpath.patch, now upstream
* Disable kubuntu04_no_va_mangle.patch, no longer applies
* Remove kubuntu_05_gst_codec_installer_window_id.diff, kubuntu_06_forward_events.diff,
  kubuntu_07_include_fix.diff, gstreamer now separate

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  This file is part of the KDE project.
2
 
 
3
 
    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
 
    Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
5
 
 
6
 
    This library is free software: you can redistribute it and/or modify
7
 
    it under the terms of the GNU Lesser General Public License as published by
8
 
    the Free Software Foundation, either version 2.1 or 3 of the License.
9
 
 
10
 
    This library is distributed in the hope that it will be useful,
11
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
    GNU Lesser General Public License for more details.
14
 
 
15
 
    You should have received a copy of the GNU Lesser General Public License
16
 
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
17
 
*/
18
 
 
19
 
#include "common.h"
20
 
#include "audiooutput.h"
21
 
#include "backend.h"
22
 
#include "devicemanager.h"
23
 
#include "mediaobject.h"
24
 
#include "medianodeevent.h"
25
 
#include "gsthelper.h"
26
 
#include <phonon/audiooutput.h>
27
 
 
28
 
#include <gst/gstbin.h>
29
 
#include <gst/gstghostpad.h>
30
 
#include <gst/gstutils.h>
31
 
 
32
 
QT_BEGIN_NAMESPACE
33
 
 
34
 
namespace Phonon
35
 
{
36
 
namespace Gstreamer
37
 
{
38
 
AudioOutput::AudioOutput(Backend *backend, QObject *parent)
39
 
        : QObject(parent)
40
 
        , MediaNode(backend, AudioSink)
41
 
        , m_volumeLevel(1.0)
42
 
        , m_device(0) // ### get from backend
43
 
        , m_volumeElement(0)
44
 
        , m_audioBin(0)
45
 
        , m_audioSink(0)
46
 
        , m_conv(0)
47
 
{
48
 
    static int count = 0;
49
 
    m_name = "AudioOutput" + QString::number(count++);
50
 
    if (m_backend->isValid()) {
51
 
        m_audioBin = gst_bin_new (NULL);
52
 
        gst_object_ref (GST_OBJECT (m_audioBin));
53
 
        gst_object_sink (GST_OBJECT (m_audioBin));
54
 
 
55
 
        m_conv = gst_element_factory_make ("audioconvert", NULL);
56
 
 
57
 
        // Get category from parent
58
 
        Phonon::Category category = Phonon::NoCategory;
59
 
        if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
60
 
            category = audioOutput->category();
61
 
 
62
 
        m_audioSink = m_backend->deviceManager()->createAudioSink(category);
63
 
        m_volumeElement = gst_element_factory_make ("volume", NULL);
64
 
        GstElement *queue = gst_element_factory_make ("queue", NULL);
65
 
        GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);
66
 
 
67
 
        if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
68
 
            gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);
69
 
 
70
 
            if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
71
 
                // Add ghost sink for audiobin
72
 
                GstPad *audiopad = gst_element_get_pad (queue, "sink");
73
 
                gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
74
 
                gst_object_unref (audiopad);
75
 
                m_isValid = true; // Initialization ok, accept input
76
 
            }
77
 
        }
78
 
    }
79
 
}
80
 
 
81
 
void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
82
 
{
83
 
    if (!m_audioBin)
84
 
        return;
85
 
 
86
 
    switch (event->type()) {
87
 
 
88
 
    default:
89
 
        break;
90
 
    }
91
 
}
92
 
 
93
 
 
94
 
AudioOutput::~AudioOutput()
95
 
{
96
 
    if (m_audioBin) {
97
 
        gst_element_set_state (m_audioBin, GST_STATE_NULL);
98
 
        gst_object_unref (m_audioBin);
99
 
    }
100
 
}
101
 
 
102
 
qreal AudioOutput::volume() const
103
 
{
104
 
    return m_volumeLevel;
105
 
}
106
 
 
107
 
int AudioOutput::outputDevice() const
108
 
{
109
 
    return m_device;
110
 
}
111
 
 
112
 
void AudioOutput::setVolume(qreal newVolume)
113
 
{
114
 
    if (newVolume > 2.0 )
115
 
        newVolume = 2.0;
116
 
    else if (newVolume < 0.0)
117
 
        newVolume = 0.0;
118
 
 
119
 
    if (newVolume == m_volumeLevel)
120
 
        return;
121
 
 
122
 
    m_volumeLevel = newVolume;
123
 
 
124
 
    if (m_volumeElement) {
125
 
        g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
126
 
    }
127
 
 
128
 
    emit volumeChanged(newVolume);
129
 
}
130
 
 
131
 
bool AudioOutput::setOutputDevice(int newDevice)
132
 
{
133
 
    m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
134
 
 
135
 
    if (newDevice == m_device)
136
 
        return true;
137
 
 
138
 
    if (root()) {
139
 
        root()->saveState();
140
 
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
141
 
            return false;
142
 
    }
143
 
 
144
 
    bool success = false;
145
 
    if (m_audioSink &&  newDevice >= 0) {
146
 
        // Save previous state
147
 
        GstState oldState = GST_STATE(m_audioSink);
148
 
        const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
149
 
        const QByteArray deviceId = m_backend->deviceManager()->gstId(newDevice);
150
 
        m_device = newDevice;
151
 
 
152
 
        // We test if the device can be opened by checking if it can go from NULL to READY state
153
 
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
154
 
        success = GstHelper::setProperty(m_audioSink, "device", deviceId);
155
 
        if (success) {
156
 
            success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
157
 
        }
158
 
        if (!success) { // Revert state
159
 
            m_backend->logMessage(Q_FUNC_INFO +
160
 
                                  QLatin1String(" Failed to change device ") +
161
 
                                  deviceId, Backend::Info, this);
162
 
 
163
 
            GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
164
 
            gst_element_set_state(m_audioSink, oldState);
165
 
        } else {
166
 
            m_backend->logMessage(Q_FUNC_INFO +
167
 
                                  QLatin1String(" Successfully changed device ") +
168
 
                                  deviceId, Backend::Info, this);
169
 
        }
170
 
 
171
 
        // Note the stopped state should not really be necessary, but seems to be required to
172
 
        // properly reset after changing the audio state
173
 
        if (root()) {
174
 
            QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
175
 
            root()->resumeState();
176
 
        }
177
 
    }
178
 
    return success;
179
 
}
180
 
 
181
 
#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
182
 
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
183
 
{
184
 
    m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
185
 
    if (!m_audioSink || !newDevice.isValid()) {
186
 
        return false;
187
 
    }
188
 
    const QVariant driver = newDevice.property("driver");
189
 
    if (!driver.isValid()) {
190
 
        return setOutputDevice(newDevice.index());
191
 
    }
192
 
    if (newDevice.index() == m_device) {
193
 
        return true;
194
 
    }
195
 
 
196
 
    if (root()) {
197
 
        root()->saveState();
198
 
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
199
 
            return false;
200
 
    }
201
 
 
202
 
    // Save previous state
203
 
    const GstState oldState = GST_STATE(m_audioSink);
204
 
    const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
205
 
 
206
 
    const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
207
 
    if (sinkName == "alsasink" || sinkName == "alsasink2") {
208
 
        if (driver.toByteArray() != "alsa") {
209
 
            return false;
210
 
        }
211
 
    }
212
 
 
213
 
    const QVariant deviceIdsProperty = newDevice.property("deviceIds");
214
 
    QStringList deviceIds;
215
 
    if (deviceIdsProperty.type() == QVariant::StringList) {
216
 
        deviceIds = deviceIdsProperty.toStringList();
217
 
    } else if (deviceIdsProperty.type() == QVariant::String) {
218
 
        deviceIds += deviceIdsProperty.toString();
219
 
    }
220
 
 
221
 
    // We test if the device can be opened by checking if it can go from NULL to READY state
222
 
    foreach (const QString &deviceId, deviceIds) {
223
 
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
224
 
        if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
225
 
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
226
 
                                  deviceId + QLatin1String(") succeeded"), Backend::Info, this);
227
 
            if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
228
 
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
229
 
                                      deviceId + QLatin1String(" succeeded"), Backend::Info, this);
230
 
                m_device = newDevice.index();
231
 
                if (root()) {
232
 
                    QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
233
 
                    root()->resumeState();
234
 
                }
235
 
                return true;
236
 
            } else {
237
 
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
238
 
                                      deviceId + QLatin1String(" failed"), Backend::Info, this);
239
 
            }
240
 
        } else {
241
 
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
242
 
                                  deviceId + QLatin1String(") failed"), Backend::Info, this);
243
 
        }
244
 
    }
245
 
    // Revert state
246
 
    GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
247
 
    gst_element_set_state(m_audioSink, oldState);
248
 
 
249
 
    if (root()) {
250
 
        QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
251
 
        root()->resumeState();
252
 
    }
253
 
 
254
 
    return false;
255
 
}
256
 
#endif
257
 
 
258
 
}
259
 
} //namespace Phonon::Gstreamer
260
 
 
261
 
QT_END_NAMESPACE
262
 
#include "moc_audiooutput.cpp"