Пример #1
0
static gboolean
gst_audioringbuffer_open_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->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;
  }
}
static gboolean
gst_audio_sink_ring_buffer_close_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->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;
    }
}
Пример #3
0
static gboolean
gst_audioringbuffer_activate (GstRingBuffer * buf, gboolean active)
{
  GstAudioSink *sink;
  GstAudioRingBuffer *abuf;
  GError *error = NULL;

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  abuf = GST_AUDIORING_BUFFER_CAST (buf);

  if (active) {
    abuf->running = TRUE;

    GST_DEBUG_OBJECT (sink, "starting thread");
    sink->thread =
        g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
        &error);
    if (!sink->thread || error != NULL)
      goto thread_failed;

    GST_DEBUG_OBJECT (sink, "waiting for thread");
    /* the object lock is taken */
    GST_AUDIORING_BUFFER_WAIT (buf);
    GST_DEBUG_OBJECT (sink, "thread is started");
  } else {
#ifndef GSTREAMER_LITE
    abuf->running = FALSE;
    GST_DEBUG_OBJECT (sink, "signal wait");
    GST_AUDIORING_BUFFER_SIGNAL (buf);

    GST_OBJECT_UNLOCK (buf);

    /* join the thread */
    g_thread_join (sink->thread);

    GST_OBJECT_LOCK (buf);
#else // GSTREAMER_LITE
    // We may get called with active set to FALSE several times.
    // See gst_base_audio_sink_change_state()
    if (abuf->running)
    {
      abuf->running = FALSE;
      GST_DEBUG_OBJECT (sink, "signal wait");
      GST_AUDIORING_BUFFER_SIGNAL (buf);

      GST_OBJECT_UNLOCK (buf);

      /* join the thread */
      if (sink->thread != NULL)
      {
        g_thread_join (sink->thread);
        sink->thread = NULL;
      }

      GST_OBJECT_LOCK (buf);
    }
#endif // GSTREAMER_LITE
  }
  return TRUE;

  /* ERRORS */
thread_failed:
  {
    if (error)
      GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
    else
      GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
    return FALSE;
  }
}
Пример #4
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;
    }
}
Пример #6
0
static gboolean
NAS_createFlow (GstNasSink * sink, GstRingBufferSpec * spec)
{
  AuElement elements[2];
  AuUint32 buf_samples;
  unsigned char format;

  format = gst_nas_sink_sink_get_format (spec);
  if (format == 0) {
    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
        ("Unable to get format %d", spec->format));
    return FALSE;
  }
  GST_DEBUG_OBJECT (sink, "Format: %d %d\n", spec->format, format);

  sink->flow = AuGetScratchFlow (sink->audio, NULL);
  if (sink->flow == 0) {
    GST_DEBUG_OBJECT (sink, "couldn't get flow");
    return FALSE;
  }

  /* free old Elements and reconnet to server, needed to change samplerate */
  {
    AuBool clocked;
    int num_elements;
    AuStatus status;
    AuElement *oldelems;

    oldelems =
        AuGetElements (sink->audio, sink->flow, &clocked, &num_elements,
        &status);
    if (num_elements > 0) {
      GST_DEBUG_OBJECT (sink, "GetElements status: %i", status);
      if (oldelems)
        AuFreeElements (sink->audio, num_elements, oldelems);
      gst_nas_sink_close (GST_AUDIO_SINK (sink));
      gst_nas_sink_open (GST_AUDIO_SINK (sink));
      sink->flow = AuGetScratchFlow (sink->audio, NULL);
      if (sink->flow == 0) {
        GST_DEBUG_OBJECT (sink, "couldn't get flow");
        return FALSE;
      }
    }
  }

  /* free old Elements and reconnet to server, needed to change samplerate */
  {
    AuBool clocked;
    int num_elements;
    AuStatus status;
    AuElement *oldelems;

    oldelems =
        AuGetElements (sink->audio, sink->flow, &clocked, &num_elements,
        &status);
    if (num_elements > 0) {
      GST_DEBUG_OBJECT (sink, "GetElements status: %i", status);
      if (oldelems)
        AuFreeElements (sink->audio, num_elements, oldelems);
      gst_nas_sink_close (GST_AUDIO_SINK (sink));
      gst_nas_sink_open (GST_AUDIO_SINK (sink));
      sink->flow = AuGetScratchFlow (sink->audio, NULL);
      if (sink->flow == 0) {
        GST_DEBUG_OBJECT (sink, "couldn't get flow");
        return FALSE;
      }
    }
  }

  buf_samples = spec->rate * NAS_SOUND_PORT_DURATION;
  /*
     spec->segsize = gst_util_uint64_scale (buf_samples * spec->bytes_per_sample,
     spec->latency_time, GST_SECOND / GST_USECOND);
     spec->segsize -= spec->segsize % spec->bytes_per_sample;
     spec->segtotal = spec->buffer_time / spec->latency_time;
   */
  spec->segsize = buf_samples * spec->bytes_per_sample;
  spec->segtotal = 1;

  GST_DEBUG_OBJECT (sink, "Rate %d Format %d tracks %d bufs %d %d/%d w %d",
      spec->rate, format, spec->channels, (gint) buf_samples, spec->segsize,
      spec->segtotal, spec->width);
  AuMakeElementImportClient (&elements[0],      /* element */
      spec->rate,               /* rate */
      format,                   /* format */
      spec->channels,           /* number of tracks */
      AuTrue,                   /* discart */
      buf_samples,              /* max samples */
      (AuUint32) (buf_samples / 100 * AuSoundPortLowWaterMark),
      /* low water mark */
      0,                        /* num actions */
      NULL);

  sink->device = NAS_getDevice (sink->audio, spec->channels);
  if (sink->device == AuNone) {
    GST_DEBUG_OBJECT (sink, "no device with %i tracks found", spec->channels);
    return FALSE;
  }

  AuMakeElementExportDevice (&elements[1],      /* element */
      0,                        /* input */
      sink->device,             /* device */
      spec->rate,               /* rate */
      AuUnlimitedSamples,       /* num samples */
      0,                        /* num actions */
      NULL);                    /* actions */

  AuSetElements (sink->audio,   /* server */
      sink->flow,               /* flow ID */
      AuTrue,                   /* clocked */
      2,                        /* num elements */
      elements,                 /* elements */
      NULL);

  AuRegisterEventHandler (sink->audio,  /* server */
      AuEventHandlerIDMask,     /* value mask */
      0,                        /* type */
      sink->flow,               /* flow ID */
      NAS_EventHandler,         /* callback */
      (AuPointer) sink);        /* data */

  AuStartFlow (sink->audio, sink->flow, NULL);

  return TRUE;
}