~ubuntu-branches/ubuntu/feisty/gst-plugins-good0.10/feisty-security

« back to all changes in this revision

Viewing changes to sys/sunaudio/gstsunaudiosink.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-12-21 21:12:15 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20061221211215-3uukkusokhe0nk4f
Tags: 0.10.5-0ubuntu1
* Sync with pkg-gstreamer SVN:
  + debian/rules:
    - Use Ubuntu as distribution name and point to the proper Launchpad URL
  + debian/patches/01_esdsink-priority.patch:
    - Mark the esdsink with rank primary-2 to get
      pulse > alsadmix > esd > alsa > oss

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
 
43
43
#include <fcntl.h>
44
44
#include <string.h>
 
45
#include <stropts.h>
45
46
#include <unistd.h>
46
47
#include <sys/mman.h>
47
48
 
48
49
#include "gstsunaudiosink.h"
49
50
 
 
51
GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug);
 
52
#define GST_CAT_DEFAULT sunaudio_debug
 
53
 
50
54
/* elementfactory information */
51
55
static const GstElementDetails plugin_details =
52
56
GST_ELEMENT_DETAILS ("Sun Audio Sink",
59
63
static void gst_sunaudiosink_class_init (GstSunAudioSinkClass * klass);
60
64
static void gst_sunaudiosink_init (GstSunAudioSink * filter);
61
65
static void gst_sunaudiosink_dispose (GObject * object);
 
66
static void gst_sunaudiosink_finalize (GObject * object);
62
67
 
63
68
static void gst_sunaudiosink_set_property (GObject * object, guint prop_id,
64
69
    const GValue * value, GParamSpec * pspec);
128
133
}
129
134
 
130
135
static void
 
136
gst_sunaudiosink_finalize (GObject * object)
 
137
{
 
138
  GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (object);
 
139
 
 
140
  g_mutex_free (sunaudiosink->write_mutex);
 
141
  g_cond_free (sunaudiosink->sleep_cond);
 
142
 
 
143
  g_free (sunaudiosink->device);
 
144
 
 
145
  if (sunaudiosink->fd != -1) {
 
146
    close (sunaudiosink->fd);
 
147
    sunaudiosink->fd = -1;
 
148
  }
 
149
 
 
150
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
151
}
 
152
 
 
153
static void
131
154
gst_sunaudiosink_base_init (gpointer g_class)
132
155
{
133
156
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
155
178
  parent_class = g_type_class_peek_parent (klass);
156
179
 
157
180
  gobject_class->dispose = gst_sunaudiosink_dispose;
 
181
  gobject_class->finalize = gst_sunaudiosink_finalize;
 
182
 
158
183
  gobject_class->set_property =
159
184
      GST_DEBUG_FUNCPTR (gst_sunaudiosink_set_property);
160
185
  gobject_class->get_property =
174
199
  g_object_class_install_property (gobject_class, PROP_DEVICE,
175
200
      g_param_spec_string ("device", "Device", "Audio Device (/dev/audio)",
176
201
          DEFAULT_DEVICE, G_PARAM_READWRITE));
177
 
 
178
202
}
179
203
 
180
204
static void
181
205
gst_sunaudiosink_init (GstSunAudioSink * sunaudiosink)
182
206
{
 
207
  GstBaseAudioSink *ba_sink = GST_BASE_AUDIO_SINK (sunaudiosink);
183
208
  const char *audiodev;
184
209
 
185
210
  GST_DEBUG_OBJECT (sunaudiosink, "initializing sunaudiosink");
190
215
  if (audiodev == NULL)
191
216
    audiodev = DEFAULT_DEVICE;
192
217
  sunaudiosink->device = g_strdup (audiodev);
 
218
 
 
219
  /* mutex and gconf used to control the write method */
 
220
  sunaudiosink->write_mutex = g_mutex_new ();
 
221
  sunaudiosink->sleep_cond = g_cond_new ();
193
222
}
194
223
 
195
224
static void
202
231
 
203
232
  switch (prop_id) {
204
233
    case PROP_DEVICE:
 
234
      GST_OBJECT_LOCK (sunaudiosink);
205
235
      g_free (sunaudiosink->device);
206
236
      sunaudiosink->device = g_strdup (g_value_get_string (value));
 
237
      GST_OBJECT_UNLOCK (sunaudiosink);
207
238
      break;
208
239
    default:
209
240
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221
252
 
222
253
  switch (prop_id) {
223
254
    case PROP_DEVICE:
 
255
      GST_OBJECT_LOCK (sunaudiosink);
224
256
      g_value_set_string (value, sunaudiosink->device);
 
257
      GST_OBJECT_UNLOCK (sunaudiosink);
225
258
      break;
226
259
    default:
227
260
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253
286
  int fd, ret;
254
287
 
255
288
  /* First try to open non-blocking */
 
289
  GST_OBJECT_LOCK (sunaudiosink);
256
290
  fd = open (sunaudiosink->device, O_WRONLY | O_NONBLOCK);
257
291
 
258
292
  if (fd >= 0) {
261
295
  }
262
296
 
263
297
  if (fd == -1) {
264
 
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, OPEN_WRITE, (NULL),
265
 
        ("can't open connection to Sun Audio device %s", sunaudiosink->device));
266
 
 
267
 
    return FALSE;
 
298
    GST_OBJECT_UNLOCK (sunaudiosink);
 
299
    goto open_failed;
268
300
  }
269
301
 
270
302
  sunaudiosink->fd = fd;
 
303
  GST_OBJECT_UNLOCK (sunaudiosink);
271
304
 
272
305
  ret = ioctl (fd, AUDIO_GETDEV, &sunaudiosink->dev);
273
 
  if (ret == -1) {
274
 
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
275
 
            strerror (errno)));
276
 
    return FALSE;
277
 
  }
 
306
  if (ret == -1)
 
307
    goto ioctl_error;
278
308
 
279
309
  GST_DEBUG_OBJECT (sunaudiosink, "name %s", sunaudiosink->dev.name);
280
310
  GST_DEBUG_OBJECT (sunaudiosink, "version %s", sunaudiosink->dev.version);
281
311
  GST_DEBUG_OBJECT (sunaudiosink, "config %s", sunaudiosink->dev.config);
282
312
 
283
313
  ret = ioctl (fd, AUDIO_GETINFO, &sunaudiosink->info);
284
 
  if (ret == -1) {
285
 
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
286
 
            strerror (errno)));
287
 
    return FALSE;
288
 
  }
 
314
  if (ret == -1)
 
315
    goto ioctl_error;
289
316
 
290
317
  GST_DEBUG_OBJECT (sunaudiosink, "monitor_gain %d",
291
318
      sunaudiosink->info.monitor_gain);
299
326
      sunaudiosink->info.sw_features_enabled);
300
327
 
301
328
  return TRUE;
 
329
 
 
330
open_failed:
 
331
  GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, OPEN_WRITE, (NULL),
 
332
      ("can't open connection to Sun Audio device %s", sunaudiosink->device));
 
333
  return FALSE;
 
334
ioctl_error:
 
335
  close (sunaudiosink->fd);
 
336
  GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
337
          strerror (errno)));
 
338
  return FALSE;
302
339
}
303
340
 
304
341
static gboolean
306
343
{
307
344
  GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink);
308
345
 
309
 
  close (sunaudiosink->fd);
310
 
  sunaudiosink->fd = -1;
 
346
  if (sunaudiosink->fd != -1) {
 
347
    close (sunaudiosink->fd);
 
348
    sunaudiosink->fd = -1;
 
349
  }
311
350
  return TRUE;
312
351
}
313
352
 
339
378
  ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
340
379
  ainfo.play.port = ports;
341
380
 
342
 
  /*
343
 
   * SunAudio doesn't really give access to buffer size, these values work.  Setting
344
 
   * the buffer so large (512K) is a bit annoying because this causes the volume
345
 
   * control in audio players to be slow in responding since the audio volume won't
346
 
   * change until the buffer empties.  SunAudio doesn't seem to allow changing the
347
 
   * audio output buffer size to anything smaller, though.  I notice setting the
348
 
   * values smaller causes the audio to stutter, which is worse.
349
 
   */
350
 
  spec->segsize = 4096;
351
 
  spec->segtotal = 128;
 
381
  /* buffer_time for playback is not implemented in Solaris at the moment,
 
382
     but at some point in the future, it might be */
 
383
  ainfo.play.buffer_size =
 
384
      gst_util_uint64_scale (spec->rate * spec->bytes_per_sample,
 
385
      spec->buffer_time, GST_SECOND / GST_USECOND);
 
386
 
352
387
  spec->silence_sample[0] = 0;
353
388
  spec->silence_sample[1] = 0;
354
389
  spec->silence_sample[2] = 0;
361
396
    return FALSE;
362
397
  }
363
398
 
 
399
  /* Now read back the info to find out the actual buffer size and set 
 
400
     segtotal */
 
401
  AUDIO_INITINFO (&ainfo);
 
402
 
 
403
  ret = ioctl (sunaudiosink->fd, AUDIO_GETINFO, &ainfo);
 
404
  if (ret == -1) {
 
405
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
406
            strerror (errno)));
 
407
    return FALSE;
 
408
  }
 
409
#if 0
 
410
  /* We don't actually use the buffer_size from the sound device, because
 
411
   * it seems it's just bogus sometimes */
 
412
  sunaudiosink->segtotal = spec->segtotal =
 
413
      ainfo.play.buffer_size / spec->segsize;
 
414
#else
 
415
  sunaudiosink->segtotal = spec->segtotal;
 
416
#endif
 
417
  sunaudiosink->segtotal_samples =
 
418
      spec->segtotal * spec->segsize / spec->bytes_per_sample;
 
419
 
 
420
  sunaudiosink->segs_written = (gint) ainfo.play.eof;
 
421
  sunaudiosink->samples_written = ainfo.play.samples;
 
422
  sunaudiosink->bytes_per_sample = spec->bytes_per_sample;
 
423
 
 
424
  GST_DEBUG_OBJECT (sunaudiosink, "Got device buffer_size of %u",
 
425
      ainfo.play.buffer_size);
 
426
 
364
427
  return TRUE;
365
428
}
366
429
 
370
433
  return TRUE;
371
434
}
372
435
 
 
436
#define LOOP_WHILE_EINTR(v,func) do { (v) = (func); } \
 
437
                while ((v) == -1 && errno == EINTR);
 
438
 
 
439
/* Called with the write_mutex held */
 
440
static void
 
441
gst_sunaudio_sink_do_delay (GstSunAudioSink * sink)
 
442
{
 
443
  GstBaseAudioSink *ba_sink = GST_BASE_AUDIO_SINK (sink);
 
444
  GstClockTime total_sleep;
 
445
  GstClockTime max_sleep;
 
446
  gint sleep_usecs;
 
447
  GTimeVal sleep_end;
 
448
  gint err;
 
449
  audio_info_t ainfo;
 
450
  guint diff;
 
451
 
 
452
  /* This code below ensures that we don't race any further than buffer_time 
 
453
   * ahead of the audio output, by sleeping if the next write call would cause
 
454
   * us to advance too far in the ring-buffer */
 
455
  LOOP_WHILE_EINTR (err, ioctl (sink->fd, AUDIO_GETINFO, &ainfo));
 
456
  if (err < 0)
 
457
    goto write_error;
 
458
 
 
459
  /* Compute our offset from the output (copes with overflow) */
 
460
  diff = (guint) (sink->segs_written) - ainfo.play.eof;
 
461
  if (diff > sink->segtotal) {
 
462
    /* This implies that reset did a flush just as the sound device aquired
 
463
     * some buffers internally, and it causes us to be out of sync with the
 
464
     * eof measure. This corrects it */
 
465
    sink->segs_written = ainfo.play.eof;
 
466
    diff = 0;
 
467
  }
 
468
 
 
469
  if (diff + 1 < sink->segtotal)
 
470
    return;                     /* no need to sleep at all */
 
471
 
 
472
  /* Never sleep longer than the initial number of undrained segments in the 
 
473
     device plus one */
 
474
  total_sleep = 0;
 
475
  max_sleep = (diff + 1) * (ba_sink->latency_time * GST_USECOND);
 
476
  /* sleep for a segment period between .eof polls */
 
477
  sleep_usecs = ba_sink->latency_time;
 
478
 
 
479
  /* Current time is our reference point */
 
480
  g_get_current_time (&sleep_end);
 
481
 
 
482
  /* If the next segment would take us too far along the ring buffer,
 
483
   * sleep for a bit to free up a slot. If there were a way to find out
 
484
   * when the eof field actually increments, we could use, but the only
 
485
   * notification mechanism seems to be SIGPOLL, which we can't use from
 
486
   * a support library */
 
487
  while (diff + 1 >= sink->segtotal && total_sleep < max_sleep) {
 
488
    GST_LOG_OBJECT (sink, "need to block to drain segment(s). "
 
489
        "Sleeping for %d us", sleep_usecs);
 
490
 
 
491
    g_time_val_add (&sleep_end, sleep_usecs);
 
492
 
 
493
    if (g_cond_timed_wait (sink->sleep_cond, sink->write_mutex, &sleep_end)) {
 
494
      GST_LOG_OBJECT (sink, "Waking up early due to reset");
 
495
      return;                   /* Got told to wake up */
 
496
    }
 
497
    total_sleep += (sleep_usecs * GST_USECOND);
 
498
 
 
499
    LOOP_WHILE_EINTR (err, ioctl (sink->fd, AUDIO_GETINFO, &ainfo));
 
500
    if (err < 0)
 
501
      goto write_error;
 
502
 
 
503
    /* Compute our (new) offset from the output (copes with overflow) */
 
504
    diff = (guint) g_atomic_int_get (&sink->segs_written) - ainfo.play.eof;
 
505
  }
 
506
 
 
507
  return;
 
508
 
 
509
write_error:
 
510
  GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
 
511
      ("Playback error on device '%s': %s", sink->device, strerror (errno)));
 
512
  return;
 
513
poll_failed:
 
514
  GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
 
515
      ("Playback error on device '%s': %s", sink->device, strerror (errno)));
 
516
  return;
 
517
}
 
518
 
373
519
static guint
374
520
gst_sunaudiosink_write (GstAudioSink * asink, gpointer data, guint length)
375
521
{
376
 
  return write (GST_SUNAUDIO_SINK (asink)->fd, data, length);
 
522
  GstSunAudioSink *sink = GST_SUNAUDIO_SINK (asink);
 
523
 
 
524
  gint bytes_written, err;
 
525
 
 
526
  g_mutex_lock (sink->write_mutex);
 
527
  if (sink->flushing) {
 
528
    /* Exit immediately if reset tells us to */
 
529
    g_mutex_unlock (sink->write_mutex);
 
530
    return length;
 
531
  }
 
532
 
 
533
  LOOP_WHILE_EINTR (bytes_written, write (sink->fd, data, length));
 
534
  if (bytes_written < 0) {
 
535
    err = bytes_written;
 
536
    goto write_error;
 
537
  }
 
538
 
 
539
  /* Increment our sample counter, for delay calcs */
 
540
  g_atomic_int_add (&sink->samples_written, length / sink->bytes_per_sample);
 
541
 
 
542
  /* Don't consider the segment written if we didn't output the whole lot yet */
 
543
  if (bytes_written < length) {
 
544
    g_mutex_unlock (sink->write_mutex);
 
545
    return (guint) bytes_written;
 
546
  }
 
547
 
 
548
  /* Write a zero length output to trigger increment of the eof field */
 
549
  LOOP_WHILE_EINTR (err, write (sink->fd, NULL, 0));
 
550
  if (err < 0)
 
551
    goto write_error;
 
552
 
 
553
  /* Count this extra segment we've written */
 
554
  sink->segs_written += 1;
 
555
 
 
556
  /* Now delay so we don't overrun the ring buffer */
 
557
  gst_sunaudio_sink_do_delay (sink);
 
558
 
 
559
  g_mutex_unlock (sink->write_mutex);
 
560
  return length;
 
561
 
 
562
write_error:
 
563
  g_mutex_unlock (sink->write_mutex);
 
564
 
 
565
  GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
 
566
      ("Playback error on device '%s': %s", sink->device, strerror (errno)));
 
567
  return length;                /* Say we wrote the segment to let the ringbuffer exit */
377
568
}
378
569
 
379
570
/*
380
 
 * Should provide the current delay between writing a sample to the
381
 
 * audio device and that sample being actually played.  Returning 0 for
382
 
 * now, but this isn't good for synchronization
383
 
 */
 
571
 * Provide the current number of unplayed samples that have been written
 
572
 * to the device */
384
573
static guint
385
574
gst_sunaudiosink_delay (GstAudioSink * asink)
386
575
{
387
 
  return 0;
 
576
  GstSunAudioSink *sink = GST_SUNAUDIO_SINK (asink);
 
577
  audio_info_t ainfo;
 
578
  gint ret;
 
579
  guint offset;
 
580
 
 
581
  ret = ioctl (sink->fd, AUDIO_GETINFO, &ainfo);
 
582
  if (G_UNLIKELY (ret == -1))
 
583
    return 0;
 
584
 
 
585
  offset = (g_atomic_int_get (&sink->samples_written) - ainfo.play.samples);
 
586
 
 
587
  /* If the offset is larger than the total ringbuffer size, then we asked
 
588
     between the write call and when samples_written is updated */
 
589
  if (G_UNLIKELY (offset > sink->segtotal_samples))
 
590
    return 0;
 
591
 
 
592
  return offset;
388
593
}
389
594
 
390
595
static void
391
596
gst_sunaudiosink_reset (GstAudioSink * asink)
392
597
{
 
598
  /* Get current values */
 
599
  GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink);
 
600
  audio_info_t ainfo;
 
601
  int ret;
 
602
 
 
603
  ret = ioctl (sunaudiosink->fd, AUDIO_GETINFO, &ainfo);
 
604
  if (ret == -1) {
 
605
    /*
 
606
     * Should never happen, but if we couldn't getinfo, then no point
 
607
     * trying to setinfo
 
608
     */
 
609
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
610
            strerror (errno)));
 
611
    return;
 
612
  }
 
613
 
 
614
  /*
 
615
   * Pause the audio - so audio stops playing immediately rather than
 
616
   * waiting for the ringbuffer to empty.
 
617
   */
 
618
  ainfo.play.pause = !NULL;
 
619
  ret = ioctl (sunaudiosink->fd, AUDIO_SETINFO, &ainfo);
 
620
  if (ret == -1) {
 
621
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
622
            strerror (errno)));
 
623
  }
 
624
 
 
625
  /* Flush the audio */
 
626
  ret = ioctl (sunaudiosink->fd, I_FLUSH, FLUSHW);
 
627
  if (ret == -1) {
 
628
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
629
            strerror (errno)));
 
630
  }
 
631
 
 
632
  /* Now, we take the write_mutex and signal to ensure the write thread
 
633
   * is not busy, and we signal the condition to wake up any sleeper,
 
634
   * then we flush again in case the write wrote something after we flushed,
 
635
   * and finally release the lock and unpause */
 
636
  g_mutex_lock (sunaudiosink->write_mutex);
 
637
  sunaudiosink->flushing = TRUE;
 
638
 
 
639
  g_cond_signal (sunaudiosink->sleep_cond);
 
640
 
 
641
  ret = ioctl (sunaudiosink->fd, I_FLUSH, FLUSHW);
 
642
  if (ret == -1) {
 
643
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
644
            strerror (errno)));
 
645
  }
 
646
 
 
647
  /* unpause the audio */
 
648
  ainfo.play.pause = NULL;
 
649
  ret = ioctl (sunaudiosink->fd, AUDIO_SETINFO, &ainfo);
 
650
  if (ret == -1) {
 
651
    GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s",
 
652
            strerror (errno)));
 
653
  }
 
654
 
 
655
  /* After flushing the audio device, we need to remeasure the sample count
 
656
   * and segments written count so we're in sync with the device */
 
657
 
 
658
  sunaudiosink->segs_written = ainfo.play.eof;
 
659
  g_atomic_int_set (&sunaudiosink->samples_written, ainfo.play.samples);
 
660
 
 
661
  sunaudiosink->flushing = FALSE;
 
662
  g_mutex_unlock (sunaudiosink->write_mutex);
393
663
}