gstvolume.c 17.5 KB
Newer Older
Andy Wingo's avatar
Andy Wingo committed
1
/* -*- c-basic-offset: 2 -*-
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
2
3
 * vi:si:et:sw=2:sts=8:ts=8:expandtab
 *
Andy Wingo's avatar
Andy Wingo committed
4
5
 * GStreamer
 * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
6
 * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
Andy Wingo's avatar
Andy Wingo committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

24
25
26
27
28
29
/**
 * SECTION:element-volume
 *
 * <refsect2>
 * <title>Example launch line</title>
 * <para>
Wim Taymans's avatar
Wim Taymans committed
30
31
32
 * The volume element changes the volume of the audio data.
 * </para>
 * <para>
33
 * <programlisting>
34
 * gst-launch -v -m audiotestsrc ! volume volume=0.5 ! level ! fakesink silent=TRUE
35
 * </programlisting>
36
 * This pipeline shows that the level of audiotestsrc has been halved
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
37
 * (peak values are around -6 dB and RMS around -9 dB) compared to
38
39
40
41
42
 * the same pipeline without the volume element.
 * </para>
 * </refsect2>
 */

43
44
45
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
46

Andy Wingo's avatar
Andy Wingo committed
47
48
#include <string.h>
#include <gst/gst.h>
49
#include <gst/base/gstbasetransform.h>
50
#include <gst/audio/audio.h>
51
#include <gst/interfaces/mixer.h>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
52
#include <gst/controller/gstcontroller.h>
53
#include <liboil/liboil.h>
Stefan Kost's avatar
Stefan Kost committed
54

Andy Wingo's avatar
Andy Wingo committed
55
56
#include "gstvolume.h"

57
/* some defines for audio processing */
58
59
/* the volume factor is a range from 0.0 to (arbitrary) VOLUME_MAX_DOUBLE = 10.0
 * we map 1.0 to VOLUME_UNITY_INT16
60
 */
61
62
63
64
65
#define VOLUME_UNITY_INT16           8192       /* internal int for unity 2^13 */
#define VOLUME_UNITY_INT16_BIT_SHIFT 13 /* number of bits to shift for unity */
#define VOLUME_MAX_DOUBLE            10.0
#define VOLUME_MAX_INT16             32767
#define VOLUME_MIN_INT16             -32768
Andy Wingo's avatar
Andy Wingo committed
66

67
/* number of steps we use for the mixer interface to go from 0.0 to 1.0 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
68
# define VOLUME_STEPS           100
Andy Wingo's avatar
Andy Wingo committed
69

70
71
72
#define GST_CAT_DEFAULT gst_volume_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

Stefan Kost's avatar
Stefan Kost committed
73
static const GstElementDetails volume_details = GST_ELEMENT_DETAILS ("Volume",
74
75
76
    "Filter/Effect/Audio",
    "Set volume on audio/raw streams",
    "Andy Wingo <wingo@pobox.com>");
Andy Wingo's avatar
Andy Wingo committed
77
78

/* Filter signals and args */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
79
80
enum
{
Andy Wingo's avatar
Andy Wingo committed
81
82
83
84
  /* FILL ME */
  LAST_SIGNAL
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85
86
enum
{
87
88
89
90
  PROP_0,
  PROP_SILENT,
  PROP_MUTE,
  PROP_VOLUME
Andy Wingo's avatar
Andy Wingo committed
91
92
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
93
static GstStaticPadTemplate volume_sink_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
94
95
96
97
    GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-raw-float, "
98
99
100
        "rate = (int) [ 1, MAX ], "
        "channels = (int) [ 1, MAX ], "
        "endianness = (int) BYTE_ORDER, "
101
        "width = (int) {32, 64}; "
102
103
104
105
106
        "audio/x-raw-int, "
        "channels = (int) [ 1, MAX ], "
        "rate = (int) [ 1,  MAX ], "
        "endianness = (int) BYTE_ORDER, "
        "width = (int) 16, " "depth = (int) 16, " "signed = (bool) TRUE")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
107
108
    );

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
109
110
static GstStaticPadTemplate volume_src_template = GST_STATIC_PAD_TEMPLATE
    ("src",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
111
112
113
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-raw-float, "
114
115
116
        "rate = (int) [ 1, MAX ], "
        "channels = (int) [ 1, MAX ], "
        "endianness = (int) BYTE_ORDER, "
117
        "width = (int) {32, 64}; "
118
119
120
121
122
        "audio/x-raw-int, "
        "channels = (int) [ 1, MAX ], "
        "rate = (int) [ 1,  MAX ], "
        "endianness = (int) BYTE_ORDER, "
        "width = (int) 16, " "depth = (int) 16, " "signed = (bool) TRUE")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
123
124
    );

125
126
127
static void gst_volume_interface_init (GstImplementsInterfaceClass * klass);
static void gst_volume_mixer_init (GstMixerClass * iface);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
128
#define _init_interfaces(type)                                          \
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  {                                                                     \
    static const GInterfaceInfo voliface_info = {                       \
      (GInterfaceInitFunc) gst_volume_interface_init,                   \
      NULL,                                                             \
      NULL                                                              \
    };                                                                  \
    static const GInterfaceInfo volmixer_info = {                       \
      (GInterfaceInitFunc) gst_volume_mixer_init,                       \
      NULL,                                                             \
      NULL                                                              \
    };                                                                  \
                                                                        \
    g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,   \
        &voliface_info);                                                \
    g_type_add_interface_static (type, GST_TYPE_MIXER, &volmixer_info); \
144
145
146
147
148
  }

GST_BOILERPLATE_FULL (GstVolume, gst_volume, GstBaseTransform,
    GST_TYPE_BASE_TRANSFORM, _init_interfaces);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
149
150
151
152
153
154
155
static void volume_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void volume_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void volume_update_volume (const GValue * value, gpointer data);
static void volume_update_mute (const GValue * value, gpointer data);

156
157
static GstFlowReturn volume_transform_ip (GstBaseTransform * base,
    GstBuffer * outbuf);
158
static gboolean volume_set_caps (GstBaseTransform * base, GstCaps * incaps,
159
160
    GstCaps * outcaps);

161
162
static void volume_process_double (GstVolume * this, gpointer bytes,
    guint n_bytes);
163
static void volume_process_float (GstVolume * this, gpointer bytes,
164
    guint n_bytes);
165
static void volume_process_int16 (GstVolume * this, gpointer bytes,
166
    guint n_bytes);
167
static void volume_process_int16_clamp (GstVolume * this, gpointer bytes,
168
    guint n_bytes);
Andy Wingo's avatar
Andy Wingo committed
169

170
171
/* helper functions */

172
173
174
static void
volume_choose_func (GstVolume * this)
{
175
  this->process = NULL;
176
177
  switch (this->format) {
    case GST_VOLUME_FORMAT_INT:
178
      /* FIXME: should we also support gint8, gint32? */
179
180
181
      /* only clamp if the gain is greater than 1.0
       * FIXME: real_vol_i can change while processing the buffer!
       */
182
      if (this->real_vol_i > VOLUME_UNITY_INT16)
183
184
185
186
187
        this->process = volume_process_int16_clamp;
      else
        this->process = volume_process_int16;
      break;
    case GST_VOLUME_FORMAT_FLOAT:
188
189
190
191
192
193
194
195
      switch (this->width) {
        case 32:
          this->process = volume_process_float;
          break;
        case 64:
          this->process = volume_process_double;
          break;
      }
196
197
      break;
    default:
198
      break;
199
200
201
  }
}

202
203
204
static void
volume_update_real_volume (GstVolume * this)
{
205
206
  gboolean passthrough = FALSE;

207
208
209
210
211
212
  if (this->mute) {
    this->real_vol_f = 0.0;
    this->real_vol_i = 0;
  } else {
    this->real_vol_f = this->volume_f;
    this->real_vol_i = this->volume_i;
213
    passthrough = (this->volume_i == VOLUME_UNITY_INT16);
214
  }
215
216
  volume_choose_func (this);
  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (this), passthrough);
217
218
219
220
}

/* Mixer interface */

221
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
222
gst_volume_interface_supported (GstImplementsInterface * iface, GType type)
223
224
225
226
227
228
{
  g_assert (type == GST_TYPE_MIXER);
  return TRUE;
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
229
gst_volume_interface_init (GstImplementsInterfaceClass * klass)
230
231
232
233
234
{
  klass->supported = gst_volume_interface_supported;
}

static const GList *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
235
gst_volume_list_tracks (GstMixer * mixer)
236
{
237
  GstVolume *this = GST_VOLUME (mixer);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
238

239
240
  g_return_val_if_fail (this != NULL, NULL);
  g_return_val_if_fail (GST_IS_VOLUME (this), NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
241

242
  return this->tracklist;
243
244
245
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
246
gst_volume_set_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
247
{
248
  GstVolume *this = GST_VOLUME (mixer);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
249

250
251
  g_return_if_fail (this != NULL);
  g_return_if_fail (GST_IS_VOLUME (this));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
252

253
  this->volume_f = (gfloat) volumes[0] / VOLUME_STEPS;
254
  this->volume_i = this->volume_f * VOLUME_UNITY_INT16;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
255

256
  volume_update_real_volume (this);
257
258
259
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
260
gst_volume_get_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
261
{
262
  GstVolume *this = GST_VOLUME (mixer);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
263

264
265
  g_return_if_fail (this != NULL);
  g_return_if_fail (GST_IS_VOLUME (this));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
266

267
  volumes[0] = (gint) this->volume_f * VOLUME_STEPS;
268
269
270
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
271
gst_volume_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
272
{
273
  GstVolume *this = GST_VOLUME (mixer);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
274

275
276
  g_return_if_fail (this != NULL);
  g_return_if_fail (GST_IS_VOLUME (this));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
277

278
  this->mute = mute;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
279

280
  volume_update_real_volume (this);
281
282
283
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
284
gst_volume_mixer_init (GstMixerClass * klass)
285
286
{
  GST_MIXER_TYPE (klass) = GST_MIXER_SOFTWARE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
287

288
289
290
291
292
293
294
  /* default virtual functions */
  klass->list_tracks = gst_volume_list_tracks;
  klass->set_volume = gst_volume_set_volume;
  klass->get_volume = gst_volume_get_volume;
  klass->set_mute = gst_volume_set_mute;
}

295
296
/* Element class */

297
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
298
gst_volume_dispose (GObject * object)
299
{
300
  GstVolume *volume = GST_VOLUME (object);
Colin Walters's avatar
Colin Walters committed
301

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
302
303
304
305
306
307
308
  if (volume->tracklist) {
    if (volume->tracklist->data)
      g_object_unref (volume->tracklist->data);
    g_list_free (volume->tracklist);
    volume->tracklist = NULL;
  }

309
310
311
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

312
static void
313
gst_volume_base_init (gpointer g_class)
314
315
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
316
317

  gst_element_class_add_pad_template (element_class,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
318
      gst_static_pad_template_get (&volume_src_template));
319
  gst_element_class_add_pad_template (element_class,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
320
      gst_static_pad_template_get (&volume_sink_template));
321
322
  gst_element_class_set_details (element_class, &volume_details);
}
323

Andy Wingo's avatar
Andy Wingo committed
324
static void
325
gst_volume_class_init (GstVolumeClass * klass)
Andy Wingo's avatar
Andy Wingo committed
326
327
{
  GObjectClass *gobject_class;
328
  GstBaseTransformClass *trans_class;
Andy Wingo's avatar
Andy Wingo committed
329

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
330
  gobject_class = (GObjectClass *) klass;
331
332
  trans_class = (GstBaseTransformClass *) klass;

333
334
335
  gobject_class->set_property = volume_set_property;
  gobject_class->get_property = volume_get_property;
  gobject_class->dispose = gst_volume_dispose;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
336

337
  g_object_class_install_property (gobject_class, PROP_MUTE,
338
      g_param_spec_boolean ("mute", "Mute", "mute channel",
Stefan Kost's avatar
Stefan Kost committed
339
          FALSE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
Andy Wingo's avatar
Andy Wingo committed
340

341
  g_object_class_install_property (gobject_class, PROP_VOLUME,
342
      g_param_spec_double ("volume", "Volume", "volume factor",
Stefan Kost's avatar
Stefan Kost committed
343
344
          0.0, VOLUME_MAX_DOUBLE, 1.0,
          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
Andy Wingo's avatar
Andy Wingo committed
345

346
347
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "volume", 0, "Volume gain");

348
349
  trans_class->transform_ip = GST_DEBUG_FUNCPTR (volume_transform_ip);
  trans_class->set_caps = GST_DEBUG_FUNCPTR (volume_set_caps);
Andy Wingo's avatar
Andy Wingo committed
350
351
352
}

static void
353
gst_volume_init (GstVolume * this, GstVolumeClass * g_class)
Andy Wingo's avatar
Andy Wingo committed
354
{
355
  GstMixerTrack *track = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
356

357
  this->mute = FALSE;
358
  this->volume_i = VOLUME_UNITY_INT16;
359
  this->volume_f = 1.0;
360
  this->real_vol_i = VOLUME_UNITY_INT16;
361
362
  this->real_vol_f = 1.0;
  this->tracklist = NULL;
363
  this->format = GST_VOLUME_FORMAT_NONE;
364

365
  track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
366
367
368
369
370
371
372

  if (GST_IS_MIXER_TRACK (track)) {
    track->label = g_strdup ("volume");
    track->num_channels = 1;
    track->min_volume = 0;
    track->max_volume = VOLUME_STEPS;
    track->flags = GST_MIXER_TRACK_SOFTWARE;
373
    this->tracklist = g_list_append (this->tracklist, track);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
374
  }
Andy Wingo's avatar
Andy Wingo committed
375
376
}

377
378
379
380
/* NOTE: although it might be tempting to have volume_process_mute() which uses
 *       memset(bytes, 0, nbytes) for the vol=0 case, this has the downside that
 *       unmuting would unly take place after processing a buffer.
 */
Andy Wingo's avatar
Andy Wingo committed
381

382
static void
383
384
385
386
387
388
389
390
391
392
393
394
395
396
volume_process_double (GstVolume * this, gpointer bytes, guint n_bytes)
{
  gdouble *data = (gdouble *) bytes;
  guint i, num_samples;

  num_samples = n_bytes / sizeof (gdouble);

  for (i = 0; i < num_samples; i++) {
    *data++ *= this->real_vol_f;
  }
}

static void
volume_process_float (GstVolume * this, gpointer bytes, guint n_bytes)
397
{
398
399
  gfloat *data = (gfloat *) bytes;
  guint i, num_samples;
400

401
  num_samples = n_bytes / sizeof (gfloat);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
402

403
  for (i = 0; i < num_samples; i++) {
404
    *data++ *= this->real_vol_f;
405
  }
406
  /* FIXME: seems to be slower than above!
407
408
     oil_scalarmultiply_f32_ns (data, data, &this->real_vol_f, num_samples);
   */
409
}
410

411
static void
412
volume_process_int16 (GstVolume * this, gpointer bytes, guint n_bytes)
413
{
414
  gint16 *data = (gint16 *) bytes;
415
416
  guint i, num_samples;
  gint val;
417
418
419

  num_samples = n_bytes / sizeof (gint16);

420
421
  /* FIXME: need... liboil... 
   * oil_scalarmultiply_s16_ns ?
422
   * https://bugs.freedesktop.org/show_bug.cgi?id=7060
423
   */
424
425
426
  for (i = 0; i < num_samples; i++) {
    /* we use bitshifting instead of dividing by UNITY_INT for speed */
    val = (gint) * data;
427
428
    *data++ =
        (gint16) ((this->real_vol_i * val) >> VOLUME_UNITY_INT16_BIT_SHIFT);
429
430
  }
}
431

432
static void
433
volume_process_int16_clamp (GstVolume * this, gpointer bytes, guint n_bytes)
434
{
435
  gint16 *data = (gint16 *) bytes;
436
437
  guint i, num_samples;
  gint val;
438
439
440
441
442
443

  num_samples = n_bytes / sizeof (gint16);

  /* FIXME: need... liboil... 
   * oil_scalarmultiply_s16_ns ?
   * https://bugs.freedesktop.org/show_bug.cgi?id=7060
444
   */
445
446
447
448
  for (i = 0; i < num_samples; i++) {
    /* we use bitshifting instead of dividing by UNITY_INT for speed */
    val = (gint) * data;
    *data++ =
449
450
451
        (gint16) CLAMP ((this->real_vol_i *
            val) >> VOLUME_UNITY_INT16_BIT_SHIFT, VOLUME_MIN_INT16,
        VOLUME_MAX_INT16);
Andy Wingo's avatar
Andy Wingo committed
452
453
454
  }
}

455
456
457
/* GstBaseTransform vmethod implementations */

/* get notified of caps and plug in the correct process function */
458
static gboolean
459
460
461
volume_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps)
{
  GstVolume *this = GST_VOLUME (base);
462
  const gchar *mimetype;
463
  GstStructure *structure;
464

465
466
  GST_DEBUG_OBJECT (this,
      "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
467

468
469
470
  structure = gst_caps_get_structure (incaps, 0);
  gst_structure_get_int (structure, "width", &this->width);
  mimetype = gst_structure_get_name (structure);
471

472
473
474
  /* based on mimetype, choose the correct volume_process format */
  if (strcmp (mimetype, "audio/x-raw-int") == 0) {
    this->format = GST_VOLUME_FORMAT_INT;
475
    GST_DEBUG_OBJECT (this, "use int: %u", this->width);
476
477
  } else if (strcmp (mimetype, "audio/x-raw-float") == 0) {
    this->format = GST_VOLUME_FORMAT_FLOAT;
478
    GST_DEBUG_OBJECT (this, "use float: %u", this->width);
479
  } else {
480
    this->process = NULL;
481
    goto invalid_format;
482
  }
483
  volume_choose_func (this);
484
485
486
487
488
489

  return TRUE;

  /* ERRORS */
invalid_format:
  {
490
    GST_ELEMENT_ERROR (this, CORE, NEGOTIATION,
491
        ("Invalid incoming caps: %" GST_PTR_FORMAT, incaps), (NULL));
492
493
494
495
496
497
498
499
500
    return FALSE;
  }
}

/* call the plugged-in process function for this instance
 * needs to be done with this indirection since volume_transform is
 * a class-global method
 */
static GstFlowReturn
501
volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
502
503
{
  GstVolume *this = GST_VOLUME (base);
504
505
  GstClockTime timestamp;

506
507
508
  /* don't process data in passthrough-mode */
  if (gst_base_transform_is_passthrough (base))
    return GST_FLOW_OK;
509

510
511
512
  /* FIXME: if controllers are bound, subdivide GST_BUFFER_SIZE into small
   * chunks for smooth fades, what is small? 1/10th sec.
   */
513
  timestamp = GST_BUFFER_TIMESTAMP (outbuf);
514
515
516
517
518
  timestamp =
      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);

  GST_DEBUG_OBJECT (base, "sync to %" GST_TIME_FORMAT,
      GST_TIME_ARGS (timestamp));
519

520
521
  if (GST_CLOCK_TIME_IS_VALID (timestamp))
    gst_object_sync_values (G_OBJECT (this), timestamp);
Stefan Kost's avatar
Stefan Kost committed
522

523
  this->process (this, GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
524
525
526
527

  return GST_FLOW_OK;
}

528
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
529
volume_update_mute (const GValue * value, gpointer data)
530
{
531
  GstVolume *this = (GstVolume *) data;
Andy Wingo's avatar
Andy Wingo committed
532

533
  g_return_if_fail (GST_IS_VOLUME (this));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
534
535

  if (G_VALUE_HOLDS_BOOLEAN (value)) {
536
    this->mute = g_value_get_boolean (value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
537
  } else if (G_VALUE_HOLDS_INT (value)) {
538
    this->mute = (g_value_get_int (value) == 1);
539
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
540

541
  volume_update_real_volume (this);
542
}
Andy Wingo's avatar
Andy Wingo committed
543

544
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
545
volume_update_volume (const GValue * value, gpointer data)
546
{
547
  GstVolume *this = (GstVolume *) data;
548

549
  g_return_if_fail (GST_IS_VOLUME (this));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
550

551
  this->volume_f = g_value_get_double (value);
552
  this->volume_i = this->volume_f * VOLUME_UNITY_INT16;
553
554

  volume_update_real_volume (this);
555
}
Andy Wingo's avatar
Andy Wingo committed
556
557

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
558
559
volume_set_property (GObject * object, guint prop_id, const GValue * value,
    GParamSpec * pspec)
Andy Wingo's avatar
Andy Wingo committed
560
{
561
  GstVolume *this = GST_VOLUME (object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
562
563

  switch (prop_id) {
564
    case PROP_MUTE:
565
      volume_update_mute (value, this);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
566
      break;
567
    case PROP_VOLUME:
568
      volume_update_volume (value, this);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
569
570
571
572
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
Andy Wingo's avatar
Andy Wingo committed
573
574
575
576
  }
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
577
578
volume_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
Andy Wingo's avatar
Andy Wingo committed
579
{
580
  GstVolume *this = GST_VOLUME (object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
581

Andy Wingo's avatar
Andy Wingo committed
582
  switch (prop_id) {
583
    case PROP_MUTE:
584
      g_value_set_boolean (value, this->mute);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
585
      break;
586
    case PROP_VOLUME:
587
      g_value_set_double (value, this->volume_f);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
588
589
590
591
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
Andy Wingo's avatar
Andy Wingo committed
592
593
594
595
  }
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
596
plugin_init (GstPlugin * plugin)
Andy Wingo's avatar
Andy Wingo committed
597
{
598
599
  /*oil_init (); */

600
601
602
  /* initialize gst controller library */
  gst_controller_init (NULL, NULL);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
603
604
  return gst_element_register (plugin, "volume", GST_RANK_NONE,
      GST_TYPE_VOLUME);
Andy Wingo's avatar
Andy Wingo committed
605
606
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
607
608
609
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "volume",
610
    "plugin for controlling audio volume",
611
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);