1
/*  This file is part of the KDE project
2
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
3
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
4
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Lesser General Public
7
    License as published by the Free Software Foundation; either
8
    version 2.1 of the License, or (at your option) version 3, or any
9
    later version accepted by the membership of KDE e.V. (or its
10
    successor approved by the membership of KDE e.V.), Nokia Corporation
11
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
12
    act as a proxy defined in Section 6 of version 3 of the license.
13
14
    This library is distributed in the hope that it will be useful,
15
    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
    Lesser General Public License for more details.
18
19
    You should have received a copy of the GNU Lesser General Public
20
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
21
22
*/
23
24
#include "audiodataoutput.h"
25
#include "gsthelper.h"
26
#include "medianode.h"
27
#include "mediaobject.h"
28
#include <QtCore/QVector>
29
#include <QtCore/QMap>
30
#include <phonon/audiooutput.h>
31
32
QT_BEGIN_HEADER
33
QT_BEGIN_NAMESPACE
34
35
namespace Phonon
36
{
37
namespace Gstreamer
38
{
39
AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent)
40
    : QObject(parent),
41
    MediaNode(backend, AudioSink | AudioSource)
42
{
43
    static int count = 0;
44
    m_name = "AudioDataOutput" + QString::number(count++);
45
46
    m_queue = gst_element_factory_make ("identity", NULL);
47
    gst_object_ref(m_queue);
48
    m_isValid = true;
49
}
50
51
AudioDataOutput::~AudioDataOutput()
52
{
53
    gst_element_set_state(m_queue, GST_STATE_NULL);
54
    gst_object_unref(m_queue);
55
}
56
57
int AudioDataOutput::dataSize() const
58
{
59
    return m_dataSize;
60
}
61
62
int AudioDataOutput::sampleRate() const
63
{
64
    return 44100;
65
}
66
67
void AudioDataOutput::setDataSize(int size)
68
{
69
    m_dataSize = size;
70
}
71
72
typedef QMap<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
73
typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;
74
75
inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &rightBuffer)
76
{
77
    //TODO: Floats
78
    IntMap map;
79
    map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer);
80
    map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer);
81
    emit dataReady(map);
82
}
83
84
void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat)
85
{
86
    // TODO emit endOfMedia
87
    AudioDataOutput *that = reinterpret_cast<AudioDataOutput*>(gThat);
88
89
    // determine the number of channels
90
    GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0);
91
    gst_structure_get_int (structure, "channels", &that->m_channels);
92
93
    if (that->m_channels > 2 || that->m_channels < 0) {
94
        qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels;
95
        return;
96
    }
97
98
    gint16 *data = reinterpret_cast<gint16*>(GST_BUFFER_DATA(buffer));
99
    guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16);
100
101
    that->m_pendingData.reserve(that->m_pendingData.size() + size);
102
103
    for (uint i=0; i<size; i++) {
104
        // 8 bit? interleaved? yay for lacking documentation!
105
        that->m_pendingData.append(data[i]);
106
    }
107
108
    while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
109
        if (that->m_channels == 1) {
110
            QVector<qint16> intBuffer(that->m_dataSize);
111
            memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16));
112
113
            that->convertAndEmit(intBuffer, intBuffer);
114
            int newSize = that->m_pendingData.size() - that->m_dataSize;
115
            memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16));
116
            that->m_pendingData.resize(newSize);
117
        } else {
118
            QVector<qint16> left(that->m_dataSize), right(that->m_dataSize);
119
            for (int i=0; i<that->m_dataSize; i++) {
120
                left[i] = that->m_pendingData[i*2];
121
                right[i] = that->m_pendingData[i*2+1];
122
            }
123
            that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2);
124
            that->convertAndEmit(left, right);
125
        }
126
    }
127
}
128
129
void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event)
130
{
131
    if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) {
132
        g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL);
133
        GstPad *audiopad = gst_element_get_pad (audioElement(), "src");
134
        gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this);
135
        gst_object_unref (audiopad);
136
        return;
137
    }
138
139
    MediaNode::mediaNodeEvent(event);
140
}
141
142
}} //namespace Phonon::Gstreamer
143
144
QT_END_NAMESPACE
145
QT_END_HEADER
146
147
#include "moc_audiodataoutput.cpp"
148
// vim: sw=4 ts=4