~vcs-imports/gnome-media/main

« back to all changes in this revision

Viewing changes to gst-mixer/src/mixer.c

  • Committer: uraeus
  • Date: 2003-10-25 01:58:21 UTC
  • Revision ID: vcs-imports@canonical.com-20031025015821-n50sk08xakhes2gk
2003-25-10 Christian Schaller <Uraeus@gnome.org>
- New GStreamer based mixer commited!!
- Removed need for gnome-common when doing autogen.sh
- Misc fixes and cleanups
- Still a lot needing doing :(

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer Mixer
 
2
 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
 
3
 *
 
4
 * mixer.c: sample mixer application
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public
 
17
 * License along with this library; if not, write to the
 
18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include "config.h"
 
24
#endif
 
25
 
 
26
#include <string.h>
 
27
#include <glib.h>
 
28
#include <gnome.h>
 
29
#include <gst/gst.h>
 
30
#include <gst/mixer/mixer.h>
 
31
 
 
32
typedef struct _MyMixerControls {
 
33
  GstMixer *mixer;
 
34
  GstMixerTrack *track;
 
35
  GList *adjustments;
 
36
  GtkWidget *lock, *mute, *record;
 
37
  gboolean locked;
 
38
} MyMixerControls;
 
39
 
 
40
/* private stock icons */
 
41
#define GST_MIXER_STOCK_PHONE "gst-mixer-phone"
 
42
#define GST_MIXER_STOCK_VIDEO "gst-mixer-video"
 
43
#define GST_MIXER_STOCK_TONE  "gst-mixer-tone"
 
44
#define GST_MIXER_STOCK_MIXER "gst-mixer-mixer"
 
45
 
 
46
static const struct {
 
47
  gchar *label,
 
48
        *pixmap;
 
49
} pix[] = {
 
50
  { "cd",         GTK_STOCK_CDROM       },
 
51
  { "line",       GNOME_STOCK_LINE_IN   },
 
52
  { "microphone", GNOME_STOCK_MIC       },
 
53
  { "mixer",      GST_MIXER_STOCK_MIXER },
 
54
  { "pcm",        GST_MIXER_STOCK_TONE  },
 
55
  { "phone",      GST_MIXER_STOCK_PHONE },
 
56
  { "speaker",    GNOME_STOCK_VOLUME    },
 
57
  { "video",      GST_MIXER_STOCK_VIDEO },
 
58
  { "volume",     GST_MIXER_STOCK_TONE  },
 
59
  { NULL, NULL }
 
60
};
 
61
 
 
62
static void
 
63
cb_volume_changed (GtkAdjustment *adj,
 
64
                   gpointer       data)
 
65
{
 
66
  MyMixerControls *ctrl = (MyMixerControls *) data;
 
67
  gint *volumes, i = 0;
 
68
  GList *adjustments = ctrl->adjustments;
 
69
 
 
70
  if (ctrl->locked)
 
71
    return;
 
72
  ctrl->locked = TRUE;
 
73
  volumes = g_malloc (sizeof (gint) * g_list_length (adjustments));
 
74
 
 
75
  for ( ; adjustments != NULL; adjustments = adjustments->next) {
 
76
    GtkAdjustment *adj2 = (GtkAdjustment *) adjustments->data;
 
77
 
 
78
    if (ctrl->lock != NULL &&
 
79
        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ctrl->lock))) {
 
80
      gtk_adjustment_set_value (adj2, gtk_adjustment_get_value (adj));
 
81
      volumes[i++] = gtk_adjustment_get_value (adj);
 
82
    } else {
 
83
      volumes[i++] = gtk_adjustment_get_value (adj2);
 
84
    }
 
85
  }
 
86
 
 
87
  gst_mixer_set_volume (ctrl->mixer, ctrl->track, volumes);
 
88
 
 
89
  g_free (volumes);
 
90
  ctrl->locked = FALSE;
 
91
}
 
92
 
 
93
static void
 
94
cb_lock_toggled (GtkWidget *button,
 
95
                 gpointer   data)
 
96
{
 
97
  MyMixerControls *ctrl = (MyMixerControls *) data;
 
98
 
 
99
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
 
100
    /* get the mean value, and set it on the first adjustment.
 
101
     * the cb_olume_changed () callback will take care of the
 
102
     * rest */
 
103
    gint volume = 0, num = 0;
 
104
    GList *adjustments = ctrl->adjustments;
 
105
 
 
106
    for ( ; adjustments != NULL; adjustments = adjustments->next) {
 
107
      GtkAdjustment *adj = (GtkAdjustment *) adjustments->data;
 
108
 
 
109
      num++;
 
110
      volume += gtk_adjustment_get_value (adj);
 
111
    }
 
112
 
 
113
    /* safety check */
 
114
    if (ctrl->adjustments != NULL) {
 
115
      gtk_adjustment_set_value ((GtkAdjustment *) ctrl->adjustments->data,
 
116
                                volume / num);
 
117
    }
 
118
  }
 
119
}
 
120
 
 
121
static void
 
122
cb_mute_toggled (GtkWidget *button,
 
123
                 gpointer   data)
 
124
{
 
125
  MyMixerControls *ctrl = (MyMixerControls *) data;
 
126
  gst_mixer_set_mute (ctrl->mixer, ctrl->track,
 
127
                      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
 
128
}
 
129
 
 
130
static void
 
131
cb_record_toggled (GtkWidget *button,
 
132
                   gpointer   data)
 
133
{
 
134
  MyMixerControls *ctrl = (MyMixerControls *) data;
 
135
  gst_mixer_set_record (ctrl->mixer, ctrl->track,
 
136
                        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
 
137
}
 
138
 
 
139
static void
 
140
create_track_widget (GstMixer      *mixer,
 
141
                     GtkWidget     *table,
 
142
                     gint           column_pos,
 
143
                     GstMixerTrack *track)
 
144
{
 
145
  GtkWidget *label, *slider, *button, *image;
 
146
  GtkObject *adj;
 
147
  gint i, *volumes;
 
148
  GList *adjlist = NULL;
 
149
  MyMixerControls *ctrl = g_new0 (MyMixerControls, 1);
 
150
  gchar *str = NULL;
 
151
 
 
152
  volumes = g_malloc (sizeof (gint) * track->num_channels);
 
153
 
 
154
  ctrl->mixer = mixer;
 
155
  ctrl->track = track;
 
156
  ctrl->locked = FALSE;
 
157
 
 
158
  /* image (optional) */
 
159
  for (i = 0; str == NULL && pix[i].label != NULL; i++) {
 
160
    /* we dup the string to make the comparison case-insensitive */
 
161
    gchar *label_l = g_strdup (track->label),
 
162
          *needle_l = g_strdup (pix[i].label);
 
163
    gint pos;
 
164
 
 
165
    /* make case insensitive */
 
166
    for (pos = 0; label_l[pos] != '\0'; pos++)
 
167
      label_l[pos] = g_ascii_tolower (label_l[pos]);
 
168
    for (pos = 0; needle_l[pos] != '\0'; pos++)
 
169
      needle_l[pos] = g_ascii_tolower (needle_l[pos]);
 
170
 
 
171
    if (g_strrstr (label_l, needle_l) != NULL)
 
172
      str = pix[i].pixmap;
 
173
 
 
174
    g_free (label_l);
 
175
    g_free (needle_l);
 
176
  }
 
177
 
 
178
  if (str != NULL) {
 
179
    if ((image = gtk_image_new_from_stock (str, GTK_ICON_SIZE_MENU)) != NULL) {
 
180
      gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
 
181
      gtk_table_attach_defaults (GTK_TABLE (table), image,
 
182
                                 column_pos, column_pos + track->num_channels,
 
183
                                 0, 1);
 
184
    }
 
185
  }
 
186
 
 
187
  /* label */
 
188
  label = gtk_label_new (track->label);
 
189
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
 
190
  gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
 
191
  gtk_table_attach_defaults (GTK_TABLE (table), label,
 
192
                             column_pos, column_pos + track->num_channels,
 
193
                             1, 2);
 
194
 
 
195
  /* now sliders for each of the tracks */
 
196
  gst_mixer_get_volume (mixer, track, volumes);
 
197
  for (i = 0; i < track->num_channels; i++) {
 
198
    adj = gtk_adjustment_new (volumes[i],
 
199
                              track->min_volume, track->max_volume,
 
200
                              1.0, 1.0, 0.0);
 
201
    adjlist = g_list_append (adjlist, (gpointer) adj);
 
202
    g_signal_connect (G_OBJECT (adj), "value_changed",
 
203
                      G_CALLBACK (cb_volume_changed), (gpointer) ctrl);
 
204
    slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
 
205
    gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
 
206
    gtk_range_set_inverted (GTK_RANGE (slider), TRUE);
 
207
    gtk_widget_set_size_request (slider, -1, 100);
 
208
    gtk_table_attach_defaults (GTK_TABLE (table), slider,
 
209
                               column_pos + i, column_pos + i + 1,
 
210
                               2, 3);
 
211
  }
 
212
 
 
213
  ctrl->adjustments = adjlist;
 
214
 
 
215
  /* buttons (lock, mute, rec) */
 
216
  if (track->num_channels > 1) {
 
217
    button = gtk_check_button_new_with_label (_("Lock"));
 
218
    gtk_table_attach_defaults (GTK_TABLE (table), button,
 
219
                               column_pos, column_pos + track->num_channels,
 
220
                               3, 4);
 
221
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
222
    ctrl->lock = button;
 
223
    g_signal_connect (G_OBJECT (button), "toggled",
 
224
                      G_CALLBACK (cb_lock_toggled), (gpointer) ctrl);
 
225
  }
 
226
 
 
227
  button = gtk_check_button_new_with_label (_("Mute"));
 
228
  gtk_table_attach_defaults (GTK_TABLE (table), button,
 
229
                             column_pos, column_pos + track->num_channels,
 
230
                             4, 5);
 
231
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
232
                                GST_MIXER_TRACK_HAS_FLAG (track,
 
233
                                                GST_MIXER_TRACK_MUTE));
 
234
  g_signal_connect (G_OBJECT (button), "toggled",
 
235
                    G_CALLBACK (cb_mute_toggled), (gpointer) ctrl);
 
236
  ctrl->mute = button;
 
237
 
 
238
  if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_INPUT)) {
 
239
    button = gtk_check_button_new_with_label (_("Rec."));
 
240
    gtk_table_attach_defaults (GTK_TABLE (table), button,
 
241
                               column_pos, column_pos + track->num_channels,
 
242
                               5, 6);
 
243
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
244
                                  GST_MIXER_TRACK_HAS_FLAG (track,
 
245
                                                GST_MIXER_TRACK_RECORD));
 
246
    g_signal_connect (G_OBJECT (button), "toggled",
 
247
                      G_CALLBACK (cb_record_toggled), (gpointer) ctrl);
 
248
    ctrl->record = button;
 
249
  }
 
250
 
 
251
  g_free (volumes);
 
252
}
 
253
 
 
254
static GtkWidget *
 
255
create_mixer_widget (GstMixer *mixer)
 
256
{
 
257
  GtkWidget *table;
 
258
  gint tablepos = 0;
 
259
  const GList *tracks;
 
260
 
 
261
  /* count number of tracks */
 
262
  tracks = gst_mixer_list_tracks (mixer);
 
263
  for ( ; tracks != NULL; tracks = tracks->next) {
 
264
    tablepos += ((GstMixerTrack *) tracks->data)->num_channels;
 
265
    if (tracks->next != NULL)
 
266
      tablepos++;
 
267
  }
 
268
 
 
269
  /* create table for all single tracks */
 
270
  table = gtk_table_new (6, tablepos, FALSE);
 
271
  gtk_container_set_border_width (GTK_CONTAINER (table), 4);
 
272
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
 
273
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
 
274
 
 
275
  /* add each */
 
276
  tablepos = 0;
 
277
  tracks = gst_mixer_list_tracks (mixer);
 
278
  for ( ; tracks != NULL; tracks = tracks->next) {
 
279
    create_track_widget (mixer, table, tablepos,
 
280
                         (GstMixerTrack *) tracks->data);
 
281
    tablepos += ((GstMixerTrack *) tracks->data)->num_channels;
 
282
    if (tracks->next != NULL) {
 
283
      GtkWidget *sep = gtk_vseparator_new ();
 
284
      gtk_table_attach_defaults (GTK_TABLE (table), sep,
 
285
                                 tablepos, tablepos+1, 0, 6);
 
286
      tablepos++;
 
287
    }
 
288
  }
 
289
 
 
290
  return table;
 
291
}
 
292
 
 
293
static GList *
 
294
create_mixer_collection (GtkWidget *notebook)
 
295
{
 
296
  GtkWidget *page, *label;
 
297
  const GList *elements;
 
298
  GList *collection = NULL;
 
299
  gint num = 0;
 
300
 
 
301
  /* go through all elements of a certain class and check whether
 
302
   * they implement a mixer. If so, add a page */
 
303
  elements = gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY);
 
304
  for ( ; elements != NULL; elements = elements->next) {
 
305
    GstElementFactory *factory = GST_ELEMENT_FACTORY (elements->data);
 
306
    gchar *title, *name;
 
307
    GstElement *element;
 
308
 
 
309
    /* check category */
 
310
    if (strcmp (factory->details->klass, "Generic/Audio"))
 
311
      continue;
 
312
 
 
313
    /* create element */
 
314
    title = g_strdup_printf ("gst-mixer-%d", num);
 
315
    element = gst_element_factory_create (factory, title);
 
316
    if (!element) {
 
317
      g_free (title);
 
318
      continue;
 
319
    }
 
320
 
 
321
    /* check whether it implements a mixer  */
 
322
    if (!gst_element_set_state (element, GST_STATE_READY) ||
 
323
        !GST_IS_MIXER (element)) {
 
324
      gst_element_set_state (element, GST_STATE_NULL);
 
325
      g_object_unref (G_OBJECT (element));
 
326
      g_free (title);
 
327
      continue;
 
328
    }
 
329
 
 
330
    /* create mixer UI object */
 
331
    page = create_mixer_widget (GST_MIXER (element));
 
332
    if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (element)),
 
333
                                      "device-name")) {
 
334
      g_object_get (element, "device-name", &name, NULL);
 
335
    } else {
 
336
      name = title;
 
337
    }
 
338
    label = gtk_label_new (name);
 
339
 
 
340
    /* add new notebook page + keep track */
 
341
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
 
342
    collection = g_list_append (collection, element);
 
343
    num++;
 
344
    g_free (title);
 
345
  }
 
346
 
 
347
  return collection;
 
348
}
 
349
 
 
350
static void
 
351
cb_about (GtkWidget *widget,
 
352
          gpointer   data)
 
353
{
 
354
  GtkWidget *about;
 
355
  const gchar *authors[] = { "Ronald Bultje <rbultje@ronald.bitfreak.net>",
 
356
                             NULL };
 
357
 
 
358
  about = gnome_about_new (_("GStreamer Volume Control"),
 
359
                           VERSION,
 
360
                           "(c) 2003 Ronald Bultje",
 
361
                           _("A GNOME/GStreamer-based mixer application"),
 
362
                           authors, NULL, NULL,
 
363
                           NULL);
 
364
 
 
365
  gtk_widget_show (about);
 
366
}
 
367
 
 
368
static void
 
369
cb_destroy (GtkWidget *widget,
 
370
            gpointer   data)
 
371
{
 
372
  gtk_main_quit();
 
373
}
 
374
 
 
375
static GnomeUIInfo file_menu[] = {
 
376
  GNOMEUIINFO_MENU_EXIT_ITEM (cb_destroy, NULL),
 
377
  GNOMEUIINFO_END
 
378
};
 
379
 
 
380
static GnomeUIInfo help_menu[] = {
 
381
  GNOMEUIINFO_MENU_ABOUT_ITEM (cb_about, NULL),
 
382
  GNOMEUIINFO_HELP (PACKAGE),
 
383
  GNOMEUIINFO_END
 
384
};
 
385
 
 
386
static GnomeUIInfo main_menu[] = {
 
387
  GNOMEUIINFO_MENU_FILE_TREE (file_menu),
 
388
  GNOMEUIINFO_MENU_HELP_TREE (help_menu),
 
389
  GNOMEUIINFO_END
 
390
};
 
391
 
 
392
static void
 
393
register_stock_icons (void)
 
394
{
 
395
  GtkIconFactory *icon_factory;
 
396
  struct {
 
397
    gchar *filename,
 
398
          *stock_id;
 
399
  } list[] = {
 
400
    { "mixer.png", GST_MIXER_STOCK_MIXER },
 
401
    { "phone.png", GST_MIXER_STOCK_PHONE },
 
402
    { "tone.png",  GST_MIXER_STOCK_TONE  },
 
403
    { "video.png", GST_MIXER_STOCK_VIDEO },
 
404
    { NULL, NULL }
 
405
  };
 
406
  gint num;
 
407
 
 
408
  icon_factory = gtk_icon_factory_new ();
 
409
  gtk_icon_factory_add_default (icon_factory);
 
410
 
 
411
  for (num = 0; list[num].filename != NULL; num++) {
 
412
    gchar *filename = gnome_program_locate_file (NULL,
 
413
                                                 GNOME_FILE_DOMAIN_APP_PIXMAP,
 
414
                                                 list[num].filename, TRUE, NULL);
 
415
    if (filename) {
 
416
      GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
417
      GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
 
418
      gtk_icon_factory_add (icon_factory, list[num].stock_id, icon_set);
 
419
      g_free (filename);
 
420
    }
 
421
  }
 
422
}
 
423
 
 
424
gint
 
425
main (gint   argc,
 
426
      gchar *argv[])
 
427
{
 
428
  gchar *appfile;
 
429
  GtkWidget *window, *notebook;
 
430
  GList *mixers, *item;
 
431
  struct poptOption options[] = {
 
432
    {NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL},
 
433
    POPT_TABLEEND
 
434
  };
 
435
 
 
436
  /* init gstreamer/gnome */
 
437
  options[0].arg = (void *) gst_init_get_popt_table();
 
438
  gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
 
439
                      argc, argv,
 
440
                      GNOME_PARAM_POPT_TABLE, options,
 
441
                      GNOME_PARAM_APP_DATADIR, DATA_DIR,
 
442
                      NULL);
 
443
  register_stock_icons ();
 
444
 
 
445
  appfile = gnome_program_locate_file (NULL,
 
446
                                       GNOME_FILE_DOMAIN_APP_PIXMAP,
 
447
                                       "mixer.png", TRUE, NULL);
 
448
  if (appfile) {
 
449
    gnome_window_icon_set_default_from_file (appfile);
 
450
    g_free (appfile);
 
451
  }
 
452
 
 
453
  /* create main window + menus */
 
454
  window = gnome_app_new (PACKAGE, _("GStreamer Volume Control"));
 
455
  gnome_app_create_menus (GNOME_APP (window), main_menu);
 
456
 
 
457
  /* create all mixers */
 
458
  notebook = gtk_notebook_new ();
 
459
  if (!(mixers = create_mixer_collection (notebook))) {
 
460
    GtkWidget *dialog =
 
461
        gtk_message_dialog_new (NULL, 0,
 
462
                                GTK_MESSAGE_ERROR,
 
463
                                GTK_BUTTONS_CLOSE,
 
464
                                _("Sorry, no mixer elements and/or devices found"));
 
465
    gtk_widget_show (dialog);
 
466
    gtk_dialog_run (GTK_DIALOG (dialog));
 
467
    return 0;
 
468
  }
 
469
  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) == 1)
 
470
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
 
471
 
 
472
  /* add to window */
 
473
  gnome_app_set_contents (GNOME_APP (window), notebook);
 
474
  g_signal_connect (G_OBJECT (window), "destroy",
 
475
                    G_CALLBACK (cb_destroy), NULL);
 
476
 
 
477
  /* show off and run */
 
478
  gtk_widget_show_all (window);
 
479
  gtk_main ();
 
480
 
 
481
  /* unref */
 
482
  for (item = mixers; item != NULL; item = item->next) {
 
483
    GstElement *element = GST_ELEMENT (item->data);
 
484
 
 
485
    gst_element_set_state (element, GST_STATE_NULL);
 
486
    gst_object_unref (GST_OBJECT (element));
 
487
  }
 
488
 
 
489
  return 0;
 
490
}