/* Play the stream (global decoder_stream) using the given decoder. */ static void play_stream (const struct decoder *f, struct out_buf *out_buf) { void *decoder_data; struct sound_params sound_params = { 0, 0, 0 }; struct decoder_error err; struct md5_data null_md5; null_md5.okay = false; out_buf_reset (out_buf); assert (f->open_stream != NULL); decoder_data = f->open_stream (decoder_stream); f->get_error (decoder_data, &err); if (err.type != ERROR_OK) { LOCK (decoder_stream_mut); decoder_stream = NULL; UNLOCK (decoder_stream_mut); f->close (decoder_data); error ("%s", err.err); decoder_error_clear (&err); logit ("Can't open file"); } else { audio_state_started_playing (); bitrate_list_init (&bitrate_list); decode_loop (f, decoder_data, NULL, out_buf, &sound_params, &null_md5, 0.0); } }
static int wav_decode (void *prv_data, char *buf, int buf_len, struct sound_params *sound_params) { struct wavpack_data *data = (struct wavpack_data *)prv_data; int ret, i, s_num, iBps, oBps; int8_t * buf8 = (int8_t *)buf; int16_t * buf16 = (int16_t *)buf; int32_t * buf32 = (int32_t *)buf; iBps = data->channels * WavpackGetBytesPerSample (data->wpc); oBps = (iBps == 6) ? 8 : iBps; s_num = buf_len / oBps; decoder_error_clear (&data->error); int32_t *dbuf = (int32_t *)xcalloc ( s_num, data->channels * 4); ret = WavpackUnpackSamples (data->wpc, dbuf, s_num ); if (ret == 0) { free (dbuf); return 0; } if (data->mode & MODE_FLOAT) { sound_params->fmt = SFMT_FLOAT; memcpy (buf, dbuf, ret * oBps); } else { debug ("iBps %d", iBps); switch (iBps / data->channels){ case 4: for (i = 0; i < ret * data->channels; i++) buf32[i] = dbuf[i]; sound_params->fmt = SFMT_S32 | SFMT_NE; break; case 3: for (i = 0; i < ret * data->channels; i++) buf32[i] = dbuf[i] * 256; sound_params->fmt = SFMT_S32 | SFMT_NE; break; case 2: for (i = 0; i < ret * data->channels; i++) buf16[i] = dbuf[i]; sound_params->fmt = SFMT_S16 | SFMT_NE; break; case 1: for (i = 0; i < ret * data->channels; i++) buf8[i] = dbuf[i]; sound_params->fmt = SFMT_S8 | SFMT_NE; } } sound_params->channels = data->channels; sound_params->rate = data->sample_rate; free (dbuf); return ret * oBps ; }
static void aac_close (void *prv_data) { struct aac_data *data = (struct aac_data *)prv_data; NeAACDecClose (data->decoder); io_close (data->stream); decoder_error_clear (&data->error); free (data); }
static void sndfile_close (void *void_data) { struct sndfile_data *data = (struct sndfile_data *)void_data; if (data->sndfile) sf_close (data->sndfile); decoder_error_clear (&data->error); free (data); }
static void timidity_close (void *void_data) { struct timidity_data *data = (struct timidity_data *)void_data; if (data->midisong) { mid_song_free(data->midisong); } decoder_error_clear (&data->error); free (data); }
static void wav_close (void *prv_data) { struct wavpack_data *data = (struct wavpack_data *)prv_data; if (data->ok) { WavpackCloseFile (data->wpc); } decoder_error_clear (&data->error); free (data); logit ("File closed"); }
static void mp3_close (void *void_data) { struct mp3_data *data = (struct mp3_data *)void_data; if (data->ok) { io_close (data->io_stream); mad_stream_finish (&data->stream); mad_frame_finish (&data->frame); mad_synth_finish (&data->synth); } decoder_error_clear (&data->error); free (data); }
static void ffmpeg_close (void *prv_data) { struct ffmpeg_data *data = (struct ffmpeg_data *)prv_data; if (data->ok) { avcodec_close (data->enc); av_close_input_file (data->ic); if (data->remain_buf) free (data->remain_buf); } decoder_error_clear (&data->error); free (data); }
static void spx_close (void *prv_data) { struct spx_data *data = (struct spx_data *)prv_data; if (data->ok) { if (data->st) speex_decoder_destroy (data->st); if (data->comment_packet) free (data->comment_packet); if (data->output) free (data->output); speex_bits_destroy (&data->bits); ogg_stream_clear (&data->os); ogg_sync_clear (&data->oy); io_close (data->stream); } decoder_error_clear (&data->error); free (data); }
static int ffmpeg_decode (void *prv_data, char *buf, int buf_len, struct sound_params *sound_params) { struct ffmpeg_data *data = (struct ffmpeg_data *)prv_data; int ret; int data_size; AVPacket pkt, pkt_tmp; uint8_t *pkt_data; int pkt_size = 0; int filled = 0; /* The sample buffer should be 16 byte aligned (because SSE), a segmentation * fault may occur otherwise. * * See: avcodec.h in ffmpeg */ char avbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2] __attribute__((aligned(16))); decoder_error_clear (&data->error); sound_params->channels = data->enc->channels; sound_params->rate = data->enc->sample_rate; sound_params->fmt = SFMT_S16 | SFMT_NE; if (data->remain_buf) { int to_copy = MIN (buf_len, data->remain_buf_len); debug ("Copying %d bytes from the remain buf", to_copy); memcpy (buf, data->remain_buf, to_copy); if (to_copy < data->remain_buf_len) { memmove (data->remain_buf, data->remain_buf + to_copy, data->remain_buf_len - to_copy); data->remain_buf_len -= to_copy; } else { debug ("Remain buf is now empty"); free (data->remain_buf); data->remain_buf = NULL; data->remain_buf_len = 0; } return to_copy; } do { ret = av_read_frame (data->ic, &pkt); if (ret < 0) return 0; memcpy(&pkt_tmp, &pkt, sizeof(pkt)); pkt_data = pkt.data; pkt_size = pkt.size; debug ("Got %dB packet", pkt_size); while (pkt_size) { int len; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(26<<8)+0) data_size = sizeof (avbuf); len = avcodec_decode_audio3 (data->enc, (int16_t *)avbuf, &data_size, &pkt); #elif LIBAVCODEC_VERSION_INT >= ((51<<16)+(50<<8)+0) data_size = sizeof (avbuf); len = avcodec_decode_audio2 (data->enc, (int16_t *)avbuf, &data_size, pkt_data, pkt_size); #else len = avcodec_decode_audio (data->enc, (int16_t *)avbuf, &data_size, pkt_data, pkt_size); #endif debug ("Decoded %dB", data_size); if (len < 0) { /* skip frame */ decoder_error (&data->error, ERROR_STREAM, 0, "Error in the stream!"); break; } pkt_data += len; pkt_size -= len; if (buf_len) { int to_copy = MIN (data_size, buf_len); memcpy (buf, avbuf, to_copy); buf += to_copy; filled += to_copy; buf_len -= to_copy; debug ("Copying %dB (%dB filled)", to_copy, filled); if (to_copy < data_size) put_in_remain_buf (data, avbuf + to_copy, data_size - to_copy); } else if (data_size) add_to_remain_buf (data, avbuf, data_size); } } while (!filled); /* 2.0 - 16bit/sample*/ data->bitrate = pkt.size * 8 / ((filled + data->remain_buf_len) / 2.0 / sound_params->channels / sound_params->rate) / 1000; av_free_packet (&pkt_tmp); return filled; }
/* Play a file (disk file) using the given decoder. next_file is precached. */ static void play_file (const char *file, const struct decoder *f, const char *next_file, struct out_buf *out_buf) { void *decoder_data; struct sound_params sound_params = { 0, 0, 0 }; float already_decoded_time; struct md5_data md5; #if !defined(NDEBUG) && defined(DEBUG) md5.okay = true; md5.len = 0; md5_init_ctx (&md5.ctx); #endif out_buf_reset (out_buf); precache_wait (&precache); if (precache.ok && strcmp(precache.file, file)) { logit ("The precached file is not the file we want."); precache.f->close (precache.decoder_data); precache_reset (&precache); } if (precache.ok && !strcmp(precache.file, file)) { struct decoder_error err; logit ("Using precached file"); assert (f == precache.f); sound_params = precache.sound_params; decoder_data = precache.decoder_data; set_info_channels (sound_params.channels); set_info_rate (sound_params.rate / 1000); if (!audio_open(&sound_params)) { md5.okay = false; precache.f->close (precache.decoder_data); precache_reset (&precache); return; } #if !defined(NDEBUG) && defined(DEBUG) md5.len += precache.buf_fill; md5_process_bytes (precache.buf, precache.buf_fill, &md5.ctx); #endif audio_send_buf (precache.buf, precache.buf_fill); precache.f->get_error (precache.decoder_data, &err); if (err.type != ERROR_OK) { md5.okay = false; if (err.type != ERROR_STREAM || options_get_int( "ShowStreamErrors")) error ("%s", err.err); decoder_error_clear (&err); } already_decoded_time = precache.decoded_time; if(f->get_avg_bitrate) set_info_avg_bitrate (f->get_avg_bitrate(decoder_data)); else set_info_avg_bitrate (0); bitrate_list_init (&bitrate_list); bitrate_list.head = precache.bitrate_list.head; bitrate_list.tail = precache.bitrate_list.tail; /* don't free list elements when reseting precache */ precache.bitrate_list.head = NULL; precache.bitrate_list.tail = NULL; } else { struct decoder_error err; status_msg ("Opening..."); decoder_data = f->open(file); f->get_error (decoder_data, &err); if (err.type != ERROR_OK) { f->close (decoder_data); status_msg (""); error ("%s", err.err); decoder_error_clear (&err); logit ("Can't open file, exiting"); return; } already_decoded_time = 0.0; if(f->get_avg_bitrate) set_info_avg_bitrate (f->get_avg_bitrate(decoder_data)); bitrate_list_init (&bitrate_list); } audio_plist_set_time (file, f->get_duration(decoder_data)); audio_state_started_playing (); precache_reset (&precache); decode_loop (f, decoder_data, next_file, out_buf, &sound_params, &md5, already_decoded_time); #if !defined(NDEBUG) && defined(DEBUG) if (md5.okay) { uint8_t buf[MD5_DIGEST_SIZE]; md5_finish_ctx (&md5.ctx, buf); log_md5_sum (file, sound_params, f, buf, md5.len); } #endif }
/* Decoder loop for already opened and probably running for some time decoder. * next_file will be precached at eof. */ static void decode_loop (const struct decoder *f, void *decoder_data, const char *next_file, struct out_buf *out_buf, struct sound_params *sound_params, struct md5_data *md5, const float already_decoded_sec) { bool eof = false; bool stopped = false; char buf[PCM_BUF_SIZE]; int decoded = 0; struct sound_params new_sound_params; bool sound_params_change = false; float decode_time = already_decoded_sec; /* the position of the decoder (in seconds) */ out_buf_set_free_callback (out_buf, buf_free_callback); LOCK (curr_tags_mut); curr_tags = tags_new (); UNLOCK (curr_tags_mut); if (f->get_stream) { LOCK (decoder_stream_mut); decoder_stream = f->get_stream (decoder_data); UNLOCK (decoder_stream_mut); } else logit ("No get_stream() function"); status_msg ("Playing..."); while (1) { debug ("loop..."); LOCK (request_cond_mutex); if (!eof && !decoded) { struct decoder_error err; UNLOCK (request_cond_mutex); if (decoder_stream && out_buf_get_fill(out_buf) < PREBUFFER_THRESHOLD) { prebuffering = 1; io_prebuffer (decoder_stream, options_get_int("Prebuffering") * 1024); prebuffering = 0; status_msg ("Playing..."); } decoded = f->decode (decoder_data, buf, sizeof(buf), &new_sound_params); if (decoded) decode_time += decoded / (float)(sfmt_Bps( new_sound_params.fmt) * new_sound_params.rate * new_sound_params.channels); f->get_error (decoder_data, &err); if (err.type != ERROR_OK) { md5->okay = false; if (err.type != ERROR_STREAM || options_get_int( "ShowStreamErrors")) error ("%s", err.err); decoder_error_clear (&err); } if (!decoded) { eof = true; logit ("EOF from decoder"); } else { debug ("decoded %d bytes", decoded); if (!sound_params_eq(new_sound_params, *sound_params)) sound_params_change = true; bitrate_list_add (&bitrate_list, decode_time, f->get_bitrate(decoder_data)); update_tags (f, decoder_data, decoder_stream); } } /* Wait, if there is no space in the buffer to put the decoded * data or EOF occurred and there is something in the buffer. */ else if (decoded > out_buf_get_free(out_buf) || (eof && out_buf_get_fill(out_buf))) { debug ("waiting..."); if (eof && !precache.file && next_file && file_type(next_file) == F_SOUND && options_get_int("Precache") && options_get_bool("AutoNext")) start_precache (&precache, next_file); pthread_cond_wait (&request_cond, &request_cond_mutex); UNLOCK (request_cond_mutex); } else UNLOCK (request_cond_mutex); /* When clearing request, we must make sure, that another * request will not arrive at the moment, so we check if * the request has changed. */ if (request == REQ_STOP) { logit ("stop"); stopped = true; md5->okay = false; out_buf_stop (out_buf); LOCK (request_cond_mutex); if (request == REQ_STOP) request = REQ_NOTHING; UNLOCK (request_cond_mutex); break; } else if (request == REQ_SEEK) { int decoder_seek; logit ("seeking"); md5->okay = false; req_seek = MAX(0, req_seek); if ((decoder_seek = f->seek(decoder_data, req_seek)) == -1) logit ("error when seeking"); else { out_buf_stop (out_buf); out_buf_reset (out_buf); out_buf_time_set (out_buf, decoder_seek); bitrate_list_empty (&bitrate_list); decode_time = decoder_seek; eof = false; decoded = 0; } LOCK (request_cond_mutex); if (request == REQ_SEEK) request = REQ_NOTHING; UNLOCK (request_cond_mutex); } else if (!eof && decoded <= out_buf_get_free(out_buf) && !sound_params_change) { debug ("putting into the buffer %d bytes", decoded); #if !defined(NDEBUG) && defined(DEBUG) if (md5->okay) { md5->len += decoded; md5_process_bytes (buf, decoded, &md5->ctx); } #endif audio_send_buf (buf, decoded); decoded = 0; } else if (!eof && sound_params_change && out_buf_get_fill(out_buf) == 0) { logit ("Sound parameters have changed."); *sound_params = new_sound_params; sound_params_change = false; set_info_channels (sound_params->channels); set_info_rate (sound_params->rate / 1000); out_buf_wait (out_buf); if (!audio_open(sound_params)) { md5->okay = false; break; } } else if (eof && out_buf_get_fill(out_buf) == 0) { logit ("played everything"); break; } } status_msg (""); LOCK (decoder_stream_mut); decoder_stream = NULL; f->close (decoder_data); UNLOCK (decoder_stream_mut); bitrate_list_destroy (&bitrate_list); LOCK (curr_tags_mut); if (curr_tags) { tags_free (curr_tags); curr_tags = NULL; } UNLOCK (curr_tags_mut); out_buf_wait (out_buf); if (precache.ok && (stopped || !options_get_bool ("AutoNext"))) { precache_wait (&precache); precache.f->close (precache.decoder_data); precache_reset (&precache); } }
static void *precache_thread (void *data) { struct precache *precache = (struct precache *)data; int decoded; struct sound_params new_sound_params; struct decoder_error err; precache->buf_fill = 0; precache->sound_params.channels = 0; /* mark that sound_params were not yet filled. */ precache->decoded_time = 0.0; precache->f = get_decoder (precache->file); assert (precache->f != NULL); precache->decoder_data = precache->f->open(precache->file); precache->f->get_error(precache->decoder_data, &err); if (err.type != ERROR_OK) { logit ("Failed to open the file for precache: %s", err.err); decoder_error_clear (&err); precache->f->close (precache->decoder_data); return NULL; } audio_plist_set_time (precache->file, precache->f->get_duration(precache->decoder_data)); /* Stop at PCM_BUF_SIZE, because when we decode too much, there is no * place where we can put the data that doesn't fit into the buffer. */ while (precache->buf_fill < PCM_BUF_SIZE) { decoded = precache->f->decode (precache->decoder_data, precache->buf + precache->buf_fill, PCM_BUF_SIZE, &new_sound_params); if (!decoded) { /* EOF so fast? We can't pass this information * in precache, so give up. */ logit ("EOF when precaching."); precache->f->close (precache->decoder_data); return NULL; } precache->f->get_error (precache->decoder_data, &err); if (err.type == ERROR_FATAL) { logit ("Error reading file for precache: %s", err.err); decoder_error_clear (&err); precache->f->close (precache->decoder_data); return NULL; } if (!precache->sound_params.channels) precache->sound_params = new_sound_params; else if (!sound_params_eq(precache->sound_params, new_sound_params)) { /* There is no way to store sound with two different * parameters in the buffer, give up with * precaching. (this should never happen). */ logit ("Sound parameters have changed when precaching."); decoder_error_clear (&err); precache->f->close (precache->decoder_data); return NULL; } bitrate_list_add (&precache->bitrate_list, precache->decoded_time, precache->f->get_bitrate( precache->decoder_data)); precache->buf_fill += decoded; precache->decoded_time += decoded / (float)(sfmt_Bps( new_sound_params.fmt) * new_sound_params.rate * new_sound_params.channels); if (err.type != ERROR_OK) { decoder_error_clear (&err); break; /* Don't lose the error message */ } } precache->ok = 1; logit ("Successfully precached file (%d bytes)", precache->buf_fill); return NULL; }