Пример #1
0
static gboolean
gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  gboolean result = FALSE;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  if (csink->prepare)
    result = csink->prepare (sink, spec);
  if (!result)
    goto could_not_prepare;

  /* set latency to one more segment as we need some headroom */
  spec->seglatency = spec->segtotal + 1;

  buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
  memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));

  return TRUE;

  /* ERRORS */
could_not_prepare:
  {
    GST_DEBUG_OBJECT (sink, "could not prepare device");
    return FALSE;
  }
}
Пример #2
0
static gboolean
gst_audioringbuffer_stop (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  /* unblock any pending writes to the audio device */
  if (csink->reset) {
    GST_DEBUG_OBJECT (sink, "reset...");
    csink->reset (sink);
    GST_DEBUG_OBJECT (sink, "reset done");
  }
#if 0
  if (abuf->running) {
    GST_DEBUG_OBJECT (sink, "stop, waiting...");
    GST_AUDIORING_BUFFER_WAIT (buf);
    GST_DEBUG_OBJECT (sink, "stopped");
  }
#endif

  return TRUE;
}
Пример #3
0
/* function is called with LOCK */
static gboolean
gst_audioringbuffer_release (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  gboolean result = FALSE;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  /* free the buffer */
  gst_buffer_unref (buf->data);
  buf->data = NULL;

  if (csink->unprepare)
    result = csink->unprepare (sink);

  if (!result)
    goto could_not_unprepare;

  GST_DEBUG_OBJECT (sink, "unprepared");

  return result;

could_not_unprepare:
  {
    GST_DEBUG_OBJECT (sink, "could not unprepare device");
    return FALSE;
  }
}
Пример #4
0
static guint
gst_audioringbuffer_delay (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  guint res = 0;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  if (csink->delay)
    res = csink->delay (sink);

  return res;
}
Пример #5
0
static gboolean
gst_audioringbuffer_pause (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  /* unblock any pending writes to the audio device */
  if (csink->reset) {
    GST_DEBUG_OBJECT (sink, "reset...");
    csink->reset (sink);
    GST_DEBUG_OBJECT (sink, "reset done");
  }

  return TRUE;
}
static gboolean
gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf,
                                    GstAudioRingBufferSpec * spec)
{
    GstAudioSink *sink;
    GstAudioSinkClass *csink;
    gboolean result = FALSE;

    sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
    csink = GST_AUDIO_SINK_GET_CLASS (sink);

    if (csink->prepare)
        result = csink->prepare (sink, spec);
    if (!result)
        goto could_not_prepare;

    /* set latency to one more segment as we need some headroom */
    spec->seglatency = spec->segtotal + 1;

    buf->size = spec->segtotal * spec->segsize;

    buf->memory = g_malloc (buf->size);

    if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
        gst_audio_format_fill_silence (buf->spec.info.finfo, buf->memory,
                                       buf->size);
    } else {
        /* FIXME, non-raw formats get 0 as the empty sample */
        memset (buf->memory, 0, buf->size);
    }


    return TRUE;

    /* ERRORS */
could_not_prepare:
    {
        GST_DEBUG_OBJECT (sink, "could not prepare device");
        return FALSE;
    }
}
Пример #7
0
static gboolean
gst_audioringbuffer_close_device (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  gboolean result = TRUE;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  if (csink->close)
    result = csink->close (sink);

  if (!result)
    goto could_not_close;

  return result;

could_not_close:
  {
    GST_DEBUG_OBJECT (sink, "could not close device");
    return FALSE;
  }
}
static gboolean
gst_audio_sink_ring_buffer_open_device (GstAudioRingBuffer * buf)
{
    GstAudioSink *sink;
    GstAudioSinkClass *csink;
    gboolean result = TRUE;

    sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
    csink = GST_AUDIO_SINK_GET_CLASS (sink);

    if (csink->open)
        result = csink->open (sink);

    if (!result)
        goto could_not_open;

    return result;

could_not_open:
    {
        GST_DEBUG_OBJECT (sink, "could not open device");
        return FALSE;
    }
}
Пример #9
0
/* this internal thread does nothing else but write samples to the audio device.
 * It will write each segment in the ringbuffer and will update the play
 * pointer.
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf);
  WriteFunc writefunc;
  GstMessage *message;
  GValue val = { 0 };

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  GST_DEBUG_OBJECT (sink, "enter thread");

  GST_OBJECT_LOCK (abuf);
  GST_DEBUG_OBJECT (sink, "signal wait");
  GST_AUDIORING_BUFFER_SIGNAL (buf);
  GST_OBJECT_UNLOCK (abuf);

  writefunc = csink->write;
  if (writefunc == NULL)
    goto no_function;

  g_value_init (&val, G_TYPE_POINTER);
  g_value_set_pointer (&val, sink->thread);
  message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
  gst_message_set_stream_status_object (message, &val);
  GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
  gst_element_post_message (GST_ELEMENT_CAST (sink), message);

  while (TRUE) {
    gint left, len;
    guint8 *readptr;
    gint readseg;

    /* buffer must be started */
    if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
      gint written;

      left = len;
      do {
        written = writefunc (sink, readptr, left);
        GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
            written, left, readseg);
        if (written < 0 || written > left) {
          /* might not be critical, it e.g. happens when aborting playback */
          GST_WARNING_OBJECT (sink,
              "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
              GST_DEBUG_FUNCPTR_NAME (writefunc),
              (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
          break;
        }
        left -= written;
        readptr += written;
      } while (left > 0);

      /* clear written samples */
      gst_ring_buffer_clear (buf, readseg);

      /* we wrote one segment */
      gst_ring_buffer_advance (buf, 1);
    } else {
      GST_OBJECT_LOCK (abuf);
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (sink, "signal wait");
      GST_AUDIORING_BUFFER_SIGNAL (buf);
      GST_DEBUG_OBJECT (sink, "wait for action");
#ifndef GSTREAMER_LITE
      GST_AUDIORING_BUFFER_WAIT (buf);
#else // GSTREAMER_LITE
      // In same cases we may have condition when we waiting here for ring buffer to start,
      // while ring buffer is started and data is available. So, lets use wait with timeout
      // and recheck if we good to go. wait_segment() will start ring buffer when data is available.
      {
          GTimeVal timeout;
          g_get_current_time(&timeout);
          g_time_val_add(&timeout, 100000); // 100 millisecond
          GST_AUDIORING_BUFFER_TIMED_WAIT (buf, &timeout);
      }
#endif // GSTREAMER_LITE
      GST_DEBUG_OBJECT (sink, "got signal");
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (sink, "continue running");
      GST_OBJECT_UNLOCK (abuf);
    }
  }

  /* Will never be reached */
  g_assert_not_reached ();
  return;

  /* ERROR */
no_function:
  {
    GST_DEBUG_OBJECT (sink, "no write function, exit thread");
    return;
  }
stop_running:
  {
    GST_OBJECT_UNLOCK (abuf);
    GST_DEBUG_OBJECT (sink, "stop running, exit thread");
    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
        GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
    gst_message_set_stream_status_object (message, &val);
    GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
    gst_element_post_message (GST_ELEMENT_CAST (sink), message);
    return;
  }
}
/* this internal thread does nothing else but write samples to the audio device.
 * It will write each segment in the ringbuffer and will update the play
 * pointer.
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstAudioRingBuffer * buf)
{
    GstAudioSink *sink;
    GstAudioSinkClass *csink;
    GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
    WriteFunc writefunc;
    GstMessage *message;
    GValue val = { 0 };

    sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
    csink = GST_AUDIO_SINK_GET_CLASS (sink);

    GST_DEBUG_OBJECT (sink, "enter thread");

    GST_OBJECT_LOCK (abuf);
    GST_DEBUG_OBJECT (sink, "signal wait");
    GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
    GST_OBJECT_UNLOCK (abuf);

    writefunc = csink->write;
    if (writefunc == NULL)
        goto no_function;

    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
              GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
    g_value_init (&val, GST_TYPE_G_THREAD);
    g_value_set_boxed (&val, g_thread_self ());
    gst_message_set_stream_status_object (message, &val);
    g_value_unset (&val);
    GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
    gst_element_post_message (GST_ELEMENT_CAST (sink), message);

    while (TRUE) {
        gint left, len;
        guint8 *readptr;
        gint readseg;

        /* buffer must be started */
        if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
            gint written;

            left = len;
            do {
                written = writefunc (sink, readptr, left);
                GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
                                written, left, readseg);
                if (written < 0 || written > left) {
                    /* might not be critical, it e.g. happens when aborting playback */
                    GST_WARNING_OBJECT (sink,
                                        "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
                                        GST_DEBUG_FUNCPTR_NAME (writefunc),
                                        (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
                    break;
                }
                left -= written;
                readptr += written;
            } while (left > 0);

            /* clear written samples */
            gst_audio_ring_buffer_clear (buf, readseg);

            /* we wrote one segment */
            gst_audio_ring_buffer_advance (buf, 1);
        } else {
            GST_OBJECT_LOCK (abuf);
            if (!abuf->running)
                goto stop_running;
            if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
                            GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
                GST_OBJECT_UNLOCK (abuf);
                continue;
            }
            GST_DEBUG_OBJECT (sink, "signal wait");
            GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
            GST_DEBUG_OBJECT (sink, "wait for action");
            GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
            GST_DEBUG_OBJECT (sink, "got signal");
            if (!abuf->running)
                goto stop_running;
            GST_DEBUG_OBJECT (sink, "continue running");
            GST_OBJECT_UNLOCK (abuf);
        }
    }

    /* Will never be reached */
    g_assert_not_reached ();
    return;

    /* ERROR */
no_function:
    {
        GST_DEBUG_OBJECT (sink, "no write function, exit thread");
        return;
    }
stop_running:
    {
        GST_OBJECT_UNLOCK (abuf);
        GST_DEBUG_OBJECT (sink, "stop running, exit thread");
        message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
                  GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
        g_value_init (&val, GST_TYPE_G_THREAD);
        g_value_set_boxed (&val, g_thread_self ());
        gst_message_set_stream_status_object (message, &val);
        g_value_unset (&val);
        GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
        gst_element_post_message (GST_ELEMENT_CAST (sink), message);
        return;
    }
}