source: roaraudio/plugins/gstreamer0.10/roarmixer.c @ 3533:84051d6f5086

Last change on this file since 3533:84051d6f5086 was 3533:84051d6f5086, checked in by phi, 14 years ago

hanlde scale more correctly

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