static gint64 xmms_ringbuf_plugin_seek (xmms_xform_t *xform, gint64 offset, xmms_xform_seek_mode_t whence, xmms_error_t *error) { xmms_ringbuf_priv_t *priv; gint64 res = -1; priv = xmms_xform_private_data_get (xform); g_mutex_lock (&priv->state_lock); if (priv->state == STATE_BUFFERING) { priv->state = STATE_WANT_SEEK; priv->seek_offset = offset; priv->seek_whence = whence; xmms_ringbuf_set_eos (priv->buffer, TRUE); while (priv->state == STATE_WANT_SEEK) { g_cond_wait (&priv->state_cond, &priv->state_lock); } xmms_ringbuf_set_eos (priv->buffer, FALSE); if (priv->state == STATE_SEEK_DONE) { res = priv->seek_res; priv->state = STATE_WANT_BUFFER; } } g_cond_signal (&priv->state_cond); g_mutex_unlock (&priv->state_lock); return res; }
static gboolean song_changed (void *data) { /* executes in the output thread; NOT the filler thread */ xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data; xmms_medialib_entry_t entry; entry = xmms_xform_entry_get (arg->chain); XMMS_DBG ("Running hotspot! Song changed!! %d", entry); arg->output->played = 0; arg->output->current_entry = entry; if (!xmms_output_format_set (arg->output, xmms_xform_outtype_get (arg->chain))) { XMMS_DBG ("Couldn't set format, stopping filler.."); xmms_output_filler_state_nolock (arg->output, FILLER_STOP); xmms_ringbuf_set_eos (arg->output->filler_buffer, TRUE); return FALSE; } if (arg->flush) xmms_output_flush (arg->output); xmms_object_emit_f (XMMS_OBJECT (arg->output), XMMS_IPC_SIGNAL_OUTPUT_CURRENTID, XMMSV_TYPE_UINT32, entry); return TRUE; }
static void xmms_output_filler_state_nolock (xmms_output_t *output, xmms_output_filler_state_t state) { output->filler_state = state; g_cond_signal (output->filler_state_cond); if (state == FILLER_QUIT || state == FILLER_STOP || state == FILLER_KILL) { xmms_ringbuf_clear (output->filler_buffer); } if (state != FILLER_STOP) { xmms_ringbuf_set_eos (output->filler_buffer, FALSE); } }
static void fill (xmms_xform_t *xform, xmms_ringbuf_priv_t *priv) { xmms_error_t err; char buf[4096]; int res; res = xmms_xform_read (xform, buf, sizeof (buf), &err); if (res > 0) { xmms_ringbuf_write_wait (priv->buffer, buf, res, &priv->buffer_lock); } else if (res == -1) { /* XXX copy error */ g_mutex_lock (&priv->state_lock); priv->state = STATE_WANT_STOP; } else { xmms_ringbuf_set_eos (priv->buffer, TRUE); priv->state = STATE_WANT_STOP; } }
static gboolean song_changed (void *data) { /* executes in the output thread; NOT the filler thread */ xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data; xmms_medialib_entry_t entry; xmms_stream_type_t *type; entry = xmms_xform_entry_get (arg->chain); XMMS_DBG ("Running hotspot! Song changed!! %d", entry); arg->output->played = 0; arg->output->current_entry = entry; type = xmms_xform_outtype_get (arg->chain); if (!xmms_output_format_set (arg->output, type)) { gint fmt, rate, chn; fmt = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_FORMAT); rate = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_SAMPLERATE); chn = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_CHANNELS); XMMS_DBG ("Couldn't set format %s/%d/%d, stopping filler..", xmms_sample_name_get (fmt), rate, chn); xmms_output_filler_state_nolock (arg->output, FILLER_STOP); xmms_ringbuf_set_eos (arg->output->filler_buffer, TRUE); return FALSE; } if (arg->flush) xmms_output_flush (arg->output); xmms_object_emit (XMMS_OBJECT (arg->output), XMMS_IPC_SIGNAL_PLAYBACK_CURRENTID, xmmsv_new_int (entry)); return TRUE; }
static void * xmms_output_filler (void *arg) { xmms_output_t *output = (xmms_output_t *)arg; xmms_xform_t *chain = NULL; gboolean last_was_kill = FALSE; char buf[4096]; xmms_error_t err; gint ret; xmms_error_reset (&err); g_mutex_lock (output->filler_mutex); while (output->filler_state != FILLER_QUIT) { if (output->filler_state == FILLER_STOP) { if (chain) { xmms_object_unref (chain); chain = NULL; } xmms_ringbuf_set_eos (output->filler_buffer, TRUE); g_cond_wait (output->filler_state_cond, output->filler_mutex); last_was_kill = FALSE; continue; } if (output->filler_state == FILLER_KILL) { if (chain) { xmms_object_unref (chain); chain = NULL; output->filler_state = FILLER_RUN; last_was_kill = TRUE; } else { output->filler_state = FILLER_STOP; } continue; } if (output->filler_state == FILLER_SEEK) { if (!chain) { XMMS_DBG ("Seek without chain, ignoring.."); output->filler_state = FILLER_STOP; continue; } ret = xmms_xform_this_seek (chain, output->filler_seek, XMMS_XFORM_SEEK_SET, &err); if (ret == -1) { XMMS_DBG ("Seeking failed: %s", xmms_error_message_get (&err)); } else { XMMS_DBG ("Seek ok! %d", ret); output->filler_skip = output->filler_seek - ret; if (output->filler_skip < 0) { XMMS_DBG ("Seeked %d samples too far! Updating position...", -output->filler_skip); output->filler_skip = 0; output->filler_seek = ret; } xmms_ringbuf_clear (output->filler_buffer); xmms_ringbuf_hotspot_set (output->filler_buffer, seek_done, NULL, output); } output->filler_state = FILLER_RUN; } if (!chain) { xmms_medialib_entry_t entry; xmms_output_song_changed_arg_t *arg; xmms_medialib_session_t *session; g_mutex_unlock (output->filler_mutex); entry = xmms_playlist_current_entry (output->playlist); if (!entry) { XMMS_DBG ("No entry from playlist!"); output->filler_state = FILLER_STOP; g_mutex_lock (output->filler_mutex); continue; } chain = xmms_xform_chain_setup (entry, output->format_list, FALSE); if (!chain) { session = xmms_medialib_begin_write (); if (xmms_medialib_entry_property_get_int (session, entry, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS) == XMMS_MEDIALIB_ENTRY_STATUS_NEW) { xmms_medialib_end (session); xmms_medialib_entry_remove (entry); } else { xmms_medialib_entry_status_set (session, entry, XMMS_MEDIALIB_ENTRY_STATUS_NOT_AVAILABLE); xmms_medialib_entry_send_update (entry); xmms_medialib_end (session); } if (!xmms_playlist_advance (output->playlist)) { XMMS_DBG ("End of playlist"); output->filler_state = FILLER_STOP; } g_mutex_lock (output->filler_mutex); continue; } arg = g_new0 (xmms_output_song_changed_arg_t, 1); arg->output = output; arg->chain = chain; arg->flush = last_was_kill; xmms_object_ref (chain); last_was_kill = FALSE; g_mutex_lock (output->filler_mutex); xmms_ringbuf_hotspot_set (output->filler_buffer, song_changed, song_changed_arg_free, arg); } xmms_ringbuf_wait_free (output->filler_buffer, sizeof (buf), output->filler_mutex); if (output->filler_state != FILLER_RUN) { XMMS_DBG ("State changed while waiting..."); continue; } g_mutex_unlock (output->filler_mutex); ret = xmms_xform_this_read (chain, buf, sizeof (buf), &err); g_mutex_lock (output->filler_mutex); if (ret > 0) { gint skip = MIN (ret, output->toskip); output->toskip -= skip; if (ret > skip) { xmms_ringbuf_write_wait (output->filler_buffer, buf + skip, ret - skip, output->filler_mutex); } } else { if (ret == -1) { /* print error */ xmms_error_reset (&err); } xmms_object_unref (chain); chain = NULL; if (!xmms_playlist_advance (output->playlist)) { XMMS_DBG ("End of playlist"); output->filler_state = FILLER_STOP; } } } g_mutex_unlock (output->filler_mutex); return NULL; }