~ubuntu-branches/ubuntu/quantal/phonon-backend-gstreamer/quantal

« back to all changes in this revision

Viewing changes to gstreamer/artssink.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2011-04-15 14:43:30 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110415144330-7uif3319lxdu4ltt
Tags: 4:4.7.0really4.5.0-0ubuntu2
* New upstream release
* Add kubuntu_02_install_codec.diff to fix codec install

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
 
 
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
 
/*****************************************
19
 
 *
20
 
 *  This is an aRts plugin for GStreamer
21
 
 *
22
 
 ****************************************/
23
 
 
24
 
#include <gst/gst.h>
25
 
#include <gst/audio/audio.h>
26
 
#include <gst/audio/gstaudiosink.h>
27
 
#include "artssink.h"
28
 
 
29
 
QT_BEGIN_NAMESPACE
30
 
 
31
 
namespace Phonon
32
 
{
33
 
namespace Gstreamer
34
 
{
35
 
 
36
 
static GstStaticPadTemplate sinktemplate =
37
 
GST_STATIC_PAD_TEMPLATE ("sink",
38
 
    GST_PAD_SINK,
39
 
    GST_PAD_ALWAYS,
40
 
    GST_STATIC_CAPS (
41
 
                     "audio/x-raw-int, "
42
 
                     "width = (int) { 8, 16 }, "
43
 
                     "depth = (int) { 8, 16 }, "
44
 
                     "endianness = (int) BYTE_ORDER, "
45
 
                     "channels = (int) { 1, 2 }, "
46
 
                     "rate = (int) [ 8000, 96000 ]"
47
 
                    )
48
 
);
49
 
 
50
 
typedef int (*Ptr_arts_init)();
51
 
typedef arts_stream_t (*Ptr_arts_play_stream)(int, int, int, const char*);
52
 
typedef int (*Ptr_arts_close_stream)(arts_stream_t);
53
 
typedef int (*Ptr_arts_stream_get)(arts_stream_t, arts_parameter_t_enum);
54
 
typedef int (*Ptr_arts_stream_set)(arts_stream_t, arts_parameter_t_enum, int value);
55
 
typedef int (*Ptr_arts_write)(arts_stream_t, const void *, int);
56
 
typedef int (*Ptr_arts_suspended)();
57
 
typedef void (*Ptr_arts_free)();
58
 
 
59
 
static Ptr_arts_init p_arts_init = 0;
60
 
static Ptr_arts_play_stream p_arts_play_stream = 0;
61
 
static Ptr_arts_close_stream p_arts_close_stream = 0;
62
 
static Ptr_arts_stream_get p_arts_stream_get= 0;
63
 
static Ptr_arts_stream_set p_arts_stream_set= 0;
64
 
static Ptr_arts_write p_arts_write = 0;
65
 
static Ptr_arts_suspended p_arts_suspended = 0;
66
 
static Ptr_arts_free p_arts_free = 0;
67
 
 
68
 
static void arts_sink_dispose (GObject * object);
69
 
static void arts_sink_reset (GstAudioSink * asink);
70
 
static void arts_sink_finalize (GObject * object);
71
 
static GstCaps *arts_sink_get_caps (GstBaseSink * bsink);
72
 
static gboolean arts_sink_open (GstAudioSink * asink);
73
 
static gboolean arts_sink_close (GstAudioSink * asink);
74
 
static gboolean arts_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec);
75
 
static gboolean arts_sink_unprepare (GstAudioSink * asink);
76
 
static guint arts_sink_write (GstAudioSink * asink, gpointer data, guint length);
77
 
static guint arts_sink_delay (GstAudioSink * asink);
78
 
 
79
 
static gboolean connected = false;
80
 
static gboolean init = false;
81
 
static int sinkCount;
82
 
 
83
 
GST_BOILERPLATE (ArtsSink, arts_sink, GstAudioSink, GST_TYPE_AUDIO_SINK)
84
 
 
85
 
// ArtsSink args
86
 
enum
87
 
{
88
 
    ARG_0,
89
 
    ARG_ARTSSINK
90
 
};
91
 
 
92
 
/* open the device with given specs */
93
 
gboolean arts_sink_open(GstAudioSink *sink)
94
 
{
95
 
    Q_UNUSED(sink);
96
 
 
97
 
    // We already have an open connection to this device
98
 
    if (!init) {
99
 
        GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), ("Could not connect to aRts", NULL));
100
 
        return false;
101
 
    } else if (connected) {
102
 
        GST_ELEMENT_ERROR (sink, RESOURCE, BUSY, (NULL), ("Device is busy", NULL));
103
 
        return false;
104
 
    }
105
 
 
106
 
    // Check if all symbols were resolved
107
 
    if (!(p_arts_init && p_arts_play_stream && p_arts_close_stream
108
 
         && p_arts_stream_get && p_arts_stream_set && p_arts_write && p_arts_free))
109
 
        return FALSE;
110
 
 
111
 
    // Check if arts_init succeeded
112
 
    if (!init)
113
 
        return false;
114
 
 
115
 
    return true;
116
 
}
117
 
 
118
 
/* prepare resources and state to operate with the given specs */
119
 
static gboolean arts_sink_prepare(GstAudioSink *sink, GstRingBufferSpec *spec)
120
 
{
121
 
    ArtsSink *asink = (ArtsSink*)sink;
122
 
 
123
 
    if (!init)
124
 
        return false;
125
 
 
126
 
    asink->samplerate = spec->rate;
127
 
    asink->samplebits = spec->depth;
128
 
    asink->channels = spec->channels;
129
 
    asink->bytes_per_sample = spec->bytes_per_sample;
130
 
 
131
 
    static int id = 0;
132
 
    asink->stream = p_arts_play_stream(spec->rate, spec->depth, spec->channels,
133
 
                                        QString("gstreamer-%0").arg(id++).toLatin1().constData());
134
 
    if (asink->stream)
135
 
        connected = true;
136
 
 
137
 
    return connected;
138
 
}
139
 
 
140
 
/* undo anything that was done in prepare() */
141
 
static gboolean arts_sink_unprepare(GstAudioSink *sink)
142
 
{
143
 
    Q_UNUSED(sink);
144
 
    ArtsSink *asink = (ArtsSink*)sink;
145
 
    if (init && connected) {
146
 
        p_arts_close_stream(asink->stream);
147
 
        connected = false;
148
 
    }
149
 
    return true;
150
 
}
151
 
 
152
 
/* close the device */
153
 
static gboolean arts_sink_close(GstAudioSink *sink)
154
 
{
155
 
    Q_UNUSED(sink);
156
 
    return true;
157
 
}
158
 
 
159
 
/* write samples to the device */
160
 
static guint arts_sink_write(GstAudioSink *sink, gpointer data, guint length)
161
 
{
162
 
    ArtsSink *asink = (ArtsSink*)sink;
163
 
 
164
 
    if (!init)
165
 
        return 0;
166
 
 
167
 
    int errorcode = p_arts_write(asink->stream, (char*)data, length);
168
 
 
169
 
    if (errorcode < 0)
170
 
        GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Could not write to device.", NULL));
171
 
 
172
 
    return errorcode > 0 ? errorcode : 0;
173
 
}
174
 
 
175
 
/* get number of samples queued in the device */
176
 
static guint arts_sink_delay(GstAudioSink *sink)
177
 
{
178
 
    ArtsSink *asink = (ArtsSink*)sink;
179
 
    if (!init)
180
 
        return 0;
181
 
 
182
 
    // We get results in millisecons so we have to caculate the approximate size in samples
183
 
    guint delay = p_arts_stream_get(asink->stream, ARTS_P_SERVER_LATENCY) * (asink->samplerate / 1000);
184
 
    return delay;
185
 
}
186
 
 
187
 
/* reset the audio device, unblock from a write */
188
 
static void arts_sink_reset(GstAudioSink *sink)
189
 
{
190
 
    // ### We are currently unable to gracefully recover
191
 
    // after artsd has been restarted or killed.
192
 
    Q_UNUSED(sink);
193
 
}
194
 
 
195
 
// Register element details
196
 
static void arts_sink_base_init (gpointer g_class) {
197
 
    GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
198
 
    static gchar longname[] = "Experimental aRts sink",
199
 
                    klass[] = "Sink/Audio",
200
 
              description[] = "aRts Audio Output Device",
201
 
                   author[] = "Nokia Corporation and/or its subsidiary(-ies) <qt-info@nokia.com>";
202
 
    GstElementDetails details = GST_ELEMENT_DETAILS (longname,
203
 
                                          klass,
204
 
                                          description,
205
 
                                          author);
206
 
    gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sinktemplate));
207
 
    gst_element_class_set_details (gstelement_class, &details);
208
 
}
209
 
 
210
 
static void arts_sink_class_init (ArtsSinkClass * klass)
211
 
{
212
 
    parent_class = (GstAudioSinkClass*)g_type_class_peek_parent(klass);
213
 
 
214
 
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
215
 
    gobject_class->finalize = GST_DEBUG_FUNCPTR (arts_sink_finalize);
216
 
    gobject_class->dispose = GST_DEBUG_FUNCPTR (arts_sink_dispose);
217
 
 
218
 
    GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
219
 
    gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (arts_sink_get_caps);
220
 
 
221
 
    GstAudioSinkClass *gstaudiosink_class = (GstAudioSinkClass*)klass;
222
 
    gstaudiosink_class->open =      GST_DEBUG_FUNCPTR(arts_sink_open);
223
 
    gstaudiosink_class->prepare =   GST_DEBUG_FUNCPTR(arts_sink_prepare);
224
 
    gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(arts_sink_unprepare);
225
 
    gstaudiosink_class->close =     GST_DEBUG_FUNCPTR(arts_sink_close);
226
 
    gstaudiosink_class->write =     GST_DEBUG_FUNCPTR(arts_sink_write);
227
 
    gstaudiosink_class->delay =     GST_DEBUG_FUNCPTR(arts_sink_delay);
228
 
    gstaudiosink_class->reset =     GST_DEBUG_FUNCPTR(arts_sink_reset);
229
 
}
230
 
 
231
 
static void arts_sink_init (ArtsSink * src, ArtsSinkClass * g_class)
232
 
{
233
 
    Q_UNUSED(g_class);
234
 
    GST_DEBUG_OBJECT (src, "initializing artssink");
235
 
    src->stream = 0;
236
 
#ifndef QT_NO_LIBRARY
237
 
    p_arts_init =  (Ptr_arts_init)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_init");
238
 
    p_arts_play_stream =  (Ptr_arts_play_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_play_stream");
239
 
    p_arts_close_stream =  (Ptr_arts_close_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_close_stream");
240
 
    p_arts_stream_get =  (Ptr_arts_stream_get)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_stream_get");
241
 
    p_arts_stream_set =  (Ptr_arts_stream_set)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_stream_set");
242
 
    p_arts_write =  (Ptr_arts_write)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_write");
243
 
    p_arts_suspended =  (Ptr_arts_suspended)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_suspended");
244
 
    p_arts_free =  (Ptr_arts_free)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_free");
245
 
 
246
 
    if (!sinkCount) {
247
 
        int errorcode = p_arts_init();
248
 
        if (!errorcode) {
249
 
            init = TRUE;
250
 
        }
251
 
    }
252
 
    sinkCount ++;
253
 
#endif //QT_NO_LIBRARY
254
 
}
255
 
 
256
 
static void arts_sink_dispose (GObject * object)
257
 
{
258
 
    Q_UNUSED(object);
259
 
    if (--sinkCount == 0) {
260
 
        p_arts_free();
261
 
    }
262
 
}
263
 
 
264
 
static void arts_sink_finalize (GObject * object)
265
 
{
266
 
    G_OBJECT_CLASS (parent_class)->finalize (object);
267
 
}
268
 
 
269
 
static GstCaps *arts_sink_get_caps (GstBaseSink * bsink)
270
 
{
271
 
    Q_UNUSED(bsink);
272
 
    return NULL;
273
 
}
274
 
 
275
 
}
276
 
} //namespace Phonon::Gstreamer
277
 
 
278
 
QT_END_NAMESPACE