~ubuntu-branches/ubuntu/oneiric/phonon/oneiric-201108111512

« back to all changes in this revision

Viewing changes to xine/audiodataoutput.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
 
    Copyright (C) 2004 Max Howell <max.howell@methylblue.com>
3
 
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
4
 
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
5
 
 
6
 
    This program is free software; you can redistribute it and/or
7
 
    modify it under the terms of the GNU Library General Public
8
 
    License as published by the Free Software Foundation; either
9
 
    version 2 of the License, or (at your option) any later version.
10
 
 
11
 
    This library is distributed in the hope that it will be useful,
12
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 
    Library General Public License for more details.
15
 
 
16
 
    You should have received a copy of the GNU Library General Public License
17
 
    along with this library; see the file COPYING.LIB.  If not, write to
18
 
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
 
    Boston, MA 02110-1301, USA.
20
 
 
21
 
*/
22
 
 
23
 
#include "audiodataoutput.h"
24
 
#include "mediaobject.h"
25
 
 
26
 
 
27
 
namespace Phonon
28
 
{
29
 
namespace Xine
30
 
{
31
 
 
32
 
 
33
 
AudioDataOutputXT::AudioDataOutputXT(AudioDataOutput *output) :
34
 
                    SinkNodeXT("AudioDataOutput"),
35
 
                    SourceNodeXT("AudioDataOutput"),
36
 
                    m_frontend(output),
37
 
                    m_audioPort(0),
38
 
                    m_postOutput(0)
39
 
{
40
 
    m_xine = Backend::xine();
41
 
 
42
 
    m_firstVpts = -1;
43
 
 
44
 
    // Dummy audio port, until we get the proper one
45
 
    xine_audio_port_t *port = xine_open_audio_driver(m_xine, "none", 0);
46
 
 
47
 
    // Allocate a new scope plugin
48
 
    m_plugin = (scope_plugin_t*)qMalloc(sizeof(scope_plugin_t));
49
 
 
50
 
    // It is also a post plugin
51
 
    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;
52
 
 
53
 
    //1 audio input, 0 video inputs
54
 
    _x_post_init(post_plugin, 1, 0);
55
 
 
56
 
    // Intercept the null audio port (until we get the proper one)
57
 
    intercept(port, true);
58
 
 
59
 
    /* code is straight from xine_init_post()
60
 
       can't use that function as it only dlopens the plugins
61
 
       and our plugin is statically linked in */
62
 
    post_plugin->running_ticket = (*m_xine).port_ticket;
63
 
    post_plugin->xine = m_xine;
64
 
 
65
 
    // Store a reference to our own object in the post plugin struct
66
 
    m_plugin->audioDataOutput = this;
67
 
}
68
 
 
69
 
AudioDataOutputXT::~AudioDataOutputXT()
70
 
{
71
 
    //xine_post_dispose(m_xine, &((post_plugin_t*)m_plugin)->xine_post); //TODO
72
 
    delete m_plugin;
73
 
}
74
 
 
75
 
/// Rewires this node to the specified sourcenode. I don't think this is ever used (properly).
76
 
void AudioDataOutputXT::rewireTo(SourceNodeXT *source)
77
 
{
78
 
    debug() << Q_FUNC_INFO << "rewiring to " << source;
79
 
    if (!source->audioOutputPort()) { // I can't get no satisfaction
80
 
        debug() << Q_FUNC_INFO << " no audioport in source";
81
 
        return;
82
 
    }
83
 
 
84
 
    // Make sure the source is sane
85
 
    source->assert();
86
 
 
87
 
    // Get the audio input port in our post plugin
88
 
    xine_post_in_t *target = (xine_post_in_t*)xine_post_input(
89
 
                                    &((post_plugin_t*)m_plugin)->xine_post,
90
 
                                    const_cast<char*>("audio in"));
91
 
 
92
 
    if (!xine_post_wire(source->audioOutputPort(), target)) {
93
 
        qWarning() << Q_FUNC_INFO << ": Failed to rewire!";
94
 
        return;
95
 
    }
96
 
    m_postOutput = source->audioOutputPort();
97
 
    m_xtSink->rewireTo(source);
98
 
 
99
 
    // Make sure things went okay
100
 
    source->assert();
101
 
    SinkNodeXT::assert();
102
 
}
103
 
 
104
 
/// Returns this Source's audio output port. Don't think this is used either.
105
 
xine_post_out_t *AudioDataOutputXT::audioOutputPort() const
106
 
{
107
 
    return m_postOutput;
108
 
}
109
 
 
110
 
/// Intercepts a given Xine audio port (called from AudioOutput)
111
 
void AudioDataOutputXT::intercept(xine_audio_port_t *p, bool isNull)
112
 
{
113
 
    if (p == m_audioPort) // we're already intercepting this one
114
 
        return;
115
 
    m_audioPort = p;
116
 
 
117
 
    post_in_t  *input;
118
 
    post_out_t *output;
119
 
 
120
 
    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;
121
 
 
122
 
    // Populate the port with dummy functions
123
 
    post_audio_port_t *port = _x_post_intercept_audio_port(post_plugin, m_audioPort, &input, &output);
124
 
    /* TODO:
125
 
     *  Do we leak these ports? Or is the Xine reference counting enough?
126
 
     *  Stay tuned for valgrind and interesting questions!
127
 
     */
128
 
 
129
 
    if (!port) {
130
 
        qWarning() << Q_FUNC_INFO << "unable to allocate port! (out of memory?)";
131
 
        delete post_plugin;
132
 
        return;
133
 
    }
134
 
 
135
 
    // Put in our own callbacks
136
 
    port->new_port.open       = openPort;
137
 
    port->new_port.close      = closePort;
138
 
    port->new_port.put_buffer = putBufferCallback;
139
 
 
140
 
    // Store the audio port for future use
141
 
    m_audioPort = &port->new_port;
142
 
 
143
 
    // Wire in the port input into our post plugin
144
 
    post_plugin->xine_post.audio_input[0] = &port->new_port;
145
 
    post_plugin->xine_post.type = PLUGIN_POST;
146
 
 
147
 
    if (isNull)
148
 
        m_frontend->m_keepInSync = false;
149
 
    else
150
 
        m_frontend->m_keepInSync = true;
151
 
}
152
 
 
153
 
/// Callback function, opens the xine port
154
 
int AudioDataOutputXT::openPort(xine_audio_port_t *port_gen,
155
 
                                xine_stream_t *stream,
156
 
                                uint32_t bits,
157
 
                                uint32_t rate,
158
 
                                int mode)
159
 
{
160
 
    // Reference to the relevant object
161
 
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;
162
 
 
163
 
    post_audio_port_t *port = (post_audio_port_t*)port_gen;
164
 
 
165
 
    _x_post_rewire((post_plugin_t*)port->post);
166
 
    _x_post_inc_usage(port);
167
 
 
168
 
    port->stream = stream;
169
 
    port->bits = bits;
170
 
    port->rate = rate;
171
 
    port->mode = mode;
172
 
 
173
 
    // Set the new audio stream parameters
174
 
    that->m_channels = _x_ao_mode2channels(mode);
175
 
    that->m_frontend->setChannels(that->m_channels);
176
 
    that->m_frontend->m_sampleRate = rate;
177
 
 
178
 
    return port->original_port->open(port->original_port, stream, bits, rate, mode);
179
 
}
180
 
 
181
 
/// Callback function, closes the xine port
182
 
void AudioDataOutputXT::closePort(xine_audio_port_t *port_gen, xine_stream_t *stream)
183
 
{
184
 
    debug() << Q_FUNC_INFO << " closing port " << port_gen;
185
 
    post_audio_port_t *port = (post_audio_port_t*)port_gen;
186
 
 
187
 
    // This is the same as closing the port, according to comments in the Xine source
188
 
    port->stream = NULL;
189
 
    port->original_port->close(port->original_port, stream);
190
 
 
191
 
    // Decrease the reference counter in the port
192
 
    _x_post_dec_usage(port);
193
 
}
194
 
 
195
 
/// Callback function, receives audio data
196
 
void AudioDataOutputXT::putBufferCallback(xine_audio_port_t * port_gen, audio_buffer_t *buf, xine_stream_t *stream)
197
 
{
198
 
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;
199
 
 
200
 
    // Get the number of samples (audio frames * audio channels)
201
 
    int samples = buf->num_frames * that->m_channels;
202
 
 
203
 
    // Present the audio data to our frontend
204
 
    that->m_frontend->packetReady(samples, buf->mem, buf->vpts);
205
 
 
206
 
    /* Send the audio buffer back to the original port.
207
 
       This notifies Xine that we have finished processing
208
 
       this buffer, so Xine can give us a new one */
209
 
    post_audio_port_t *port = (post_audio_port_t*)port_gen;
210
 
    port->original_port->put_buffer(port->original_port, buf, stream);
211
 
}
212
 
 
213
 
 
214
 
/* BACKEND-FRONT OBJECT */
215
 
AudioDataOutput::AudioDataOutput(QObject*)
216
 
: SinkNode(new AudioDataOutputXT(this))
217
 
, SourceNode(static_cast<AudioDataOutputXT *>(SinkNode::m_threadSafeObject.data()))
218
 
, m_mediaObject(0)
219
 
{
220
 
    m_keepInSync = false;
221
 
    m_sampleRate = 44100;
222
 
}
223
 
 
224
 
AudioDataOutput::~AudioDataOutput()
225
 
{
226
 
    //K_XT(AudioDataOutput);
227
 
    //delete xt;
228
 
}
229
 
 
230
 
inline void AudioDataOutput::packetReady(const int samples, const qint16 *buffer, const qint64 vpts)
231
 
{
232
 
    if (m_channels < 0 || m_channels > 2)
233
 
        return;
234
 
 
235
 
    // Check if it has been cleared
236
 
    if (m_pendingFrames.isEmpty())
237
 
        m_pendingFrames.append(Frame());
238
 
 
239
 
    for (int i=0; i<samples; i++) {
240
 
        if (m_pendingFrames.first().map[Phonon::AudioDataOutput::LeftChannel].size() >= m_dataSize) {
241
 
            m_pendingFrames.prepend(Frame());
242
 
            m_pendingFrames.first().timestamp = vpts;
243
 
 
244
 
            // Tell the QVector how much data we're expecting, speeds things up a bit
245
 
            m_pendingFrames.first().map[Phonon::AudioDataOutput::LeftChannel].reserve(m_dataSize);
246
 
            if (m_channels == 2)
247
 
                m_pendingFrames.first().map[Phonon::AudioDataOutput::RightChannel].reserve(m_dataSize);
248
 
        }
249
 
 
250
 
        m_pendingFrames.first().map[Phonon::AudioDataOutput::LeftChannel].append(buffer[i]);
251
 
        if (m_channels == 2)
252
 
            m_pendingFrames.first().map[Phonon::AudioDataOutput::RightChannel].append(buffer[i++]);
253
 
    }
254
 
 
255
 
    // Are we supposed to keep our signals in sync?
256
 
    if (m_keepInSync) {
257
 
        /*while (m_mediaObject && !m_pendingFrames.isEmpty() &&
258
 
               m_pendingFrames.first().timestamp < m_mediaObject->stream()->currentVpts() &&
259
 
               m_pendingFrames.first().map[Phonon::AudioDataOutput::LeftChannel].size() >= m_dataSize) {
260
 
            emit dataReady(m_pendingFrames.takeFirst().map);
261
 
        }*/
262
 
        for (int i=0; i<m_pendingFrames.size(); i++) {
263
 
            if (m_pendingFrames[i].timestamp < m_mediaObject->stream()->currentVpts() &&
264
 
                m_pendingFrames[i].map[Phonon::AudioDataOutput::LeftChannel].size() >= m_dataSize) {
265
 
                emit dataReady(m_pendingFrames.takeAt(i).map);
266
 
            }
267
 
        }
268
 
    } else { // Fire at will, as long as there is enough data
269
 
        while (!m_pendingFrames.isEmpty() &&
270
 
               m_pendingFrames.last().map[Phonon::AudioDataOutput::LeftChannel].size() >= m_dataSize)
271
 
            emit dataReady(m_pendingFrames.takeLast().map);
272
 
    }
273
 
}
274
 
 
275
 
/// Handle events (basically just pass it on)
276
 
void AudioDataOutput::upstreamEvent(Event *e)
277
 
{
278
 
    Q_ASSERT(e);
279
 
    if (e->type() == Event::IsThereAXineEngineForMe) {
280
 
        // yes there is
281
 
        MediaObject *mediaObject = dynamic_cast<MediaObject*>(m_source); //TODO; qobject_cast?
282
 
        if (mediaObject) {
283
 
            SourceNode::downstreamEvent(new HeresYourXineStreamEvent(mediaObject->stream()));
284
 
            m_mediaObject = mediaObject;
285
 
        }
286
 
    } else
287
 
        SourceNode::upstreamEvent(e);
288
 
}
289
 
 
290
 
}} //namespace Phonon::Xine
291
 
 
292
 
#include "audiodataoutput.moc"
293
 
// vim: sw=4 ts=4