source: roaraudio/plugins/gstreamer0.10/roarmixer.c @ 5238:5117fb0e7ed4

Last change on this file since 5238:5117fb0e7ed4 was 5238:5117fb0e7ed4, checked in by phi, 12 years ago

Removed roar_stream_connect(), roar_stream_add_data(), roar_stream_send_data() and roar_stream_set_flags().

File size: 13.8 KB
Line 
1//roarmixer.c:
2/* GStreamer
3 * Copyright (C) <2005>      Arwed v. Merkatz <v.merkatz@gmx.net>
4 * Copyright (C) <2008-2011> Philipp 'ph3-der-loewe' Schafft
5 *                                    <lion@lion.leolix.org>
6 *
7 * roarmixer.h: an RoarAudio audio mixer
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
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 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02111-1307, USA.
23 */
24
25
26#include "roarmixer.h"
27
28GST_DEBUG_CATEGORY_EXTERN (roar_debug);
29#define GST_CAT_DEFAULT roar_debug
30
31enum
32{
33  PROP_DEVICE_NAME = 1
34};
35
36
37static const GstElementDetails gst_roar_mixer_element_details =
38GST_ELEMENT_DETAILS ("RoarAudio Mixer",
39    "Generic/Audio",
40    "Control sound input and output levels with RoarAudio",
41    "Philipp 'ph3-der-loewe' Schafft <lion@lion.leolix.org>");
42
43GST_BOILERPLATE_WITH_INTERFACE (GstRoarMixerElement, gst_roar_mixer_element,
44    GstElement, GST_TYPE_ELEMENT, GstMixer, GST_TYPE_MIXER,
45    gst_roar_mixer_element);
46
47GST_IMPLEMENT_ROAR_MIXER_METHODS (GstRoarMixerElement, gst_roar_mixer_element);
48
49static GstStateChangeReturn gst_roar_mixer_element_change_state (GstElement *
50    element, GstStateChange transition);
51
52static void gst_roar_mixer_element_get_property (GObject * object,
53    guint prop_id, GValue * value, GParamSpec * pspec);
54
55static void
56gst_roar_mixer_element_base_init (gpointer klass)
57{
58  gst_element_class_set_details (GST_ELEMENT_CLASS (klass),
59      &gst_roar_mixer_element_details);
60}
61
62static void
63gst_roar_mixer_element_class_init (GstRoarMixerElementClass * klass)
64{
65  GstElementClass *element_class;
66  GObjectClass *gobject_class;
67
68  element_class = (GstElementClass *) klass;
69  gobject_class = (GObjectClass *) klass;
70
71  gobject_class->get_property = gst_roar_mixer_element_get_property;
72
73  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
74      g_param_spec_string ("device-name", "Device name",
75          "Human-readable name of the sound device", "", G_PARAM_READABLE));
76
77  element_class->change_state =
78      GST_DEBUG_FUNCPTR (gst_roar_mixer_element_change_state);
79}
80
81static void
82gst_roar_mixer_element_init (GstRoarMixerElement * this,
83    GstRoarMixerElementClass * g_class)
84{
85  this->mixer = NULL;
86}
87
88static void
89gst_roar_mixer_element_get_property (GObject * object, guint prop_id,
90    GValue * value, GParamSpec * pspec)
91{
92  GstRoarMixerElement *this = GST_ROAR_MIXER_ELEMENT (object);
93
94  switch (prop_id) {
95    case PROP_DEVICE_NAME:
96      if (this->mixer) {
97        g_value_set_string (value, this->mixer->cardname);
98      } else {
99        g_value_set_string (value, NULL);
100      }
101      break;
102    default:
103      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
104      break;
105  }
106}
107
108static GstStateChangeReturn
109gst_roar_mixer_element_change_state (GstElement * element,
110    GstStateChange transition)
111{
112  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
113  GstRoarMixerElement *this = GST_ROAR_MIXER_ELEMENT (element);
114
115  switch (transition) {
116    case GST_STATE_CHANGE_NULL_TO_READY:
117      if (!this->mixer) {
118        this->mixer = gst_roarmixer_new(NULL, GST_ROAR_MIXER_ALL);
119      }
120      break;
121    default:
122      break;
123  }
124
125  ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
126  if (ret == GST_STATE_CHANGE_FAILURE)
127    return ret;
128
129  switch (transition) {
130    case GST_STATE_CHANGE_READY_TO_NULL:
131      if (this->mixer) {
132        gst_roarmixer_free(this->mixer);
133        this->mixer = NULL;
134      }
135      break;
136    default:
137      break;
138  }
139
140  return ret;
141}
142
143
144gboolean gst_roarmixer_factory_init (GstPlugin * plugin) {
145  if (!gst_element_register(plugin, "roarmixer", GST_RANK_MARGINAL,
146                            GST_TYPE_ROAR_MIXER_ELEMENT))
147    return FALSE;
148
149  return TRUE;
150}
151
152G_DEFINE_TYPE (GstRoarMixerTrack, gst_roarmixer_track, GST_TYPE_MIXER_TRACK);
153
154GstRoarMixer*    gst_roarmixer_new                (const gchar *device,
155                                                 GstRoarMixerDirection dir) {
156  GstRoarMixer *ret = NULL;
157
158  ROAR_WARN("gst_roarmixer_new(device='%s', dir=0x%.4x) = ?", device, dir);
159
160  ret = g_new0(GstRoarMixer, 1);
161
162  ret->device = g_strdup(device);
163  ret->dir    = dir;
164  ret->cardname = g_strdup("RoarAudio Default Device");
165
166/*
167  if (!gst_ossmixer_open (ret))
168    goto error;
169*/
170
171  if ( roar_simple_connect(&(ret->con), (char*)device, "gstroarmixer") == -1 )
172   goto error;
173
174  ROAR_WARN("gst_roarmixer_new(device='%s', dir=0x%.4x) = %p", device, dir, ret);
175  return ret;
176
177error:
178  if (ret)
179    gst_roarmixer_free (ret);
180
181  ROAR_WARN("gst_roarmixer_new(device='%s', dir=0x%.4x) = NULL // Error?", device, dir);
182  return NULL;
183}
184
185void            gst_roarmixer_free               (GstRoarMixer *mixer) {
186  g_return_if_fail(mixer != NULL);
187
188  ROAR_WARN("gst_roarmixer_free(mixer=%p) = ?", mixer);
189
190  if (mixer->device) {
191    g_free(mixer->device);
192    mixer->device = NULL;
193  }
194
195  if (mixer->cardname) {
196    g_free(mixer->cardname);
197    mixer->cardname = NULL;
198  }
199
200  if (mixer->tracklist) {
201    g_list_foreach(mixer->tracklist, (GFunc) g_object_unref, NULL);
202    g_list_free(mixer->tracklist);
203    mixer->tracklist = NULL;
204  }
205
206  roar_disconnect(&(mixer->con));
207
208  g_free (mixer);
209
210  ROAR_WARN("gst_roarmixer_free(mixer=%p) = (void)", mixer);
211}
212
213/* unused with G_DISABLE_* */
214static G_GNUC_UNUSED gboolean gst_roarmixer_contains_track (GstRoarMixer * mixer,
215                                                            GstRoarMixerTrack * roartrack) {
216  const GList *item;
217
218  if ( mixer == NULL || mixer->tracklist == NULL )
219   return FALSE;
220
221  for (item = mixer->tracklist; item != NULL; item = item->next)
222    if (item->data == roartrack)
223      return TRUE;
224
225  return FALSE;
226}
227
228void            gst_roarmixer_updatestreamlist   (GstRoarMixer *mixer) {
229  gint  i      = 0;
230  gint num;
231  gint id[ROAR_STREAMS_MAX];
232  GstMixerTrack *track;
233
234  ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p) = ? // ########################", mixer);
235  ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p): tracklist=%p", mixer, mixer->tracklist);
236
237  if (mixer->tracklist) {
238    ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p) = (void)", mixer);
239    return;
240  }
241
242/*
243  if (mixer->tracklist) {
244    g_list_foreach(mixer->tracklist, (GFunc) g_object_unref, NULL);
245    g_list_free(mixer->tracklist);
246    mixer->tracklist = NULL;
247  }
248*/
249
250  ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p): tracklist=%p", mixer, mixer->tracklist);
251
252  if ( (num = roar_list_streams(&(mixer->con), id, ROAR_STREAMS_MAX)) == -1 ) {
253    return;
254  }
255
256
257  for (i = 0; i < num; i++) {
258   track = gst_roarmixer_track_new(mixer, id[i]);
259   ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p): track=%p", mixer, track);
260
261   if ( track == NULL )
262    continue;
263
264   mixer->tracklist = g_list_append(mixer->tracklist, track);
265  }
266
267  ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p): tracklist=%p", mixer, mixer->tracklist);
268
269  ROAR_WARN("gst_roarmixer_updatestreamlist(mixer=%p) = (void) // ###################", mixer);
270}
271
272const GList*    gst_roarmixer_list_tracks        (GstRoarMixer * mixer) {
273 ROAR_WARN("gst_roarmixer_list_tracks(mixer=%p) = ?", mixer);
274
275 gst_roarmixer_updatestreamlist(mixer);
276
277 ROAR_WARN("gst_roarmixer_list_tracks(mixer=%p) = %p", mixer, mixer->tracklist);
278 return (const GList *) mixer->tracklist;
279}
280
281void            gst_roarmixer_set_volume         (GstRoarMixer * mixer,
282                                                 GstMixerTrack * track,
283                                                 gint * volumes) {
284 GstRoarMixerTrack *roartrack = GST_ROARMIXER_TRACK(track);
285 int channels;
286 struct roar_mixer_settings m;
287 int mode = ROAR_SET_VOL_ALL;
288 gint i;
289
290
291 g_return_if_fail(gst_roarmixer_contains_track(mixer, roartrack));
292
293 if ( roar_get_vol(&(mixer->con), roartrack->stream_id, &m, &channels) == -1 ) {
294  ROAR_WARN("gst_roarmixer_get_volume(*): can not get mixer infos for stream %i", roartrack->stream_id);
295  return;
296 }
297
298 if ( channels != track->num_channels ) {
299  ROAR_WARN("gst_roarmixer_get_volume(*): numer of channels for stream %i mismatch (local: %i, server: %i)",
300            roartrack->stream_id, (int)track->num_channels, channels);
301
302  if ( track->num_channels < channels )
303   channels = track->num_channels;
304  mode = ROAR_SET_VOL_UNMAPPED;
305 }
306
307 for (i = 0; i < channels; i++) {
308  m.mixer[i] = volumes[i];
309 }
310
311 m.scale = 65535;
312
313 _LIBROAR_IGNORE_RET(roar_set_vol(&(mixer->con), roartrack->stream_id, &m, channels, mode));
314}
315
316void            gst_roarmixer_get_volume         (GstRoarMixer * mixer,
317                                                 GstMixerTrack * track,
318                                                 gint * volumes) {
319 GstRoarMixerTrack *roartrack = GST_ROARMIXER_TRACK(track);
320 int channels;
321 struct roar_mixer_settings m;
322 gint i;
323
324
325 g_return_if_fail(gst_roarmixer_contains_track(mixer, roartrack));
326
327 if ( roar_get_vol(&(mixer->con), roartrack->stream_id, &m, &channels) == -1 ) {
328  ROAR_WARN("gst_roarmixer_get_volume(*): can not get mixer infos for stream %i", roartrack->stream_id);
329  return;
330 }
331
332 if ( channels != track->num_channels ) {
333  ROAR_WARN("gst_roarmixer_get_volume(*): numer of channels for stream %i mismatch", roartrack->stream_id);
334
335  if ( track->num_channels < channels )
336   channels = track->num_channels;
337 }
338
339 for (i = 0; i < channels; i++) {
340  if ( m.scale == 65535 ) {
341   volumes[i] = m.mixer[i];
342  } else {
343   volumes[i] = m.mixer[i] * 65535. / (float) m.scale; // we do not hanle precides scaling here
344                                                       // as it does not matter:
345                                                       // we never write those values back to roard.
346  }
347 }
348
349}
350void            gst_roarmixer_set_record         (GstRoarMixer * mixer,
351                                                 GstMixerTrack * track,
352                                                 gboolean record) {
353}
354void            gst_roarmixer_set_mute           (GstRoarMixer * mixer,
355                                                 GstMixerTrack * track,
356                                                 gboolean mute) {
357  GstRoarMixerTrack *roartrack = GST_ROARMIXER_TRACK(track);
358  struct roar_stream s;
359
360  g_return_if_fail(gst_roarmixer_contains_track(mixer, roartrack));
361
362  roar_stream_new_by_id(&s, roartrack->stream_id);
363
364  if (mute) {
365    _LIBROAR_IGNORE_RET(roar_stream_set_flags(&(mixer->con), &s, ROAR_FLAG_MUTE, ROAR_SET_FLAG));
366  } else {
367    _LIBROAR_IGNORE_RET(roar_stream_set_flags(&(mixer->con), &s, ROAR_FLAG_MUTE, ROAR_RESET_FLAG));
368  }
369}
370
371// tracks:
372#define MASK_BIT_IS_SET(mask, bit) \
373  (mask & (1 << bit))
374
375static void
376gst_roarmixer_track_class_init (GstRoarMixerTrackClass * klass)
377{
378  /* nop */
379}
380
381static void
382gst_roarmixer_track_init (GstRoarMixerTrack * track)
383{
384  //memset(track, 0, sizeof(*track));
385  track->stream_id = -1;
386  ROAR_WARN("gst_roarmixer_track_init(track=%p) = (void)", track);
387}
388
389GstMixerTrack *
390gst_roarmixer_track_new (GstRoarMixer * mixer,
391    gint stream_id)
392{
393  GstRoarMixerTrack *roartrack;
394  GstMixerTrack *track;
395  struct roar_stream s;
396  struct roar_client c;
397  struct roar_meta   m;
398  gint flags = 0;
399  gchar buf[1024];
400  int num;
401  int id[ROAR_CLIENTS_MAX];
402  char * clientname = NULL;
403  char * metaname   = NULL;
404  char   streamname[1024] = {0};
405  gint i, h;
406
407  ROAR_WARN("gst_roarmixer_track_new(mixer=%p, stream_id=%i) = ?", mixer, stream_id);
408
409  if ( roar_get_stream(&(mixer->con), &s, stream_id) == -1 ) {
410    return NULL;
411  }
412
413 // TODO: find something more efficent:
414
415 if ( (num = roar_list_clients(&(mixer->con), id, ROAR_CLIENTS_MAX)) != -1 ) {
416  for (i = 0; i < num; i++) {
417   ROAR_DBG("gst_roarmixer_track_new(*): stream %i -->> client %i?", stream_id, id[i]);
418   if ( roar_get_client(&(mixer->con), &c, id[i]) != -1 ) {
419    for (h = 0; h < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; h++) {
420     ROAR_DBG("gst_roarmixer_track_new(*): stream %i <-> %i -->> client %i?", stream_id, c.streams[h], id[i]);
421     if ( c.streams[h] == stream_id ) {
422      clientname = c.name;
423      h = ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT;
424      i = num;
425     }
426    }
427   }
428  }
429 }
430
431 m.type = ROAR_META_TYPE_TITLE;
432 if ( roar_stream_meta_get(&(mixer->con), &s, &m) != -1 ) {
433  metaname = m.value;
434 }
435
436 if ( roar_stream_get_name(&(mixer->con), &s, streamname, 1024) != 0 )
437  *streamname = 0;
438
439  switch (s.dir) {
440   case ROAR_DIR_PLAY:
441     flags |= GST_MIXER_TRACK_OUTPUT;
442    break;
443   case ROAR_DIR_MIXING:
444     flags |= GST_MIXER_TRACK_OUTPUT;
445    break;
446   case ROAR_DIR_OUTPUT:
447     flags |= GST_MIXER_TRACK_MASTER;
448   case ROAR_DIR_MONITOR:
449     flags |= GST_MIXER_TRACK_OUTPUT;
450    break;
451   default: return NULL;
452  }
453
454#if 0
455  if ( !*streamname && metaname == NULL )
456   sprintf(streamname, "[Stream %i]", stream_id);
457
458  sprintf(buf, "%s\n%s",  clientname ? clientname : "[Unknown]",
459                         *streamname ? streamname : metaname
460                         );
461#else
462  if ( *streamname ) {
463   strcpy(buf, streamname);
464  } else {
465   sprintf(buf, "Stream %i/%s", stream_id, clientname);
466  }
467#endif
468
469  roartrack = g_object_new(GST_TYPE_ROARMIXER_TRACK, NULL);
470  ROAR_WARN("gst_roarmixer_track_new(*): roartrack=%p", roartrack);
471  track               = GST_MIXER_TRACK(roartrack);
472  track->label        = g_strdup(buf);
473  track->num_channels = s.info.channels;
474  track->flags        = flags;
475  track->min_volume   = 0;
476  track->max_volume   = 65535;
477  roartrack->stream_id = stream_id;
478
479  /* volume */
480  ROAR_WARN("gst_roarmixer_track_new(mixer=%p, stream_id=%i) = %p", mixer, stream_id, track);
481  return track;
482}
483
484//ll
Note: See TracBrowser for help on using the repository browser.