//codecfilter_celt.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011 * * 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" #ifdef ROAR_HAVE_LIBCELT #ifdef ROAR_HAVE_CELT_VERSION_0_7_1 typedef celt_int16 celt_int16_t; #endif int cf_celt_open(CODECFILTER_USERDATA_T * inst, int codec, struct roar_stream_server * info, struct roar_codecfilter * filter) { struct codecfilter_celt_inst * self = roar_mm_malloc(sizeof(struct codecfilter_celt_inst)); struct roar_stream * s = ROAR_STREAM(info); if ( !self ) return -1; /* CELTMode * mode; CELTEncoder * encoder; CELTDecoder * decoder; int frame_size; int lookahead; int out_size; char * ibuf; char * obuf; char * rest; int s_buf; int f_rest; /-* how much is in rest? *-/ */ self->stream = info; self->frame_size = 256; self->lookahead = self->frame_size; self->encoder = NULL; self->decoder = NULL; self->opened_encoder = 0; self->opened_decoder = 0; self->s_buf = s->info.channels * self->frame_size * 2; self->ibuf = roar_mm_malloc(self->s_buf); self->obuf = roar_mm_malloc(self->s_buf); self->i_rest = roar_mm_malloc(self->s_buf); self->o_rest = roar_mm_malloc(self->s_buf); self->fi_rest = 0; self->fo_rest = 0; if ( !(self->ibuf && self->obuf && self->i_rest && self->o_rest) ) { if ( self->ibuf != NULL ) roar_mm_free(self->ibuf); if ( self->obuf != NULL ) roar_mm_free(self->obuf); if ( self->i_rest != NULL ) roar_mm_free(self->o_rest); if ( self->o_rest != NULL ) roar_mm_free(self->o_rest); roar_mm_free(self); return -1; } #ifdef ROAR_HAVE_CELT_VERSION_0_7_1 self->mode = celt_mode_create(s->info.rate, self->frame_size, NULL); #else self->mode = celt_mode_create(s->info.rate, s->info.channels, self->frame_size, NULL); #endif if ( !self->mode ) { roar_mm_free(self); return -1; } if ( s->dir == ROAR_DIR_PLAY ) { #ifdef ROAR_HAVE_CELT_VERSION_0_7_1 self->decoder = celt_decoder_create(self->mode, s->info.channels, NULL); #else self->decoder = celt_decoder_create(self->mode); #endif } else if ( s->dir == ROAR_DIR_MONITOR || s->dir == ROAR_DIR_OUTPUT ) { #ifdef ROAR_HAVE_CELT_VERSION_0_7_1 self->encoder = celt_encoder_create(self->mode, s->info.channels, NULL); #else self->encoder = celt_encoder_create(self->mode); #endif } else if ( s->dir == ROAR_DIR_BIDIR ) { #ifdef ROAR_HAVE_CELT_VERSION_0_7_1 self->decoder = celt_decoder_create(self->mode, s->info.channels, NULL); self->encoder = celt_encoder_create(self->mode, s->info.channels, NULL); #else self->decoder = celt_decoder_create(self->mode); self->encoder = celt_encoder_create(self->mode); #endif } else { celt_mode_destroy(self->mode); roar_mm_free(self); return -1; } *inst = (CODECFILTER_USERDATA_T) self; s->info.codec = ROAR_CODEC_DEFAULT; s->info.bits = 16; // CELT hardcoded return 0; } int cf_celt_close(CODECFILTER_USERDATA_T inst) { struct codecfilter_celt_inst * self = (struct codecfilter_celt_inst *) inst; if ( !inst ) return -1; if ( self->encoder != NULL ) celt_encoder_destroy(self->encoder); if ( self->decoder != NULL ) celt_decoder_destroy(self->decoder); if ( self->mode != NULL ) celt_mode_destroy(self->mode); if ( self->ibuf != NULL ) roar_mm_free(self->ibuf); if ( self->obuf != NULL ) roar_mm_free(self->obuf); if ( self->i_rest != NULL ) roar_mm_free(self->i_rest); if ( self->o_rest != NULL ) roar_mm_free(self->o_rest); roar_mm_free(inst); return 0; } int cf_celt_read(CODECFILTER_USERDATA_T inst, char * buf, int len) { struct codecfilter_celt_inst * self = (struct codecfilter_celt_inst *) inst; int r = 0; uint16_t fs; char * cbuf; char magic[ROAR_CELT_MAGIC_LEN]; // printf("buf=%p, len=%i\n", buf, len); if ( !self->opened_decoder ) { errno = ENOSYS; if ( stream_vio_s_read(self->stream, magic, ROAR_CELT_MAGIC_LEN) != ROAR_CELT_MAGIC_LEN ) return -1; if ( memcmp(magic, ROAR_CELT_MAGIC, ROAR_CELT_MAGIC_LEN) != 0 ) return -1; errno = 0; self->opened_decoder = 1; } if ( self->fi_rest ) { memcpy(buf, self->i_rest, self->fi_rest); r += self->fi_rest; self->fi_rest = 0; } while ( r <= (len - self->s_buf) ) { if ( stream_vio_s_read(self->stream, &fs, 2) != 2 ) break; fs = ROAR_NET2HOST16(fs); // ROAR_WARN("0:fs=%i", fs); if ( fs > self->s_buf ) return -1; if ( stream_vio_s_read(self->stream, self->ibuf, fs) != fs ) return -1; cbuf = buf + r; // printf("buf=%p, r=%i // cbuf=%p\n", buf, r, cbuf); if ( celt_decode(self->decoder, (unsigned char *) self->ibuf, fs, (celt_int16_t *) cbuf) < 0 ) return -1; r += self->s_buf; } if ( r < len ) { // printf("r < len!\n"); if ( stream_vio_s_read(self->stream, &fs, 2) == 2 ) { fs = ROAR_NET2HOST16(fs); // ROAR_WARN("1:fs=%i", fs); // printf("next: fs=%i\n", fs); if ( fs > self->s_buf ) return -1; if ( stream_vio_s_read(self->stream, self->ibuf, fs) == fs ) { // printf("got data!\n"); if ( celt_decode(self->decoder, (unsigned char *) self->ibuf, fs, (celt_int16_t *) self->obuf) >= 0 ) { // printf("{ // decode rest\n"); // printf(" r=%i // need %i Bytes\n", r, len - r); // printf(" memcpy(buf+%i, self->obuf, %i) = ?\n", r, len - r); memcpy(buf+r, self->obuf, len - r); self->fi_rest = self->s_buf + r - len; memcpy(self->i_rest, self->obuf + len - r, self->fi_rest); // printf(" len=%i, r=%i, fi_rest=%i, s_buf=%i\n", len, r, self->fi_rest, self->s_buf); r = len; // printf("}\n"); } } } } ROAR_DBG("cf_celt_read(inst=%p, buf=%p, len=%i) = %i", inst, buf, len, r); return r; } #define BS (ROAR_STREAM(self->stream)->info.channels * 32) int cf_celt_write(CODECFILTER_USERDATA_T inst, char * buf, int len) { struct codecfilter_celt_inst * self = (struct codecfilter_celt_inst *) inst; int have = 0; int org_len = len; int diff; int fs2 = self->frame_size * 2 * ROAR_STREAM(self->stream)->info.channels; int sid; uint16_t pkglen_net, pkglen; unsigned char cbits[BS+2]; void * prethru; if ( !self->opened_encoder ) { sid = ROAR_STREAM(self->stream)->id; if ( stream_prethru_destroy(sid) == -1 ) { return -1; } if ( stream_prethru_add_data(sid, &prethru, ROAR_CELT_MAGIC_LEN) == -1 ) { return -1; } memcpy(prethru, ROAR_CELT_MAGIC, ROAR_CELT_MAGIC_LEN); if ( stream_vio_s_write(self->stream, ROAR_CELT_MAGIC, ROAR_CELT_MAGIC_LEN) != ROAR_CELT_MAGIC_LEN ) return -1; self->opened_encoder = 1; } if ( (self->fo_rest + len) > fs2 ) { if ( self->fo_rest ) { memcpy(self->obuf, self->o_rest, self->fo_rest); have = self->fo_rest; self->fo_rest = 0; } memcpy(self->obuf+have, buf, (diff=fs2-have)); buf += diff; len -= diff; pkglen = celt_encode(self->encoder, (celt_int16_t *) self->obuf, NULL, cbits+2, BS); pkglen_net = ROAR_HOST2NET16(pkglen); *(uint16_t*)cbits = pkglen_net; if ( stream_vio_s_write(self->stream, cbits, pkglen+2) == -1 ) return -1; while (len >= fs2) { pkglen = celt_encode(self->encoder, (celt_int16_t *) buf, NULL, cbits+2, BS); pkglen_net = ROAR_HOST2NET16(pkglen); *(uint16_t*)cbits = pkglen_net; if ( stream_vio_s_write(self->stream, cbits, pkglen+2) == -1 ) return -1; len -= fs2; buf += fs2; } } if ( len ) { memcpy(self->o_rest + self->fo_rest, buf, len); self->fo_rest += len; len = 0; } return org_len; } int cf_celt_delay(CODECFILTER_USERDATA_T inst, uint_least32_t * delay) { struct codecfilter_celt_inst * self = (struct codecfilter_celt_inst *) inst; ROAR_DBG("cf_celt_delay(*) = ?"); if ( self == NULL ) { *delay = (1000000 * 256) / ROAR_RATE_DEFAULT; return 0; } else { *delay = (1000000 * self->frame_size) / ROAR_STREAM(self->stream)->info.rate; ROAR_DBG("cf_celt_delay(*): frame_size=%i, rate=%i, *delay=%i", self->frame_size, ROAR_STREAM(self->stream)->info.rate, *delay); return 0; } return -1; } #endif //ll