StreamStatusMessagePtr StreamStatusMessage::create(const ObjectPtr & source, StreamStatusType type, const ElementPtr & owner) { GstMessage *m = gst_message_new_stream_status(source, static_cast<GstStreamStatusType>(type), owner); return StreamStatusMessagePtr::wrap(m, false); }
static gpointer render_thread_func (GstEglGlesSink * eglglessink) { GstMessage *message; GValue val = { 0 }; GstDataQueueItem *item = NULL; GstFlowReturn last_flow = GST_FLOW_OK; g_value_init (&val, G_TYPE_POINTER); g_value_set_pointer (&val, g_thread_self ()); message = gst_message_new_stream_status (GST_OBJECT_CAST (eglglessink), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (eglglessink)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (eglglessink, "posting ENTER stream status"); gst_element_post_message (GST_ELEMENT_CAST (eglglessink), message); g_value_unset (&val); gst_egl_adaptation_bind_API (eglglessink->egl_context); while (gst_data_queue_pop (eglglessink->queue, &item)) { GstBuffer *buf = NULL; GstMiniObject *object = item->object; GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT, object); if (GST_IS_BUFFER (object)) { GstCaps *caps; buf = GST_BUFFER_CAST (item->object); caps = GST_BUFFER_CAPS (buf); if (caps != eglglessink->configured_caps) { if (!gst_eglglessink_configure_caps (eglglessink, caps)) { g_mutex_lock (eglglessink->render_lock); eglglessink->last_flow = GST_FLOW_NOT_NEGOTIATED; g_cond_broadcast (eglglessink->render_cond); g_mutex_unlock (eglglessink->render_lock); item->destroy (item); break; } } if (eglglessink->configured_caps) { last_flow = gst_eglglessink_upload (eglglessink, buf); if (last_flow == GST_FLOW_OK) { last_flow = gst_eglglessink_render (eglglessink); } } else { GST_DEBUG_OBJECT (eglglessink, "No caps configured yet, not drawing anything"); } } else if (!object) { if (eglglessink->configured_caps) { last_flow = gst_eglglessink_render (eglglessink); } else { last_flow = GST_FLOW_OK; GST_DEBUG_OBJECT (eglglessink, "No caps configured yet, not drawing anything"); } } else { g_assert_not_reached (); } item->destroy (item); g_mutex_lock (eglglessink->render_lock); eglglessink->last_flow = last_flow; g_cond_broadcast (eglglessink->render_cond); g_mutex_unlock (eglglessink->render_lock); if (last_flow != GST_FLOW_OK) break; GST_DEBUG_OBJECT (eglglessink, "Successfully handled object"); } if (last_flow == GST_FLOW_OK) { g_mutex_lock (eglglessink->render_lock); eglglessink->last_flow = GST_FLOW_WRONG_STATE; g_cond_broadcast (eglglessink->render_cond); g_mutex_unlock (eglglessink->render_lock); } GST_DEBUG_OBJECT (eglglessink, "Shutting down thread"); /* EGL/GLES cleanup */ gst_egl_adaptation_cleanup (eglglessink->egl_context); if (eglglessink->configured_caps) { gst_caps_unref (eglglessink->configured_caps); eglglessink->configured_caps = NULL; } g_value_init (&val, G_TYPE_POINTER); g_value_set_pointer (&val, g_thread_self ()); message = gst_message_new_stream_status (GST_OBJECT_CAST (eglglessink), GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (eglglessink)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (eglglessink, "posting LEAVE stream status"); gst_element_post_message (GST_ELEMENT_CAST (eglglessink), message); g_value_unset (&val); return NULL; }
/* this internal thread does nothing else but read samples from the audio device. * It will read 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) { GstAudioSrc *src; GstAudioSrcClass *csrc; GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER (buf); ReadFunc readfunc; GstMessage *message; GValue val = { 0 }; src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf)); csrc = GST_AUDIO_SRC_GET_CLASS (src); GST_DEBUG_OBJECT (src, "enter thread"); readfunc = csrc->read; if (readfunc == NULL) goto no_function; /* FIXME: maybe we should at least use a custom pointer type here? */ g_value_init (&val, G_TYPE_POINTER); g_value_set_pointer (&val, src->thread); message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (src)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (src, "posting ENTER stream status"); gst_element_post_message (GST_ELEMENT_CAST (src), message); while (TRUE) { gint left, len; guint8 *readptr; gint readseg; if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) { gint read; left = len; do { read = readfunc (src, readptr, left); GST_LOG_OBJECT (src, "transfered %d bytes of %d to segment %d", read, left, readseg); if (read < 0 || read > left) { GST_WARNING_OBJECT (src, "error reading data %d (reason: %s), skipping segment", read, g_strerror (errno)); break; } left -= read; readptr += read; } while (left > 0); /* we read one segment */ gst_ring_buffer_advance (buf, 1); } else { GST_OBJECT_LOCK (abuf); if (!abuf->running) goto stop_running; GST_DEBUG_OBJECT (src, "signal wait"); GST_AUDIORING_BUFFER_SIGNAL (buf); GST_DEBUG_OBJECT (src, "wait for action"); GST_AUDIORING_BUFFER_WAIT (buf); GST_DEBUG_OBJECT (src, "got signal"); if (!abuf->running) goto stop_running; GST_DEBUG_OBJECT (src, "continue running"); GST_OBJECT_UNLOCK (abuf); } } /* Will never be reached */ g_assert_not_reached (); return; /* ERROR */ no_function: { GST_DEBUG ("no write function, exit thread"); return; } stop_running: { GST_OBJECT_UNLOCK (abuf); GST_DEBUG ("stop running, exit thread"); message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (src)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (src, "posting LEAVE stream status"); gst_element_post_message (GST_ELEMENT_CAST (src), 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 (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; } }