diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-01-31 20:26:17 +0100 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-01-31 20:26:17 +0100 |
commit | 6e6dc88fc61f4a84269a592c76c2b6bd0417bf4a (patch) | |
tree | 8b5b1fe103a9a4e93a680493d9f1dd2fcb71ded2 /streamer.c | |
parent | 9460844e2a1598dfe24a72dd2a283d02b57caddc (diff) | |
parent | 893655b27084db6399b82069a5dcb56d6e98fbfa (diff) |
Merge branch 'master' into devel
Conflicts:
main.c
plugins/flac/flac.c
plugins/mpgmad/mpgmad.c
streamer.c
Diffstat (limited to 'streamer.c')
-rw-r--r-- | streamer.c | 303 |
1 files changed, 187 insertions, 116 deletions
@@ -26,7 +26,6 @@ #endif #include <sys/time.h> #include "threading.h" -#include "codec.h" #include "playlist.h" #include "common.h" #include "streamer.h" @@ -38,26 +37,24 @@ #include "volume.h" #include "vfs.h" -#define trace(...) { fprintf(stderr, __VA_ARGS__); } -//#define trace(fmt,...) +//#define trace(...) { fprintf(stderr, __VA_ARGS__); } +#define trace(fmt,...) static intptr_t streamer_tid; static int src_quality; static SRC_STATE *src; static SRC_DATA srcdata; -static int codecleft; +static int src_remaining; // number of input samples in SRC buffer static int conf_replaygain_mode = 0; static int conf_replaygain_scale = 1; -// that's buffer for resampling. -// our worst case is 192KHz downsampling to 22050Hz with 2048 sample output buffer -#define INPUT_BUFFER_SIZE (2048*192000/22050*8) -static char g_readbuffer[INPUT_BUFFER_SIZE]; -// fbuffer contains readbuffer converted to floating point, to pass to SRC -static float g_fbuffer[INPUT_BUFFER_SIZE]; -// output SRC buffer - can't really exceed INPUT_BUFFER_SIZE -#define SRC_BUFFER_SIZE (INPUT_BUFFER_SIZE*2) -static float g_srcbuffer[SRC_BUFFER_SIZE]; + +#define SRC_BUFFER 16000 +static int src_in_remaining = 0; +//static int16_t g_src_in_buffer[SRC_BUFFER*2]; +static float g_src_in_fbuffer[SRC_BUFFER*2]; +static float g_src_out_fbuffer[SRC_BUFFER*2]; + static int streaming_terminate; // buffer up to 3 seconds at 44100Hz stereo @@ -260,7 +257,7 @@ streamer_thread (void *ctx) { #ifdef __linux__ prctl (PR_SET_NAME, "deadbeef-stream", 0, 0, 0, 0); #endif - codecleft = 0; + src_remaining = 0; while (!streaming_terminate) { struct timeval tm1; @@ -270,9 +267,7 @@ streamer_thread (void *ctx) { int sng = nextsong; int pstate = nextsong_pstate; nextsong = -1; - codec_lock (); - codecleft = 0; - codec_unlock (); + src_remaining = 0; if (badsong == sng) { trace ("looped to bad file. stopping...\n"); streamer_set_nextsong (-2, 1); @@ -456,9 +451,7 @@ streamer_thread (void *ctx) { streamer_lock (); streambuffer_fill = 0; streambuffer_pos = 0; - codec_lock (); - codecleft = 0; - codec_unlock (); + src_remaining = 0; if (str_current_decoder->plugin->seek (str_current_decoder, pos) >= 0) { playpos = str_current_decoder->readpos; } @@ -551,7 +544,7 @@ streamer_free (void) { void streamer_reset (int full) { // must be called when current song changes by external reasons - codecleft = 0; + src_remaining = 0; if (full) { streambuffer_pos = 0; streambuffer_fill = 0; @@ -702,128 +695,206 @@ float32_to_int16 (float *in, int16_t *out, int nsamples) { fpu_restore (ctl); } +/* + + src algorithm + + initsize = size; + while (size > 0) { + need_frames = SRC_BUFFER - src_remaining + read_samples (need_frames) + src_process (output_frames) + convert_to_int16 (bytes, size) + // handle errors + } + return initsize-size; + +*/ + +static int +streamer_read_data_for_src (int16_t *buffer, int frames) { + DB_decoder_t *decoder = str_current_decoder->plugin; + int channels = str_current_decoder->channels; + if (channels > 2) { + channels = 2; + } + int bytesread = decoder->read_int16 (str_current_decoder, (uint8_t*)buffer, frames * sizeof (int16_t) * channels); + if (channels == 1) { + // convert to stereo + int n = frames-1; + while (n >= 0) { + buffer[n*2+0] = buffer[n]; + buffer[n*2+1] = buffer[n]; + } + } + return bytesread / (sizeof (int16_t) * channels); +} + +static int +streamer_read_data_for_src_float (float *buffer, int frames) { + DB_decoder_t *decoder = str_current_decoder->plugin; + int channels = str_current_decoder->channels; + if (channels > 2) { + channels = 2; + } + if (decoder->read_float32) { +// trace ("call read_float32 (%d frames -> %d bytes)\n", frames, frames * sizeof (float) * channels); + int bytesread = decoder->read_float32 (str_current_decoder, (uint8_t*)buffer, frames * sizeof (float) * channels); +// trace ("got %d bytes -> %d frames\n", bytesread, bytesread / (sizeof (float) * channels)); + if (channels == 1) { + // convert to stereo + int n = frames-1; + while (n >= 0) { + buffer[n*2+0] = buffer[n]; + buffer[n*2+1] = buffer[n]; + } + bytesread *= 2; + } + return bytesread / (sizeof (float) * channels); + } +// trace ("read_float32 not impl\n"); + int16_t intbuffer[frames*2]; + int res = streamer_read_data_for_src (intbuffer, frames); + for (int i = 0; i < res; i++) { + buffer[i*2+0] = intbuffer[i*2+0]/(float)0x7fff; + buffer[i*2+1] = intbuffer[i*2+1]/(float)0x7fff; + } + return res; +} + +static int +streamer_decode_src_libsamplerate (uint8_t *bytes, int size) { + int initsize = size; + int16_t *out = (int16_t *)bytes; + DB_decoder_t *decoder = str_current_decoder->plugin; + int samplerate = str_current_decoder->samplerate; + float ratio = (float)p_get_rate ()/samplerate; + while (size > 0) { + int n_output_frames = size / sizeof (int16_t) / 2; + int n_input_frames = n_output_frames * samplerate / p_get_rate () + 100; + // read data from decoder + if (n_input_frames > SRC_BUFFER - src_remaining ) { + n_input_frames = SRC_BUFFER - src_remaining; + } + int nread = streamer_read_data_for_src_float (&g_src_in_fbuffer[src_remaining*2], n_input_frames); + src_remaining += nread; + // resample + + srcdata.data_in = g_src_in_fbuffer; + srcdata.data_out = g_src_out_fbuffer; + srcdata.input_frames = src_remaining; + srcdata.output_frames = size/4; + srcdata.src_ratio = ratio; +// trace ("SRC from %d to %d\n", samplerate, p_get_rate ()); + srcdata.end_of_input = (nread == n_input_frames) ? 0 : 1; + src_process (src, &srcdata); + // convert back to s16 format +// trace ("out frames: %d\n", srcdata.output_frames_gen); + int genbytes = srcdata.output_frames_gen * 4; + int bytesread = min(size, genbytes); +// trace ("bytesread: %d\n", bytesread); + float32_to_int16 ((float*)g_src_out_fbuffer, (int16_t*)bytes, bytesread>>1); + size -= bytesread; +// trace ("size: %d\n", size); + bytes += bytesread; + // calculate how many unused input samples left + src_remaining -= srcdata.input_frames_used; + + // copy spare samples for next update + if (src_remaining > 0) { + memmove (g_src_in_fbuffer, &g_src_in_fbuffer[srcdata.input_frames_used*2], src_remaining * sizeof (float) * 2); + } + + if (nread != n_input_frames) { + trace ("nread=%d, n_input_frames=%d, mismatch!\n", nread, n_input_frames); + break; + } + } + return initsize-size; +} + +#if 0 +static int +streamer_decode_src (uint8_t *bytes, int size) { + int initsize = size; + int16_t *out = (int16_t *)bytes; + DB_decoder_t *decoder = str_streaming_song.decoder; + int samplerate = decoder->info.samplerate; + float ratio = (float)samplerate / p_get_rate (); + while (size > 0) { + int n_output_frames = size / sizeof (int16_t) / 2; + int n_input_frames = n_output_frames * samplerate / p_get_rate () + 100; + // read data from decoder + if (n_input_frames > SRC_BUFFER - src_remaining ) { + n_input_frames = SRC_BUFFER - src_remaining; + } + int nread = streamer_read_data_for_src (&g_src_in_buffer[src_remaining*2], n_input_frames); + src_remaining += nread; + // resample + float idx = 0; + int i = 0; + while (i < n_output_frames && idx < src_remaining) { + int k = (int)idx; + out[0] = g_src_in_buffer[k*2+0]; + out[1] = g_src_in_buffer[k*2+1]; + i++; + idx += ratio; + out += 2; + } + size -= i*4; + src_remaining -= idx; + if (src_remaining < 0) { + src_remaining = 0; + } + else if (src_remaining > 0) { + memmove (g_src_in_buffer, &g_src_in_buffer[(SRC_BUFFER-src_remaining)*2], src_remaining*2*sizeof (int16_t)); + } + if (nread != n_input_frames) { + break; + } + } + return initsize-size; +} +#endif + // returns number of bytes been read static int streamer_read_async (char *bytes, int size) { int initsize = size; for (;;) { int bytesread = 0; - codec_lock (); if (!str_current_decoder) { - codec_unlock (); - break; - } - DB_decoder_t *decoder = str_current_decoder->plugin; - if (!decoder) { // means there's nothing left to stream, so just do nothing - codec_unlock (); break; } if (str_current_decoder->samplerate != -1) { int nchannels = str_current_decoder->channels; + if (nchannels > 2) { + nchannels = 2; + } int samplerate = str_current_decoder->samplerate; - if (str_current_decoder->samplerate == p_get_rate () && decoder->read_int16) { + if (str_current_decoder->samplerate == p_get_rate () && str_current_decoder->plugin->read_int16) { // samplerate match - if (str_current_decoder->channels == 2) { - bytesread = decoder->read_int16 (str_current_decoder, bytes, size); + if (nchannels == 2) { + bytesread = str_current_decoder->plugin->read_int16 (str_current_decoder, bytes, size); apply_replay_gain_int16 (&str_streaming_song, bytes, size); - codec_unlock (); } else { - bytesread = decoder->read_int16 (str_current_decoder, g_readbuffer, size>>1); - apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, size>>1); - mono_int16_to_stereo_int16 ((int16_t*)g_readbuffer, (int16_t*)bytes, size>>2); + uint8_t buffer[size>>1]; + bytesread = str_current_decoder->plugin->read_int16 (str_current_decoder, buffer, size>>1); + apply_replay_gain_int16 (&str_streaming_song, buffer, size>>1); + mono_int16_to_stereo_int16 ((int16_t*)buffer, (int16_t*)bytes, size>>2); bytesread *= 2; - codec_unlock (); } } else if (src_is_valid_ratio (p_get_rate ()/(double)samplerate)) { - // read and do SRC - int nsamples = size/4; - nsamples = nsamples * samplerate / p_get_rate () * 2; - // read data at source samplerate (with some room for SRC) - int nbytes = (nsamples - codecleft) * 2 * nchannels; - int samplesize = 2; - if (nbytes <= 0) { - nbytes = 0; - } - else { - if (!decoder->read_float32) { - if (nbytes > INPUT_BUFFER_SIZE) { - trace ("input buffer overflow\n"); - nbytes = INPUT_BUFFER_SIZE; - } - bytesread = decoder->read_int16 (str_current_decoder, g_readbuffer, nbytes); - apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, nbytes); - } - else { - samplesize = 4; - } - } - codec_unlock (); - // recalculate nsamples according to how many bytes we've got - if (nbytes != 0) { - if (!decoder->read_float32) { - nsamples = bytesread / (samplesize * nchannels) + codecleft; - // convert to float - float *fbuffer = g_fbuffer + codecleft*2; - int n = nsamples - codecleft; - if (nchannels == 2) { - n <<= 1; - int16_to_float32 ((int16_t*)g_readbuffer, fbuffer, n); - } - else if (nchannels == 1) { // convert mono to stereo - mono_int16_to_stereo_float32 ((int16_t*)g_readbuffer, fbuffer, n); - } - } - else { - float *fbuffer = g_fbuffer + codecleft*2; - if (nchannels == 1) { - codec_lock (); - bytesread = decoder->read_float32 (str_current_decoder, g_readbuffer, nbytes*2); - codec_unlock (); - apply_replay_gain_float32 (&str_streaming_song, g_readbuffer, nbytes*2); - nsamples = bytesread / (samplesize * nchannels) + codecleft; - mono_float32_to_stereo_float32 ((float *)g_readbuffer, fbuffer, nsamples-codecleft); - } - else { - codec_lock (); - bytesread = decoder->read_float32 (str_current_decoder, (char *)fbuffer, nbytes*2); - codec_unlock (); - apply_replay_gain_float32 (&str_streaming_song, (char *)fbuffer, nbytes*2); - nsamples = bytesread / (samplesize * nchannels) + codecleft; - } - } - } - //codec_lock (); - // convert samplerate - mutex_lock (decodemutex); - srcdata.data_in = g_fbuffer; - srcdata.data_out = g_srcbuffer; - srcdata.input_frames = nsamples; - srcdata.output_frames = size/4; - srcdata.src_ratio = p_get_rate ()/(double)samplerate; - srcdata.end_of_input = 0; - // src_set_ratio (src, srcdata.src_ratio); - src_process (src, &srcdata); - //codec_unlock (); - // convert back to s16 format - nbytes = size; - int genbytes = srcdata.output_frames_gen * 4; - bytesread = min(size, genbytes); - float32_to_int16 ((float*)g_srcbuffer, (int16_t*)bytes, bytesread>>1); - // calculate how many unused input samples left - codecleft = nsamples - srcdata.input_frames_used; - mutex_unlock (decodemutex); - // copy spare samples for next update - memmove (g_fbuffer, &g_fbuffer[srcdata.input_frames_used*2], codecleft * 8); + bytesread = streamer_decode_src_libsamplerate (bytes, size); } else { fprintf (stderr, "invalid ratio! %d / %d = %f", p_get_rate (), samplerate, p_get_rate ()/(float)samplerate); } } else { - codec_unlock (); } bytes += bytesread; size -= bytesread; |