/* * MOC - music on console * Copyright (C) 2005 Damian Pietras * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ /* The code is based on libxmms-flac written by Josh Coalson. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /*#define DEBUG*/ #include #include #include #include #include "audio.h" #include "decoder.h" #include "server.h" #include "common.h" #include "log.h" #include "io.h" #define MAX_SUPPORTED_CHANNELS 2 #define SAMPLES_PER_WRITE 512 #define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * MAX_SUPPORTED_CHANNELS * (32/8)) struct flac_data { FLAC__SeekableStreamDecoder *decoder; struct io_stream *stream; int bitrate; int abort; /* abort playing (due to an error) */ unsigned length; unsigned total_samples; FLAC__byte sample_buffer[SAMPLE_BUFFER_SIZE]; unsigned sample_buffer_fill; /* sound parameters */ unsigned bits_per_sample; unsigned sample_rate; unsigned channels; FLAC__uint64 last_decode_position; int ok; /* was this stream successfully opened? */ struct decoder_error error; }; /* Convert FLAC big-endian data into PCM little-endian. */ static size_t pack_pcm_signed (FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned bps) { FLAC__byte * const start = data; FLAC__int32 sample; const FLAC__int32 *input_; unsigned samples, channel; unsigned bytes_per_sample; unsigned incr; if (bps == 24) bps = 32; /* we encode to 32-bit words */ bytes_per_sample = bps / 8; incr = bytes_per_sample * channels; for (channel = 0; channel < channels; channel++) { samples = wide_samples; data = start + bytes_per_sample * channel; input_ = input[channel]; while(samples--) { sample = *input_++; switch(bps) { case 8: data[0] = sample; break; case 16: data[1] = (FLAC__byte)(sample >> 8); data[0] = (FLAC__byte)sample; break; case 32: data[3] = (FLAC__byte)(sample >> 16); data[2] = (FLAC__byte)(sample >> 8); data[1] = (FLAC__byte)sample; data[0] = 0; break; } data += incr; } } debug ("Converted %d bytes", wide_samples * channels * bytes_per_sample); return wide_samples * channels * bytes_per_sample; } static FLAC__StreamDecoderWriteStatus write_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { struct flac_data *data = (struct flac_data *)client_data; const unsigned wide_samples = frame->header.blocksize; if (data->abort) return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; data->sample_buffer_fill = pack_pcm_signed ( data->sample_buffer, buffer, wide_samples, data->channels, data->bits_per_sample); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void metadata_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, const FLAC__StreamMetadata *metadata, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { debug ("Got metadata info"); data->total_samples = (unsigned)(metadata->data.stream_info.total_samples & 0xffffffff); data->bits_per_sample = metadata->data.stream_info.bits_per_sample; data->channels = metadata->data.stream_info.channels; data->sample_rate = metadata->data.stream_info.sample_rate; data->length = data->total_samples / data->sample_rate; } } static void error_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, FLAC__StreamDecoderErrorStatus status, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; if (status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) { debug ("Aborting due to error"); data->abort = 1; } else decoder_error (&data->error, ERROR_FATAL, 0, "FLAC: lost sync"); } static FLAC__SeekableStreamDecoderReadStatus read_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, FLAC__byte buffer[], unsigned *bytes, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; ssize_t res; res = io_read (data->stream, buffer, *bytes); if (res > 0) { *bytes = res; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } if (res == 0) { *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } error ("read error: %s", io_strerror(data->stream)); return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } static FLAC__SeekableStreamDecoderSeekStatus seek_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, FLAC__uint64 absolute_byte_offset, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; return io_seek(data->stream, absolute_byte_offset, SEEK_SET) >= 0 ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; } static FLAC__SeekableStreamDecoderTellStatus tell_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, FLAC__uint64 *absolute_byte_offset, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; *absolute_byte_offset = io_tell (data->stream); return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; } static FLAC__SeekableStreamDecoderLengthStatus length_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, FLAC__uint64 *stream_length, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; *stream_length = io_file_size (data->stream); return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool eof_callback ( const FLAC__SeekableStreamDecoder *decoder ATTR_UNUSED, void *client_data) { struct flac_data *data = (struct flac_data *)client_data; return io_eof (data->stream); } static void *flac_open_internal (const char *file, const int buffered) { struct flac_data *data; data = (struct flac_data *)xmalloc (sizeof(struct flac_data)); decoder_error_init (&data->error); data->decoder = NULL; data->bitrate = -1; data->abort = 0; data->sample_buffer_fill = 0; data->last_decode_position = 0; data->stream = io_open (file, buffered); if (!io_ok(data->stream)) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't load file: %s", io_strerror(data->stream)); io_close (data->stream); return data; } data->ok = 1; if (!(data->decoder = FLAC__seekable_stream_decoder_new())) { decoder_error (&data->error, ERROR_FATAL, 0, "FLAC__seekable_stream_decoder_new() failed"); data->ok = 0; return data; } FLAC__seekable_stream_decoder_set_md5_checking (data->decoder, false); FLAC__seekable_stream_decoder_set_metadata_ignore_all (data->decoder); FLAC__seekable_stream_decoder_set_metadata_respond (data->decoder, FLAC__METADATA_TYPE_STREAMINFO); FLAC__seekable_stream_decoder_set_client_data (data->decoder, data); FLAC__seekable_stream_decoder_set_metadata_callback (data->decoder, metadata_callback); FLAC__seekable_stream_decoder_set_write_callback (data->decoder, write_callback); FLAC__seekable_stream_decoder_set_error_callback (data->decoder, error_callback); FLAC__seekable_stream_decoder_set_read_callback (data->decoder, read_callback); FLAC__seekable_stream_decoder_set_seek_callback (data->decoder, seek_callback); FLAC__seekable_stream_decoder_set_tell_callback (data->decoder, tell_callback); FLAC__seekable_stream_decoder_set_length_callback (data->decoder, length_callback); FLAC__seekable_stream_decoder_set_eof_callback (data->decoder, eof_callback); if (FLAC__seekable_stream_decoder_init(data->decoder) != FLAC__FILE_DECODER_OK) { decoder_error (&data->error, ERROR_FATAL, 0, "FLAC__seekable_stream_decoder_init() failed"); data->ok = 0; return data; } if (!FLAC__seekable_stream_decoder_process_until_end_of_metadata( data->decoder)) { decoder_error (&data->error, ERROR_FATAL, 0, "FLAC__seekable_stream_decoder_process_until_end_of_metadata()" " failed."); data->ok = 0; return data; } return data; } static void *flac_open (const char *file) { return flac_open_internal (file, 1); } static void flac_close (void *void_data) { struct flac_data *data = (struct flac_data *)void_data; if (data->ok) { if (data->decoder) { FLAC__seekable_stream_decoder_finish (data->decoder); FLAC__seekable_stream_decoder_delete (data->decoder); } io_close (data->stream); } free (data); } static void fill_tag (FLAC__StreamMetadata_VorbisComment_Entry *comm, struct file_tags *tags) { char *name, *value; FLAC__byte *eq; int value_length; eq = memchr (comm->entry, '=', comm->length); if (!eq) return; name = (char *)xmalloc (sizeof(char) * (eq - comm->entry + 1)); strncpy (name, (char *)comm->entry, eq - comm->entry); name[eq - comm->entry] = 0; value_length = comm->length - (eq - comm->entry + 1); if (value_length == 0) { free (name); return; } value = (char *)xmalloc (sizeof(char) * (value_length + 1)); strncpy (value, (char *)(eq + 1), value_length); value[value_length] = 0; if (!strcasecmp(name, "title")) tags->title = value; else if (!strcasecmp(name, "artist")) tags->artist = value; else if (!strcasecmp(name, "album")) tags->album = value; else if (!strcasecmp(name, "tracknumber") || !strcasecmp(name, "track")) { tags->track = atoi (value); free (value); } else free (value); } static void get_vorbiscomments (const char *filename, struct file_tags *tags) { FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new(); FLAC__bool got_vorbis_comments = false; debug ("Reading comments for %s", filename); if (!iterator) { logit ("FLAC__metadata_simple_iterator_new() failed."); return; } if (!FLAC__metadata_simple_iterator_init(iterator, filename, true, true)) { logit ("FLAC__metadata_simple_iterator_init failed."); FLAC__metadata_simple_iterator_delete(iterator); return; } do { if (FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) { FLAC__StreamMetadata *block; block = FLAC__metadata_simple_iterator_get_block ( iterator); if (block) { unsigned i; const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment; for (i = 0; i < vc->num_comments; i++) fill_tag (&vc->comments[i], tags); FLAC__metadata_object_delete (block); got_vorbis_comments = true; } } } while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator)); FLAC__metadata_simple_iterator_delete(iterator); } static void flac_info (const char *file_name, struct file_tags *info, const int tags_sel) { if (tags_sel & TAGS_TIME) { struct flac_data *data; if ((data = flac_open_internal(file_name, 0))) { info->time = data->length; flac_close (data); } } if (tags_sel & TAGS_COMMENTS) get_vorbiscomments (file_name, info); } static int flac_seek (void *void_data, int sec) { struct flac_data *data = (struct flac_data *)void_data; FLAC__uint64 target_sample; if (sec < 0 || (unsigned)sec > data->length) return -1; target_sample = (FLAC__uint64)((sec/(double)data->length) * (double)data->total_samples); if (FLAC__seekable_stream_decoder_seek_absolute(data->decoder, target_sample)) return sec; else { logit ("FLAC__seekable_stream_decoder_seek_absolute() failed."); return -1; } } static int flac_decode (void *void_data, char *buf, int buf_len, struct sound_params *sound_params) { struct flac_data *data = (struct flac_data *)void_data; unsigned to_copy; int bytes_per_sample; FLAC__uint64 decode_position; bytes_per_sample = data->bits_per_sample / 8; switch (bytes_per_sample) { case 1: sound_params->fmt = SFMT_S8; break; case 2: sound_params->fmt = SFMT_S16 | SFMT_LE; break; case 3: sound_params->fmt = SFMT_S32 | SFMT_LE; break; } sound_params->rate = data->sample_rate; sound_params->channels = data->channels; decoder_error_clear (&data->error); if (!data->sample_buffer_fill) { debug ("decoding..."); if (FLAC__seekable_stream_decoder_get_state(data->decoder) == FLAC__FILE_DECODER_END_OF_FILE) { logit ("EOF"); return 0; } if (!FLAC__seekable_stream_decoder_process_single( data->decoder)) { decoder_error (&data->error, ERROR_FATAL, 0, "Read error processing frame."); return 0; } /* Count the bitrate */ if(!FLAC__seekable_stream_decoder_get_decode_position( data->decoder, &decode_position)) decode_position = 0; if (decode_position > data->last_decode_position) { int bytes_per_sec = bytes_per_sample * data->sample_rate * data->channels; data->bitrate = (decode_position - data->last_decode_position) * 8.0 / (data->sample_buffer_fill / (float)bytes_per_sec) / 1000; } data->last_decode_position = decode_position; } else debug ("Some date remain in the buffer."); debug ("Decoded %d bytes", data->sample_buffer_fill); to_copy = MIN((unsigned)buf_len, data->sample_buffer_fill); memcpy (buf, data->sample_buffer, to_copy); memmove (data->sample_buffer, data->sample_buffer + to_copy, data->sample_buffer_fill - to_copy); data->sample_buffer_fill -= to_copy; return to_copy; } static int flac_get_bitrate (void *void_data) { struct flac_data *data = (struct flac_data *)void_data; return data->bitrate; } static int flac_get_duration (void *void_data) { struct flac_data *data = (struct flac_data *)void_data; return data->length; } static void flac_get_name (const char *file ATTR_UNUSED, char buf[4]) { strcpy (buf, "FLA"); } static int flac_our_format_ext (const char *ext) { return !strcasecmp(ext, "flac") || !strcasecmp(ext, "fla"); } static void flac_get_error (void *prv_data, struct decoder_error *error) { struct flac_data *data = (struct flac_data *)prv_data; decoder_error_copy (error, &data->error); } static struct decoder flac_decoder = { DECODER_API_VERSION, NULL, NULL, flac_open, NULL, NULL, flac_close, flac_decode, flac_seek, flac_info, flac_get_bitrate, flac_get_duration, flac_get_error, flac_our_format_ext, NULL, flac_get_name, NULL, NULL }; struct decoder *plugin_init () { return &flac_decoder; }