summaryrefslogtreecommitdiff
path: root/streamer.c
diff options
context:
space:
mode:
Diffstat (limited to 'streamer.c')
-rw-r--r--streamer.c398
1 files changed, 289 insertions, 109 deletions
diff --git a/streamer.c b/streamer.c
index a88dd639..7dcd28ad 100644
--- a/streamer.c
+++ b/streamer.c
@@ -36,7 +36,6 @@
#include "volume.h"
#include "vfs.h"
#include "premix.h"
-#include "plugins/dsp_libsrc/src.h"
#include "ringbuf.h"
//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
@@ -49,10 +48,9 @@ FILE *out;
#endif
static intptr_t streamer_tid;
-static DB_dsp_t *srcplug;
-static DB_dsp_t *eqplug;
static ddb_dsp_context_t *dsp_chain;
-static ddb_dsp_context_t *src;
+
+static DB_dsp_t *eqplug;
static ddb_dsp_context_t *eq;
static int conf_replaygain_mode = 0;
@@ -83,7 +81,9 @@ static playlist_t *streamer_playlist;
static playItem_t *playing_track;
static playItem_t *streaming_track;
static playItem_t *playlist_track;
-static ddb_waveformat_t prevformat;
+
+static ddb_waveformat_t output_format;
+static int formatchanged;
static DB_fileinfo_t *fileinfo;
@@ -655,8 +655,6 @@ streamer_set_current (playItem_t *it) {
mutex_unlock (decodemutex);
trace ("bps=%d, channels=%d, samplerate=%d\n", fileinfo->fmt.bps, fileinfo->fmt.channels, fileinfo->fmt.samplerate);
}
-// FIXME: that might break streaming at boundaries between 2 different samplerates
-// streamer_reset (0); // reset SRC
}
else {
trace ("no decoder in playitem!\n");
@@ -809,11 +807,11 @@ streamer_start_new_song (void) {
avg_bitrate = -1;
if (output->state () != OUTPUT_STATE_PLAYING) {
streamer_reset (1);
- if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
- memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t));
- plug_get_output ()->setformat (&fileinfo->fmt);
+ if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
+ memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t));
+ plug_get_output ()->setformat (&output_format);
}
- if (output->play () < 0) {
+ if (0 != output->play ()) {
fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n");
streamer_set_nextsong (-2, 0);
}
@@ -824,14 +822,9 @@ streamer_start_new_song (void) {
last_bitrate = -1;
avg_bitrate = -1;
streamer_reset (1);
- if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
- memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t));
- plug_get_output ()->setformat (&fileinfo->fmt);
- }
- if (output->play () < 0) {
- fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n");
- streamer_set_nextsong (-2, 0);
- return;
+ if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
+ memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t));
+ formatchanged = 1;
}
}
output->pause ();
@@ -920,53 +913,45 @@ streamer_thread (void *ctx) {
playpos = 0;
seekpos = -1;
- // try to switch samplerate to the closest supported by output plugin
- if (conf_get_int ("playback.dynsamplerate", 0)) {
-
- // don't switch if unchanged
- ddb_waveformat_t prevfmt;
- memcpy (&prevfmt, &output->fmt, sizeof (ddb_waveformat_t));
- if (memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
- memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t));
- output->setformat (&fileinfo->fmt);
- // check if the format actually changed
- if (memcmp (&output->fmt, &prevfmt, sizeof (ddb_waveformat_t))) {
- // restart streaming of current track
- trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevfmt.samplerate, output->fmt.samplerate);
- mutex_lock (decodemutex);
- fileinfo->plugin->free (fileinfo);
- fileinfo = NULL;
- DB_decoder_t *dec = NULL;
- dec = plug_get_decoder_for_id (streaming_track->decoder_id);
- if (dec) {
- fileinfo = dec->open (0);
- if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) < 0) {
- dec->free (fileinfo);
- fileinfo = NULL;
- }
- }
- if (!dec || !fileinfo) {
- // FIXME: handle error
+#if 0
+ // don't switch if unchanged
+ ddb_waveformat_t prevfmt;
+ memcpy (&prevfmt, &output->fmt, sizeof (ddb_waveformat_t));
+ if (memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
+ memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t));
+ output->setformat (&fileinfo->fmt);
+ // check if the format actually changed
+ if (memcmp (&output->fmt, &prevfmt, sizeof (ddb_waveformat_t))) {
+ // restart streaming of current track
+ trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevfmt.samplerate, output->fmt.samplerate);
+ mutex_lock (decodemutex);
+ fileinfo->plugin->free (fileinfo);
+ fileinfo = NULL;
+ DB_decoder_t *dec = NULL;
+ dec = plug_get_decoder_for_id (streaming_track->decoder_id);
+ if (dec) {
+ fileinfo = dec->open (0);
+ if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) < 0) {
+ dec->free (fileinfo);
+ fileinfo = NULL;
}
- mutex_unlock (decodemutex);
- bytes_until_next_song = -1;
- streamer_buffering = 1;
- streamer_reset (1);
}
+ if (!dec || !fileinfo) {
+ // FIXME: handle error
+ }
+ mutex_unlock (decodemutex);
+ bytes_until_next_song = -1;
+ streamer_buffering = 1;
+ streamer_reset (1);
}
+ }
+#endif
- // output plugin may stop playback before switching samplerate
- if (output->state () != OUTPUT_STATE_PLAYING) {
- if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
- memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t));
- plug_get_output ()->setformat (&fileinfo->fmt);
- }
- if (output->play () < 0) {
- fprintf (stderr, "streamer: failed to start playback after samplerate change; output plugin doesn't work\n");
- streamer_set_nextsong (-2, 0);
- streamer_unlock ();
- continue;
- }
+ // output plugin may stop playback before switching samplerate
+ if (output->state () != OUTPUT_STATE_PLAYING) {
+ if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) {
+ memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t));
+ formatchanged = 1;
}
}
streamer_unlock ();
@@ -1128,44 +1113,185 @@ streamer_thread (void *ctx) {
mutex_unlock (decodemutex);
}
-int
-streamer_init (void) {
-#if WRITE_DUMP
- out = fopen ("out.raw", "w+b");
-#endif
- mutex = mutex_create ();
- decodemutex = mutex_create ();
+void
+streamer_dsp_chain_free (ddb_dsp_context_t *dsp_chain) {
+ while (dsp_chain) {
+ ddb_dsp_context_t *next = dsp_chain->next;
+ dsp_chain->plugin->close (dsp_chain);
+ dsp_chain = next;
+ }
+}
- ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE);
+ddb_dsp_context_t *
+streamer_dsp_chain_load (const char *fname) {
+ int err = 1;
+ FILE *fp = fopen (fname, "rt");
+ if (!fp) {
+ return NULL;
+ }
+
+ char temp[100];
+ ddb_dsp_context_t *chain = NULL;
+ ddb_dsp_context_t *tail = NULL;
+ for (;;) {
+ // plugin enabled {
+ int enabled = 0;
+ int err = fscanf (fp, "%100s %d {\n", temp, &enabled);
+ if (err == EOF) {
+ break;
+ }
+ else if (2 != err) {
+ fprintf (stderr, "error plugin name\n");
+ goto error;
+ }
- pl_set_order (conf_get_int ("playback.order", 0));
+ DB_dsp_t *plug = (DB_dsp_t *)deadbeef->plug_get_for_id (temp);
+ if (!plug) {
+ fprintf (stderr, "streamer_dsp_chain_load: plugin %s not found. preset will not be loaded\n", temp);
+ goto error;
+ }
+ ddb_dsp_context_t *ctx = plug->open ();
+ if (!ctx) {
+ fprintf (stderr, "streamer_dsp_chain_load: failed to open ctxance of plugin %s\n", temp);
+ goto error;
+ }
+
+ if (tail) {
+ tail->next = ctx;
+ tail = ctx;
+ }
+ else {
+ tail = chain = ctx;
+ }
+
+ int n = 0;
+ for (;;) {
+ char value[1000];
+ if (!fgets (temp, sizeof (temp), fp)) {
+ fprintf (stderr, "streamer_dsp_chain_load: unexpected eof while reading plugin params\n");
+ goto error;
+ }
+ if (!strcmp (temp, "}\n")) {
+ break;
+ }
+ else if (1 != sscanf (temp, "\t%1000[^\n]\n", value)) {
+ fprintf (stderr, "streamer_dsp_chain_load: error loading param %d\n", n);
+ goto error;
+ }
+ if (plug->num_params) {
+ plug->set_param (ctx, n, value);
+ }
+ n++;
+ }
+ ctx->enabled = enabled;
+ }
- // find src plugin, and use it if found
- srcplug = (DB_dsp_t*)plug_get_for_id ("SRC");
- if (srcplug) {
- src = srcplug->open ();
- srcplug->set_param (src, SRC_PARAM_QUALITY, conf_get_str ("src_quality", "2"));
- src->next = dsp_chain;
- dsp_chain = src;
+ err = 0;
+error:
+ if (err) {
+ fprintf (stderr, "streamer_dsp_chain_load: error loading %s\n", fname);
}
+ if (fp) {
+ fclose (fp);
+ }
+ if (err && chain) {
+ streamer_dsp_chain_free (chain);
+ chain = NULL;
+ }
+ return chain;
+}
+
+int
+streamer_dsp_chain_save (const char *fname, ddb_dsp_context_t *chain) {
+ FILE *fp = fopen (fname, "w+t");
+ if (!fp) {
+ return -1;
+ }
+
+ ddb_dsp_context_t *ctx = chain;
+ while (ctx) {
+ fprintf (fp, "%s %d {\n", ctx->plugin->plugin.id, (int)ctx->enabled);
+ if (ctx->plugin->num_params) {
+ int n = ctx->plugin->num_params ();
+ int i;
+ for (i = 0; i < n; i++) {
+ char v[1000];
+ ctx->plugin->get_param (ctx, i, v, sizeof (v));
+ fprintf (fp, "\t%s\n", v);
+ }
+ }
+ fprintf (fp, "}\n");
+ ctx = ctx->next;
+ }
+
+ fclose (fp);
+ return 0;
+}
+
+void
+streamer_dsp_postinit (void) {
+ // note about EQ hack:
+ // we 1st check if there's an EQ in dsp chain, and just use it
+ // if not -- we add our own
// eq plug
- eqplug = (DB_dsp_t *)plug_get_for_id ("supereq");
if (eqplug) {
- eq = eqplug->open ();
+ ddb_dsp_context_t *p;
+
+ for (p = dsp_chain; p; p = p->next) {
+ if (!strcmp (p->plugin->plugin.id, "supereq")) {
+ break;
+ }
+ }
+ if (p) {
+ eq = p;
+ }
+ else {
+ eq = eqplug->open ();
+ eq->next = dsp_chain;
+ dsp_chain = eq;
+ }
+
+ }
+}
+
+void
+streamer_dsp_init (void) {
+ // load dsp chain from file
+ char fname[PATH_MAX];
+ snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ());
+ dsp_chain = streamer_dsp_chain_load (fname);
+
+ eqplug = (DB_dsp_t *)plug_get_for_id ("supereq");
+ streamer_dsp_postinit ();
- // load settings
- eqplug->enable (eq, deadbeef->conf_get_int ("eq.enable", 0));
- eqplug->set_param (eq, 0, conf_get_str ("eq.preamp", "1"));
+ // load legacy eq settings from pre-0.5
+ if (conf_find ("eq.", NULL)) {
+ eq->enabled = deadbeef->conf_get_int ("eq.enable", 0);
+ eqplug->set_param (eq, 0, conf_get_str ("eq.preamp", "0"));
for (int i = 0; i < 18; i++) {
char key[100];
snprintf (key, sizeof (key), "eq.band%d", i);
- eqplug->set_param (eq, 1+i, conf_get_str (key, "1"));
+ eqplug->set_param (eq, 1+i, conf_get_str (key, "0"));
}
-
- eq->next = dsp_chain;
- dsp_chain = eq;
+ // delete obsolete settings
+ conf_remove_items ("eq.");
}
+}
+
+int
+streamer_init (void) {
+#if WRITE_DUMP
+ out = fopen ("out.raw", "w+b");
+#endif
+ mutex = mutex_create ();
+ decodemutex = mutex_create ();
+
+ ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE);
+
+ pl_set_order (conf_get_int ("playback.order", 0));
+
+ streamer_dsp_init ();
conf_replaygain_mode = conf_get_int ("replaygain_mode", 0);
conf_replaygain_scale = conf_get_int ("replaygain_scale", 1);
@@ -1198,16 +1324,16 @@ streamer_free (void) {
decodemutex = 0;
mutex_free (mutex);
mutex = 0;
- if (srcplug && src) {
- srcplug->close (src);
- srcplug = NULL;
- src = NULL;
- }
- if (eqplug && eq) {
- eqplug->close (eq);
- eqplug = NULL;
- eq = NULL;
- }
+
+ char fname[PATH_MAX];
+ snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ());
+ streamer_dsp_chain_save (fname, dsp_chain);
+
+ streamer_dsp_chain_free (dsp_chain);
+ dsp_chain = NULL;
+
+ eqplug = NULL;
+ eq = NULL;
}
void
@@ -1385,14 +1511,6 @@ streamer_read_async (char *bytes, int size) {
// convert to float
int tempsize = pcm_convert (&fileinfo->fmt, input, &dspfmt, tempbuf, inputsize);
- if (srcplug) {
- // FIXME: update on change only, conversion from float to
- // str and back is slow
- char s[100];
- snprintf (s, sizeof (s), "%d", dspfmt.samplerate);
- srcplug->set_param (src, SRC_PARAM_SAMPLERATE, s);
- }
-
int nframes = inputsize / inputsamplesize;
ddb_dsp_context_t *dsp = dsp_chain;
dspfmt.samplerate = fileinfo->fmt.samplerate;
@@ -1405,6 +1523,17 @@ streamer_read_async (char *bytes, int size) {
int n = pcm_convert (&dspfmt, tempbuf, &output->fmt, bytes, nframes * dspsamplesize);
bytesread = n;
+
+ ddb_waveformat_t outfmt;
+ outfmt.bps = output->fmt.bps;
+ outfmt.is_float = output->fmt.is_float;
+ outfmt.channels = dspfmt.channels;
+ outfmt.samplerate = dspfmt.samplerate;
+ outfmt.channelmask = dspfmt.channelmask;
+ if (memcmp (&output_format, &outfmt, sizeof (ddb_waveformat_t))) {
+ memcpy (&output_format, &outfmt, sizeof (ddb_waveformat_t));
+ formatchanged = 1;
+ }
}
}
else {
@@ -1468,6 +1597,15 @@ streamer_read (char *bytes, int size) {
return -1;
}
DB_output_t *output = plug_get_output ();
+ if (formatchanged && bytes_until_next_song <= 0) {
+ formatchanged = 0;
+ plug_get_output ()->setformat (&output_format);
+ if (0 != output->play ()) {
+ fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n");
+ streamer_set_nextsong (-2, 0);
+ return -1;
+ }
+ }
streamer_lock ();
int sz = min (size, streamer_ringbuf.remaining);
if (sz) {
@@ -1593,10 +1731,6 @@ streamer_configchanged (void) {
conf_replaygain_mode = conf_get_int ("replaygain_mode", 0);
conf_replaygain_scale = conf_get_int ("replaygain_scale", 1);
pl_set_order (conf_get_int ("playback.order", 0));
-
- if (srcplug) {
- srcplug->set_param (src, SRC_PARAM_QUALITY, conf_get_str ("src_quality", "2"));
- }
}
void
@@ -1662,3 +1796,49 @@ ddb_dsp_context_t *
streamer_get_dsp_chain (void) {
return dsp_chain;
}
+
+static ddb_dsp_context_t *
+dsp_clone (ddb_dsp_context_t *from) {
+ ddb_dsp_context_t *dsp = from->plugin->open ();
+ char param[2000];
+ if (from->plugin->num_params) {
+ int n = from->plugin->num_params ();
+ for (int i = 0; i < n; i++) {
+ from->plugin->get_param (from, i, param, sizeof (param));
+ dsp->plugin->set_param (dsp, i, param);
+ }
+ }
+ dsp->enabled = from->enabled;
+ return dsp;
+}
+
+void
+streamer_set_dsp_chain (ddb_dsp_context_t *chain) {
+ mutex_lock (decodemutex);
+ streamer_dsp_chain_free (dsp_chain);
+
+ dsp_chain = NULL;
+ eq = NULL;
+
+ ddb_dsp_context_t *tail = NULL;
+ while (chain) {
+ printf ("copy %s\n", chain->plugin->plugin.id);
+ ddb_dsp_context_t *new = dsp_clone (chain);
+ if (tail) {
+ tail->next = new;
+ tail = new;
+ }
+ else {
+ dsp_chain = tail = new;
+ }
+ chain = chain->next;
+ }
+
+ streamer_dsp_postinit ();
+
+ char fname[PATH_MAX];
+ snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ());
+ streamer_dsp_chain_save (fname, dsp_chain);
+
+ mutex_unlock (decodemutex);
+}