1
/* This file is part of the KDE project.
3
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
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.
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.
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/>.
18
/*****************************************
20
* This is an aRts plugin for GStreamer
22
****************************************/
25
#include <gst/audio/audio.h>
26
#include <gst/audio/gstaudiosink.h>
36
static GstStaticPadTemplate sinktemplate =
37
GST_STATIC_PAD_TEMPLATE ("sink",
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 ]"
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)();
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;
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);
79
static gboolean connected = false;
80
static gboolean init = false;
83
GST_BOILERPLATE (ArtsSink, arts_sink, GstAudioSink, GST_TYPE_AUDIO_SINK)
92
/* open the device with given specs */
93
gboolean arts_sink_open(GstAudioSink *sink)
97
// We already have an open connection to this device
99
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), ("Could not connect to aRts", NULL));
101
} else if (connected) {
102
GST_ELEMENT_ERROR (sink, RESOURCE, BUSY, (NULL), ("Device is busy", NULL));
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))
111
// Check if arts_init succeeded
118
/* prepare resources and state to operate with the given specs */
119
static gboolean arts_sink_prepare(GstAudioSink *sink, GstRingBufferSpec *spec)
121
ArtsSink *asink = (ArtsSink*)sink;
126
asink->samplerate = spec->rate;
127
asink->samplebits = spec->depth;
128
asink->channels = spec->channels;
129
asink->bytes_per_sample = spec->bytes_per_sample;
132
asink->stream = p_arts_play_stream(spec->rate, spec->depth, spec->channels,
133
QString("gstreamer-%0").arg(id++).toLatin1().constData());
140
/* undo anything that was done in prepare() */
141
static gboolean arts_sink_unprepare(GstAudioSink *sink)
144
ArtsSink *asink = (ArtsSink*)sink;
145
if (init && connected) {
146
p_arts_close_stream(asink->stream);
152
/* close the device */
153
static gboolean arts_sink_close(GstAudioSink *sink)
159
/* write samples to the device */
160
static guint arts_sink_write(GstAudioSink *sink, gpointer data, guint length)
162
ArtsSink *asink = (ArtsSink*)sink;
167
int errorcode = p_arts_write(asink->stream, (char*)data, length);
170
GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Could not write to device.", NULL));
172
return errorcode > 0 ? errorcode : 0;
175
/* get number of samples queued in the device */
176
static guint arts_sink_delay(GstAudioSink *sink)
178
ArtsSink *asink = (ArtsSink*)sink;
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);
187
/* reset the audio device, unblock from a write */
188
static void arts_sink_reset(GstAudioSink *sink)
190
// ### We are currently unable to gracefully recover
191
// after artsd has been restarted or killed.
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,
206
gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sinktemplate));
207
gst_element_class_set_details (gstelement_class, &details);
210
static void arts_sink_class_init (ArtsSinkClass * klass)
212
parent_class = (GstAudioSinkClass*)g_type_class_peek_parent(klass);
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);
218
GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
219
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (arts_sink_get_caps);
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);
231
static void arts_sink_init (ArtsSink * src, ArtsSinkClass * g_class)
234
GST_DEBUG_OBJECT (src, "initializing artssink");
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");
247
int errorcode = p_arts_init();
253
#endif //QT_NO_LIBRARY
256
static void arts_sink_dispose (GObject * object)
259
if (--sinkCount == 0) {
264
static void arts_sink_finalize (GObject * object)
266
G_OBJECT_CLASS (parent_class)->finalize (object);
269
static GstCaps *arts_sink_get_caps (GstBaseSink * bsink)
276
} //namespace Phonon::Gstreamer