source: trunk/src/3rdparty/phonon/gstreamer/artssink.cpp

Last change on this file was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 9.2 KB
Line 
1/* This file is part of the KDE project.
2
3Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5This library is free software: you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation, either version 2.1 or 3 of the License.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along 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
29QT_BEGIN_NAMESPACE
30
31namespace Phonon
32{
33namespace Gstreamer
34{
35
36static GstStaticPadTemplate sinktemplate =
37GST_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
50typedef int (*Ptr_arts_init)();
51typedef arts_stream_t (*Ptr_arts_play_stream)(int, int, int, const char*);
52typedef int (*Ptr_arts_close_stream)(arts_stream_t);
53typedef int (*Ptr_arts_stream_get)(arts_stream_t, arts_parameter_t_enum);
54typedef int (*Ptr_arts_stream_set)(arts_stream_t, arts_parameter_t_enum, int value);
55typedef int (*Ptr_arts_write)(arts_stream_t, const void *, int);
56typedef int (*Ptr_arts_suspended)();
57typedef void (*Ptr_arts_free)();
58
59static Ptr_arts_init p_arts_init = 0;
60static Ptr_arts_play_stream p_arts_play_stream = 0;
61static Ptr_arts_close_stream p_arts_close_stream = 0;
62static Ptr_arts_stream_get p_arts_stream_get= 0;
63static Ptr_arts_stream_set p_arts_stream_set= 0;
64static Ptr_arts_write p_arts_write = 0;
65static Ptr_arts_suspended p_arts_suspended = 0;
66static Ptr_arts_free p_arts_free = 0;
67
68static void arts_sink_dispose (GObject * object);
69static void arts_sink_reset (GstAudioSink * asink);
70static void arts_sink_finalize (GObject * object);
71static GstCaps *arts_sink_get_caps (GstBaseSink * bsink);
72static gboolean arts_sink_open (GstAudioSink * asink);
73static gboolean arts_sink_close (GstAudioSink * asink);
74static gboolean arts_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec);
75static gboolean arts_sink_unprepare (GstAudioSink * asink);
76static guint arts_sink_write (GstAudioSink * asink, gpointer data, guint length);
77static guint arts_sink_delay (GstAudioSink * asink);
78
79static gboolean connected = false;
80static gboolean init = false;
81static int sinkCount;
82
83GST_BOILERPLATE (ArtsSink, arts_sink, GstAudioSink, GST_TYPE_AUDIO_SINK)
84
85// ArtsSink args
86enum
87{
88 ARG_0,
89 ARG_ARTSSINK
90};
91
92/* open the device with given specs */
93gboolean 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 */
119static 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() */
141static 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 */
153static gboolean arts_sink_close(GstAudioSink *sink)
154{
155 Q_UNUSED(sink);
156 return true;
157}
158
159/* write samples to the device */
160static 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 */
176static 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 */
188static 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
196static 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
210static 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
231static 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
256static void arts_sink_dispose (GObject * object)
257{
258 Q_UNUSED(object);
259 if (--sinkCount == 0) {
260 p_arts_free();
261 }
262}
263
264static void arts_sink_finalize (GObject * object)
265{
266 G_OBJECT_CLASS (parent_class)->finalize (object);
267}
268
269static GstCaps *arts_sink_get_caps (GstBaseSink * bsink)
270{
271 Q_UNUSED(bsink);
272 return NULL;
273}
274
275}
276} //namespace Phonon::Gstreamer
277
278QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.