gstosssink.c 14.7 KB
Newer Older
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
1 2
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3
 *               2000,2005 Wim Taymans <wim@fluendo.com>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * gstosssink.c: 
 *
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
19 20
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
21 22
 */

23 24 25 26
/**
 * SECTION:element-osssink
 *
 * This element lets you output sound using the Open Sound System (OSS).
27
 *
28 29 30 31
 * Note that you should almost always use generic audio conversion elements
 * like audioconvert and audioresample in front of an audiosink to make sure
 * your pipeline works under all circumstances (those conversion elements will
 * act in passthrough-mode if no conversion is necessary).
32 33
 *
 * <refsect2>
34
 * <title>Example pipelines</title>
35
 * |[
36
 * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! osssink
37
 * ]| will output a sine wave (continuous beep sound) to your sound card (with
38
 * a very low volume as precaution).
39
 * |[
40
 * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! osssink
41
 * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System.
42 43 44
 * </refsect2>
 */

45 46 47
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
48
#include <sys/ioctl.h>
49
#include <fcntl.h>
50
#include <errno.h>
51
#include <unistd.h>
52
#include <string.h>
53

54 55 56 57 58 59 60 61 62 63 64 65 66
#ifdef HAVE_OSS_INCLUDE_IN_SYS
# include <sys/soundcard.h>
#else
# ifdef HAVE_OSS_INCLUDE_IN_ROOT
#  include <soundcard.h>
# else
#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
#   include <machine/soundcard.h>
#  else
#   error "What to include?"
#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
#endif /* HAVE_OSS_INCLUDE_IN_SYS */
67

68
#include "common.h"
69
#include "gstosssink.h"
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
70

71 72
#include <gst/gst-i18n-plugin.h>

73 74 75
GST_DEBUG_CATEGORY_EXTERN (oss_debug);
#define GST_CAT_DEFAULT oss_debug

76
static void gst_oss_sink_dispose (GObject * object);
77
static void gst_oss_sink_finalise (GObject * object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
78

79 80 81 82 83
static void gst_oss_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void gst_oss_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
84
static GstCaps *gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85

86
static gboolean gst_oss_sink_open (GstAudioSink * asink);
87
static gboolean gst_oss_sink_close (GstAudioSink * asink);
88
static gboolean gst_oss_sink_prepare (GstAudioSink * asink,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
89
    GstAudioRingBufferSpec * spec);
90
static gboolean gst_oss_sink_unprepare (GstAudioSink * asink);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
91
static gint gst_oss_sink_write (GstAudioSink * asink, gpointer data,
92
    guint length);
93 94
static guint gst_oss_sink_delay (GstAudioSink * asink);
static void gst_oss_sink_reset (GstAudioSink * asink);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
95 96

/* OssSink signals and args */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
97 98
enum
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
99 100 101
  LAST_SIGNAL
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
102
#define DEFAULT_DEVICE  "/dev/dsp"
103 104 105 106 107 108
enum
{
  PROP_0,
  PROP_DEVICE,
};

109 110
#define FORMATS "{" GST_AUDIO_NE(S16)","GST_AUDIO_NE(U16)", S8, U8 }"

David Schleef's avatar
David Schleef committed
111
static GstStaticPadTemplate osssink_sink_factory =
112
    GST_STATIC_PAD_TEMPLATE ("sink",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
113 114
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
115 116
    GST_STATIC_CAPS ("audio/x-raw, "
        "format = (string) " FORMATS ", "
117 118 119 120 121 122 123 124
        "layout = (string) interleaved, "
        "rate = (int) [ 1, MAX ], "
        "channels = (int) 1; "
        "audio/x-raw, "
        "format = (string) " FORMATS ", "
        "layout = (string) interleaved, "
        "rate = (int) [ 1, MAX ], "
        "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
125
    );
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
126

127
/* static guint gst_oss_sink_signals[LAST_SIGNAL] = { 0 }; */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
128

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
129 130
#define gst_oss_sink_parent_class parent_class
G_DEFINE_TYPE (GstOssSink, gst_oss_sink, GST_TYPE_AUDIO_SINK);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
131

132
static void
133
gst_oss_sink_dispose (GObject * object)
134
{
135 136 137 138 139 140 141
  GstOssSink *osssink = GST_OSSSINK (object);

  if (osssink->probed_caps) {
    gst_caps_unref (osssink->probed_caps);
    osssink->probed_caps = NULL;
  }

142 143 144
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
145
static void
146
gst_oss_sink_class_init (GstOssSinkClass * klass)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
147 148
{
  GObjectClass *gobject_class;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
149
  GstElementClass *gstelement_class;
150 151
  GstBaseSinkClass *gstbasesink_class;
  GstAudioSinkClass *gstaudiosink_class;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
152

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
153
  gobject_class = (GObjectClass *) klass;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
154
  gstelement_class = (GstElementClass *) klass;
155 156 157
  gstbasesink_class = (GstBaseSinkClass *) klass;
  gstaudiosink_class = (GstAudioSinkClass *) klass;

158
  parent_class = g_type_class_peek_parent (klass);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
159

160 161 162 163
  gobject_class->dispose = gst_oss_sink_dispose;
  gobject_class->finalize = gst_oss_sink_finalise;
  gobject_class->get_property = gst_oss_sink_get_property;
  gobject_class->set_property = gst_oss_sink_set_property;
164 165 166

  g_object_class_install_property (gobject_class, PROP_DEVICE,
      g_param_spec_string ("device", "Device",
167 168
          "OSS device (usually /dev/dspN)", DEFAULT_DEVICE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
169

170
  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_sink_getcaps);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
171

172 173
  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss_sink_open);
  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss_sink_close);
174 175
  gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_sink_prepare);
  gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_sink_unprepare);
176 177 178
  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss_sink_write);
  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss_sink_delay);
  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss_sink_reset);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
179 180 181 182 183 184 185

  gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (OSS)",
      "Sink/Audio",
      "Output to a sound card via OSS",
      "Erik Walthinsen <omega@cse.ogi.edu>, "
      "Wim Taymans <wim.taymans@chello.be>");

186 187
  gst_element_class_add_static_pad_template (gstelement_class,
      &osssink_sink_factory);
Wim Taymans's avatar
Wim Taymans committed
188 189
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
190
static void
191
gst_oss_sink_init (GstOssSink * osssink)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
192
{
193 194
  const gchar *device;

195
  GST_DEBUG_OBJECT (osssink, "initializing osssink");
196

197 198 199 200
  device = g_getenv ("AUDIODEV");
  if (device == NULL)
    device = DEFAULT_DEVICE;
  osssink->device = g_strdup (device);
201
  osssink->fd = -1;
202
}
203

204 205 206 207 208 209
static void
gst_oss_sink_finalise (GObject * object)
{
  GstOssSink *osssink = GST_OSSSINK (object);

  g_free (osssink->device);
210 211

  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (object));
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225
static void
gst_oss_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstOssSink *sink;

  sink = GST_OSSSINK (object);

  switch (prop_id) {
    case PROP_DEVICE:
      g_free (sink->device);
      sink->device = g_value_dup_string (value);
226 227 228 229
      if (sink->probed_caps) {
        gst_caps_unref (sink->probed_caps);
        sink->probed_caps = NULL;
      }
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_oss_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstOssSink *sink;

  sink = GST_OSSSINK (object);

  switch (prop_id) {
    case PROP_DEVICE:
      g_value_set_string (value, sink->device);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

255
static GstCaps *
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
256
gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
257
{
258
  GstOssSink *osssink;
259 260
  GstCaps *caps;

261 262
  osssink = GST_OSSSINK (bsink);

263
  if (osssink->fd == -1) {
Wim Taymans's avatar
Wim Taymans committed
264
    caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
265
  } else if (osssink->probed_caps) {
Wim Taymans's avatar
Wim Taymans committed
266
    caps = gst_caps_ref (osssink->probed_caps);
267
  } else {
268
    caps = gst_oss_helper_probe_caps (osssink->fd);
269
    if (caps && !gst_caps_is_empty (caps)) {
Wim Taymans's avatar
Wim Taymans committed
270
      osssink->probed_caps = gst_caps_ref (caps);
271
    }
272 273
  }

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
274 275 276 277 278 279 280 281 282 283
  if (filter && caps) {
    GstCaps *intersection;

    intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (caps);
    return intersection;
  } else {
    return caps;
  }
284 285
}

286 287
static gint
ilog2 (gint x)
288
{
289 290 291 292 293 294 295 296 297 298 299 300
  /* well... hacker's delight explains... */
  x = x | (x >> 1);
  x = x | (x >> 2);
  x = x | (x >> 4);
  x = x | (x >> 8);
  x = x | (x >> 16);
  x = x - ((x >> 1) & 0x55555555);
  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  x = (x + (x >> 4)) & 0x0f0f0f0f;
  x = x + (x >> 8);
  x = x + (x >> 16);
  return (x & 0x0000003f) - 1;
301 302
}

303
static gint
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
304
gst_oss_sink_get_format (GstAudioRingBufferFormatType fmt, GstAudioFormat rfmt)
305 306 307 308
{
  gint result;

  switch (fmt) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
309
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
310 311
      result = AFMT_MU_LAW;
      break;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
312
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
313 314
      result = AFMT_A_LAW;
      break;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
315
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM:
316 317
      result = AFMT_IMA_ADPCM;
      break;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
318
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
319 320
      result = AFMT_MPEG;
      break;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
    {
      switch (rfmt) {
        case GST_AUDIO_FORMAT_U8:
          result = AFMT_U8;
          break;
        case GST_AUDIO_FORMAT_S16LE:
          result = AFMT_S16_LE;
          break;
        case GST_AUDIO_FORMAT_S16BE:
          result = AFMT_S16_BE;
          break;
        case GST_AUDIO_FORMAT_S8:
          result = AFMT_S8;
          break;
        case GST_AUDIO_FORMAT_U16LE:
          result = AFMT_U16_LE;
          break;
        case GST_AUDIO_FORMAT_U16BE:
          result = AFMT_U16_BE;
          break;
        default:
          result = 0;
          break;
      }
      break;
    }
348 349 350 351 352 353 354
    default:
      result = 0;
      break;
  }
  return result;
}

355
static gboolean
356
gst_oss_sink_open (GstAudioSink * asink)
Wim Taymans's avatar
Wim Taymans committed
357
{
358
  GstOssSink *oss;
359
  int mode;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
360

361
  oss = GST_OSSSINK (asink);
Wim Taymans's avatar
Wim Taymans committed
362

363 364
  mode = O_WRONLY;
  mode |= O_NONBLOCK;
Wim Taymans's avatar
Wim Taymans committed
365

366
  oss->fd = open (oss->device, mode, 0);
367 368 369 370
  if (oss->fd == -1) {
    switch (errno) {
      case EBUSY:
        goto busy;
371 372
      case EACCES:
        goto no_permission;
373 374 375 376
      default:
        goto open_failed;
    }
  }
377 378

  return TRUE;
379

Wim Taymans's avatar
Wim Taymans committed
380
  /* ERRORS */
381 382
busy:
  {
383 384 385 386 387 388 389 390
    GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
        (_("Could not open audio device for playback. "
                "Device is being used by another application.")), (NULL));
    return FALSE;
  }
no_permission:
  {
    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
391
        (_("Could not open audio device for playback. "
392 393
                "You don't have permission to open the device.")),
        GST_ERROR_SYSTEM);
394 395
    return FALSE;
  }
396 397
open_failed:
  {
398 399
    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
        (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
400 401
    return FALSE;
  }
402 403 404 405 406 407
}

static gboolean
gst_oss_sink_close (GstAudioSink * asink)
{
  close (GST_OSSSINK (asink)->fd);
408
  GST_OSSSINK (asink)->fd = -1;
409 410 411 412
  return TRUE;
}

static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
413
gst_oss_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
414 415 416 417 418
{
  GstOssSink *oss;
  struct audio_buf_info info;
  int mode;
  int tmp;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
419
  guint width, rate, channels;
420 421 422

  oss = GST_OSSSINK (asink);

423 424
  /* we opened non-blocking so that we can detect if the device is available
   * without hanging forever. We now want to remove the non-blocking flag. */
425 426
  mode = fcntl (oss->fd, F_GETFL);
  mode &= ~O_NONBLOCK;
427 428 429 430 431 432 433
  if (fcntl (oss->fd, F_SETFL, mode) == -1) {
    /* some drivers do no support unsetting the non-blocking flag, try to
     * close/open the device then. This is racy but we error out properly. */
    gst_oss_sink_close (asink);
    if ((oss->fd = open (oss->device, O_WRONLY, 0)) == -1)
      goto non_block;
  }
Wim Taymans's avatar
Wim Taymans committed
434

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
435 436
  tmp = gst_oss_sink_get_format (spec->type,
      GST_AUDIO_INFO_FORMAT (&spec->info));
437 438 439
  if (tmp == 0)
    goto wrong_format;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
440 441 442 443 444
  width = GST_AUDIO_INFO_WIDTH (&spec->info);
  rate = GST_AUDIO_INFO_RATE (&spec->info);
  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);

  if (width != 16 && width != 8)
445 446
    goto dodgy_width;

447
  SET_PARAM (oss, SNDCTL_DSP_SETFMT, tmp, "SETFMT");
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
448
  if (channels == 2)
449
    SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO");
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
450 451
  SET_PARAM (oss, SNDCTL_DSP_CHANNELS, channels, "CHANNELS");
  SET_PARAM (oss, SNDCTL_DSP_SPEED, rate, "SPEED");
452

453 454
  tmp = ilog2 (spec->segsize);
  tmp = ((spec->segtotal & 0x7fff) << 16) | tmp;
455 456
  GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x",
      spec->segsize, spec->segtotal, tmp);
Wim Taymans's avatar
Wim Taymans committed
457

458 459
  SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT");
  GET_PARAM (oss, SNDCTL_DSP_GETOSPACE, &info, "GETOSPACE");
Ronald S. Bultje's avatar
Ronald S. Bultje committed
460

461 462
  spec->segsize = info.fragsize;
  spec->segtotal = info.fragstotal;
463

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
464
  oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
465

466 467
  GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x",
      spec->segsize, spec->segtotal, tmp);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
468

469
  return TRUE;
470

Wim Taymans's avatar
Wim Taymans committed
471
  /* ERRORS */
472 473
non_block:
  {
474
    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
475
        ("Unable to set device %s in non blocking mode: %s",
476
            oss->device, g_strerror (errno)));
477 478
    return FALSE;
  }
479 480
wrong_format:
  {
481
    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
482 483
        ("Unable to get format (%d, %d)", spec->type,
            GST_AUDIO_INFO_FORMAT (&spec->info)));
484 485
    return FALSE;
  }
486 487
dodgy_width:
  {
488
    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
489
        ("unexpected width %d", width));
490 491
    return FALSE;
  }
492 493
}

494
static gboolean
495
gst_oss_sink_unprepare (GstAudioSink * asink)
496
{
497 498 499 500 501 502 503 504
  /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */

  if (!gst_oss_sink_close (asink))
    goto couldnt_close;

  if (!gst_oss_sink_open (asink))
    goto couldnt_reopen;

505
  return TRUE;
506

Wim Taymans's avatar
Wim Taymans committed
507
  /* ERRORS */
508 509
couldnt_close:
  {
510
    GST_DEBUG_OBJECT (asink, "Could not close the audio device");
511 512 513 514
    return FALSE;
  }
couldnt_reopen:
  {
515
    GST_DEBUG_OBJECT (asink, "Could not reopen the audio device");
516 517
    return FALSE;
  }
518 519
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
520
static gint
521
gst_oss_sink_write (GstAudioSink * asink, gpointer data, guint length)
522
{
523
  return write (GST_OSSSINK (asink)->fd, data, length);
524 525
}

526
static guint
527
gst_oss_sink_delay (GstAudioSink * asink)
528
{
529 530 531
  GstOssSink *oss;
  gint delay = 0;
  gint ret;
532

533
  oss = GST_OSSSINK (asink);
534

535 536 537 538 539 540 541
#ifdef SNDCTL_DSP_GETODELAY
  ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay);
#else
  ret = -1;
#endif
  if (ret < 0) {
    audio_buf_info info;
542

543
    ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
544

545
    delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
546
  }
547
  return delay / oss->bytes_per_sample;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
548 549
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
550
static void
551
gst_oss_sink_reset (GstAudioSink * asink)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
552
{
553 554 555
  /* There's nothing we can do here really: OSS can't handle access to the
   * same device/fd from multiple threads and might deadlock or blow up in
   * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
556
}