//codecfilter_flac.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2015 * * This file is part of roard a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * RoarAudio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "roard.h" #include #ifdef ROAR_HAVE_LIBFLAC FLAC__StreamDecoderReadStatus cf_flac_cb_read(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) { struct codecfilter_flac_inst * self = client_data; ssize_t ret; ROAR_DBG("cf_flac_cb_read(decoder=%p, buffer=%p, bytes=%p{%u}, client_data=%p) = ?", decoder, buffer, bytes, *bytes, client_data); ret = stream_vio_s_read(self->ss, buffer, *bytes); self->decoder.readret = ret; self->decoder.readc++; if (ret == -1) { *bytes = 0; #ifdef EAGAIN if ( errno == EAGAIN ) { ROAR_DBG("cf_flac_cb_read(decoder=%p, buffer=%p, bytes=%p{%u}, client_data=%p) = FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", decoder, buffer, bytes, *bytes, client_data); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } #endif ROAR_DBG("cf_flac_cb_read(decoder=%p, buffer=%p, bytes=%p{%u}, client_data=%p) = FLAC__STREAM_DECODER_READ_STATUS_ABORT", decoder, buffer, bytes, *bytes, client_data); return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } else { *bytes = ret; if ( ret == 0 && self->decoder.readc == 1 ) { ROAR_DBG("cf_flac_cb_read(decoder=%p, buffer=%p, bytes=%p{%u}, client_data=%p) = FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM", decoder, buffer, bytes, *bytes, client_data); return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } ROAR_DBG("cf_flac_cb_read(decoder=%p, buffer=%p, bytes=%p{%u}, client_data=%p) = FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", decoder, buffer, bytes, *bytes, client_data); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } } FLAC__StreamDecoderWriteStatus cf_flac_cb_write(const FLAC__StreamDecoder * decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { struct codecfilter_flac_inst * self = client_data; struct roar_buffer * buf; struct roar_interleave is; size_t buflen = _32BIT * frame->header.blocksize * frame->header.channels; void * bufdata; int32_t * c; size_t i; int32_t shift = 32 - frame->header.bits_per_sample; ROAR_DBG("cf_flac_cb_write(decoder=%p, frame=%p, buffer=%p, client_data=%p) = ?", decoder, frame, buffer, client_data); if ( roar_interl_init(&is, frame->header.channels, 32) == -1 ) { ROAR_DBG("cf_flac_cb_write(decoder=%p, frame=%p, buffer=%p, client_data=%p) = FLAC__STREAM_DECODER_WRITE_STATUS_ABORT", decoder, frame, buffer, client_data); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } if ( roar_buffer_new_data(&buf, buflen, &bufdata) == -1 ) { ROAR_DBG("cf_flac_cb_write(decoder=%p, frame=%p, buffer=%p, client_data=%p) = FLAC__STREAM_DECODER_WRITE_STATUS_ABORT", decoder, frame, buffer, client_data); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } roar_interl_encode_ext(&is, (void**)buffer, bufdata, buflen); roar_interl_uninit(&is); if ( shift ) { buflen /= 4; for (c = bufdata, i = 0; i < buflen; i++) { c[i] <<= shift; } } if ( self->decoder.written == NULL ) { self->decoder.written = buf; } else { if ( roar_buffer_moveinto(self->decoder.written, &buf) == -1 ) { roar_buffer_free(buf); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } ROAR_DBG("cf_flac_cb_write(decoder=%p, frame=%p, buffer=%p, client_data=%p) = FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", decoder, frame, buffer, client_data); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } void cf_flac_cb_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { struct codecfilter_flac_inst * self = client_data; const FLAC__StreamMetadata_VorbisComment * vc; FLAC__uint32 i; struct roar_stream_rpg rpg; const char * key, * value; char keycopy[ROAR_META_MAX_NAMELEN]; int type; float rpg_track = 0, rpg_album = 0, rpg_final = 0; if ( metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT ) { ROAR_DBG("cf_flac_cb_metadata(decoder=%p, metadata=%p, client_data=%p): have METADATA_TYPE_VORBIS_COMMENT", decoder, metadata, client_data); stream_meta_clear(ROAR_STREAM(self->ss)->id); vc = &(metadata->data.vorbis_comment); for (i = 0; i < vc->num_comments; i++) { //printf("c='%s'\n", vc->comments[i].entry); key = (const char *)vc->comments[i].entry; value = strstr(key, "="); if ( value == NULL ) continue; if ( (value - key + 1) > sizeof(keycopy) ) continue; memcpy(keycopy, key, value - key); keycopy[sizeof(keycopy)-1] = 0; keycopy[value - key] = 0; value++; //printf("keycopy='%s', value='%s'\n", keycopy, value); type = roar_meta_inttype(keycopy); if ( type == -1 ) continue; if ( stream_meta_add(ROAR_STREAM(self->ss)->id, type, "", value) == -1 ) { ROAR_WARN("cf_flac_cb_metadata(..., client_data=%p{ROAR_STREAM(.ss)->id=%i}): Can not add meta data: %s", self->ss, ROAR_STREAM(self->ss)->id, roar_error2str(roar_error)); } if ( strcmp(keycopy, "REPLAYGAIN_TRACK_PEAK") == 0 ) { rpg_track = 1/atof(value); /* } else if ( strcmp(key, "REPLAYGAIN_TRACK_GAIN") == 0 ) { rpg_track = powf(10, atof(value)/20); */ } else if ( strcmp(keycopy, "REPLAYGAIN_ALBUM_PEAK") == 0 ) { rpg_album = 1/atof(value); /* } else if ( strcmp(key, "REPLAYGAIN_ALBUM_GAIN") == 0 ) { rpg_album = powf(10, atof(value)/20); */ } } if ( streams_get_rpg(ROAR_STREAM(self->ss)->id, &rpg) != -1 ) { rpg_final = 0; switch (rpg.mode) { case ROAR_RPGMODE_NONE: rpg_final = 0.; break; case ROAR_RPGMODE_USER: rpg_final = -1.; break; case ROAR_RPGMODE_ALBUM: rpg_final = rpg_album; break; case ROAR_RPGMODE_TRACK: rpg_final = rpg_track; break; case ROAR_RPGMODE_ALBUMTRACK: rpg_final = rpg_album ? rpg_album : rpg_track; break; case ROAR_RPGMODE_TRACKALBUM: rpg_final = rpg_track ? rpg_track : rpg_album; break; } if ( rpg_final > 0 ) { self->ss->mixer.rpg_div = 2718; self->ss->mixer.rpg_mul = (float)rpg_final*2718; } else if ( !rpg_final ) { self->ss->mixer.rpg_div = 1; self->ss->mixer.rpg_mul = 1; } } stream_meta_finalize(ROAR_STREAM(self->ss)->id); } ROAR_DBG("cf_flac_cb_metadata(decoder=%p, metadata=%p, client_data=%p) = (void)", decoder, metadata, client_data); } void cf_flac_cb_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { ROAR_DBG("cf_flac_cb_error(decoder=%p, status=%i, client_data=%p) = (void)", decoder, (int)status, client_data); } int cf_flac_open(CODECFILTER_USERDATA_T * inst, int codec, struct roar_stream_server * info, struct roar_codecfilter * filter) { struct codecfilter_flac_inst * self; if ( ROAR_STREAM(info)->dir != ROAR_DIR_PLAY ) return -1; self = roar_mm_malloc(sizeof(struct codecfilter_flac_inst)); if (self == NULL) return -1; memset(self, 0, sizeof(struct codecfilter_flac_inst)); self->ss = info; self->decoder.decoder = FLAC__stream_decoder_new(); if ( self->decoder.decoder == NULL ) { roar_mm_free(self); return -1; } #ifndef ROAR_HAVE_FLAC_VERSION_1_2_1 FLAC__stream_decoder_set_read_callback(self->decoder.decoder, cf_flac_cb_read); FLAC__stream_decoder_set_write_callback(self->decoder.decoder, cf_flac_cb_write); FLAC__stream_decoder_set_metadata_callback(self->decoder.decoder, cf_flac_cb_metadata); FLAC__stream_decoder_set_error_callback(self->decoder.decoder, cf_flac_cb_error); FLAC__stream_decoder_set_client_data(self->decoder.decoder, self); #endif FLAC__stream_decoder_set_metadata_respond(self->decoder.decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); #ifdef ROAR_HAVE_FLAC_VERSION_1_2_1 FLAC__stream_decoder_init_stream(self->decoder.decoder, cf_flac_cb_read, NULL, NULL, NULL, NULL, cf_flac_cb_write, cf_flac_cb_metadata, cf_flac_cb_error, self); #else FLAC__stream_decoder_init(self->decoder.decoder); #endif *inst = self; return 0; } int cf_flac_close(CODECFILTER_USERDATA_T inst) { struct codecfilter_flac_inst * self = inst; if ( self->decoder.decoder != NULL ) { FLAC__stream_decoder_delete(self->decoder.decoder); } roar_mm_free(self); return 0; } int cf_flac_write(CODECFILTER_USERDATA_T inst, char * buf, int len); int cf_flac_read(CODECFILTER_USERDATA_T inst, char * buf, int len) { struct codecfilter_flac_inst * self = inst; struct roar_audio_info * info = &(ROAR_STREAM(self->ss)->info); struct roar_buffer_stats stats; size_t ret; FLAC__StreamDecoderState state; if ( self->decoder.written == NULL ) { stats.bytes = 0; } else { if ( roar_buffer_ring_stats(self->decoder.written, &stats) == -1 ) return -1; } self->decoder.readret = 1; self->decoder.readc = 0; while ( self->decoder.readret > 0 && stats.bytes < len ) { if ( !FLAC__stream_decoder_process_single(self->decoder.decoder) ) { break; } state = FLAC__stream_decoder_get_state(self->decoder.decoder); if ( state == FLAC__STREAM_DECODER_END_OF_STREAM || state == FLAC__STREAM_DECODER_ABORTED ) break; if ( self->decoder.written == NULL && state == FLAC__STREAM_DECODER_READ_FRAME ) { return -1; } if ( self->decoder.written == NULL ) { stats.bytes = 0; } else { if ( roar_buffer_ring_stats(self->decoder.written, &stats) == -1 ) return -1; } } if ( stats.bytes ) { ret = len; if ( roar_buffer_shift_out(&(self->decoder.written), buf, &ret) == -1 ) { return -1; } info->codec = ROAR_CODEC_DEFAULT; info->bits = 32; info->channels = FLAC__stream_decoder_get_channels(self->decoder.decoder); info->rate = FLAC__stream_decoder_get_sample_rate(self->decoder.decoder); return ret; } else { return self->decoder.readret == -1 ? -1 : 0; } } int cf_flac_ctl(CODECFILTER_USERDATA_T inst, int cmd, void * data); #endif //ll