static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { size_t frames = frame->header.blocksize; unsigned bits_per_sample = frame->header.bits_per_sample; unsigned channels = frame->header.channels; FLAC__int32 *lptr = (FLAC__int32 *)buffer[0]; FLAC__int32 *rptr = (FLAC__int32 *)buffer[channels > 1 ? 1 : 0]; if (decode.new_stream) { LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.max_sample_rate); output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; } LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( optr = (s32_t *)outputbuf->writep; f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; ); IF_PROCESS( optr = (s32_t *)process.inbuf; f = process.max_in_frames; );
static decode_state mpg_decode(void) { size_t bytes, space, size; int ret; u8_t *write_buf; LOCK_S; LOCK_O_direct; bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); IF_DIRECT( space = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)); write_buf = outputbuf->writep; );
static decode_state vorbis_decode(void) { static int channels; bool end; frames_t frames; int bytes, s, n; u8_t *write_buf; LOCK_S; LOCK_O_direct; end = (stream.state <= DISCONNECT); IF_DIRECT( frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; );
static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { size_t frames = frame->header.blocksize; unsigned bits_per_sample = frame->header.bits_per_sample; unsigned channels = frame->header.channels; FLAC__int32 *lptr = (FLAC__int32 *)buffer[0]; FLAC__int32 *rptr = (FLAC__int32 *)buffer[channels > 1 ? 1 : 0]; if (decode.new_stream) { LOCK_O; LOG_INFO("setting track_start"); output.track_start = outputbuf->writep; decode.new_stream = false; #if DSD if (output.has_dop && bits_per_sample == 24 && is_flac_dop((u32_t *)lptr, (u32_t *)rptr, frames)) { LOG_INFO("file contains DOP"); output.next_dop = true; output.next_sample_rate = frame->header.sample_rate; output.fade = FADE_INACTIVE; } else { output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates); output.next_dop = false; if (output.fade_mode) _checkfade(true); } #else output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates); if (output.fade_mode) _checkfade(true); #endif UNLOCK_O; } LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( optr = (s32_t *)outputbuf->writep; f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; ); IF_PROCESS( optr = (s32_t *)process.inbuf; f = process.max_in_frames; );
static decode_state mpg_decode(void) { size_t bytes, space, size; int ret; LOCK_S; LOCK_O; bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); space = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)); bytes = min(bytes, READ_SIZE); space = min(space, WRITE_SIZE); if (stream.state <= DISCONNECT && bytes == 0) { UNLOCK_O; UNLOCK_S; return DECODE_COMPLETE; } if (m->use16bit) { space = (space / BYTES_PER_FRAME) * 4; } ret = m->mpg123_decode(m->h, streambuf->readp, bytes, outputbuf->writep, space, &size); if (ret == MPG123_NEW_FORMAT) { if (decode.new_stream) { long rate; int channels, enc; m->mpg123_getformat(m->h, &rate, &channels, &enc); LOG_INFO("setting track_start"); output.next_sample_rate = rate; output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; } else { LOG_WARN("format change mid stream - not supported"); } } // expand 16bit output to 32bit samples if (m->use16bit) { s16_t *iptr; s32_t *optr; size_t count = size / 2; size = count * 4; iptr = (s16_t *)outputbuf->writep + count; optr = (s32_t *)outputbuf->writep + count; while (count--) { *--optr = *--iptr << 16; } } _buf_inc_readp(streambuf, bytes); _buf_inc_writep(outputbuf, size); UNLOCK_O; UNLOCK_S; LOG_SDEBUG("write %u frames", size / BYTES_PER_FRAME); if (ret == MPG123_DONE) { LOG_INFO("stream complete"); return DECODE_COMPLETE; } if (ret == MPG123_ERR) { LOG_WARN("Error"); return DECODE_COMPLETE; } // OK and NEED_MORE keep running return DECODE_RUNNING; }
static decode_state faad_decode(void) { size_t bytes_total; size_t bytes_wrap; NeAACDecFrameInfo info; s32_t *iptr; bool endstream; frames_t frames; LOCK_S; bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); if (stream.state <= DISCONNECT && !bytes_total) { UNLOCK_S; return DECODE_COMPLETE; } if (a->consume) { u32_t consume = min(a->consume, bytes_wrap); LOG_DEBUG("consume: %u of %u", consume, a->consume); _buf_inc_readp(streambuf, consume); a->pos += consume; a->consume -= consume; UNLOCK_S; return DECODE_RUNNING; } if (decode.new_stream) { int found = 0; static unsigned char channels; static unsigned long samplerate; if (a->type == '2') { // adts stream - seek for header while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) { _buf_inc_readp(streambuf, 1); bytes_total--; bytes_wrap--; } if (bytes_wrap >= 2) { long n = NEAAC(a, Init, a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels); if (n < 0) { found = -1; } else { _buf_inc_readp(streambuf, n); found = 1; } } } else { // mp4 - read header found = read_mp4_header(&samplerate, &channels); } if (found == 1) { LOG_INFO("samplerate: %u channels: %u", samplerate, channels); bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(samplerate, output.max_sample_rate); output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; } else if (found == -1) { LOG_WARN("error reading stream header"); UNLOCK_S; return DECODE_ERROR; } else { // not finished header parsing come back next time UNLOCK_S; return DECODE_RUNNING; } } if (bytes_wrap < WRAPBUF_LEN && bytes_total > WRAPBUF_LEN) { // make a local copy of frames which may have wrapped round the end of streambuf u8_t buf[WRAPBUF_LEN]; memcpy(buf, streambuf->readp, bytes_wrap); memcpy(buf + bytes_wrap, streambuf->buf, WRAPBUF_LEN - bytes_wrap); iptr = NEAAC(a, Decode, a->hAac, &info, buf, WRAPBUF_LEN); } else { iptr = NEAAC(a, Decode, a->hAac, &info, streambuf->readp, bytes_wrap); } if (info.error) { LOG_WARN("error: %u %s", info.error, NEAAC(a, GetErrorMessage, info.error)); } endstream = false; // mp4 end of chunk - skip to next offset if (a->chunkinfo && a->chunkinfo[a->nextchunk].offset && a->sample++ == a->chunkinfo[a->nextchunk].sample) { if (a->chunkinfo[a->nextchunk].offset > a->pos) { u32_t skip = a->chunkinfo[a->nextchunk].offset - a->pos; if (skip != info.bytesconsumed) { LOG_DEBUG("skipping to next chunk pos: %u consumed: %u != skip: %u", a->pos, info.bytesconsumed, skip); } if (bytes_total >= skip) { _buf_inc_readp(streambuf, skip); a->pos += skip; } else { a->consume = skip; } a->nextchunk++; } else { LOG_ERROR("error: need to skip backwards!"); endstream = true; } // adts and mp4 when not at end of chunk } else if (info.bytesconsumed != 0) { _buf_inc_readp(streambuf, info.bytesconsumed); a->pos += info.bytesconsumed; // error which doesn't advance streambuf - end } else { endstream = true; } UNLOCK_S; if (endstream) { LOG_WARN("unable to decode further"); return DECODE_ERROR; } if (!info.samples) { a->empty = true; return DECODE_RUNNING; } frames = info.samples / info.channels; if (a->skip) { u32_t skip; if (a->empty) { a->empty = false; a->skip -= frames; LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames); } skip = min(frames, a->skip); LOG_DEBUG("gapless: skipping %u frames at start", skip); frames -= skip; a->skip -= skip; iptr += skip * info.channels; } if (a->samples) { if (a->samples < frames) { LOG_DEBUG("gapless: trimming %u frames from end", frames - a->samples); frames = (frames_t)a->samples; } a->samples -= frames; } LOG_SDEBUG("write %u frames", frames); LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME; optr = (s32_t *)outputbuf->writep; ); IF_PROCESS( f = process.max_in_frames; optr = (s32_t *)process.inbuf; );