Example #1
0
void resample_samples(struct processstate *process) {
	size_t idone, odone;
	size_t clip_cnt;
	
	soxr_error_t error =
		SOXR(r, process, r->resampler, process->inbuf, process->in_frames, &idone, process->outbuf, process->max_out_frames, &odone);
	if (error) {
		LOG_INFO("soxr_process error: %s", soxr_strerror(error));
		return;
	}
	
	if (idone != process->in_frames) {
		// should not get here if buffers are big enough...
		LOG_ERROR("should not get here - partial sox process: %u of %u processed %u of %u out",
				  (unsigned)idone, process->in_frames, (unsigned)odone, process->max_out_frames);
	}
	
	process->out_frames = odone;
	process->total_in  += idone;
	process->total_out += odone;
	
	clip_cnt = *(SOXR(r, num_clips, r->resampler));
	if (clip_cnt - r->old_clips) {
		LOG_SDEBUG("resampling clips: %u", (unsigned)(clip_cnt - r->old_clips));
		r->old_clips = clip_cnt;
	}
}
Example #2
0
/*---------------------------------------------------------------------------*/
static void *decode_thread(struct thread_ctx_s *ctx) {
	while (ctx->decode_running) {
		size_t bytes, space, min_space;
		bool toend;
		bool ran = false;

		LOCK_S;
		bytes = _buf_used(ctx->streambuf);
		toend = (ctx->stream.state <= DISCONNECT);
		UNLOCK_S;
		LOCK_O;
		space = _buf_space(ctx->outputbuf);
		UNLOCK_O;

		LOCK_D;

		if (ctx->decode.state == DECODE_RUNNING && ctx->codec) {

			LOG_SDEBUG("streambuf bytes: %u outputbuf space: %u", bytes, space);

			IF_DIRECT(
				min_space = ctx->codec->min_space;
			);
			IF_PROCESS(
				min_space = ctx->process.max_out_frames * BYTES_PER_FRAME;
			);
Example #3
0
void resample_samples(struct thread_ctx_s *ctx) {
	struct soxr *r = ctx->decode.process_handle;
	size_t idone, odone;
	size_t clip_cnt;

	soxr_error_t error =
		SOXR(&gr, process, r->resampler, ctx->process.inbuf, ctx->process.in_frames, &idone, ctx->process.outbuf, ctx->process.max_out_frames, &odone);
	if (error) {
		LOG_INFO("[%p]: soxr_process error: %s", ctx, soxr_strerror(error));
		return;
	}

	if (idone != ctx->process.in_frames) {
		// should not get here if buffers are big enough...
		LOG_ERROR("[%p]: should not get here - partial sox process: %u of %u processed %u of %u out",
				  ctx, (unsigned)idone, ctx->process.in_frames, (unsigned)odone, ctx->process.max_out_frames);
	}
	
	ctx->process.out_frames = odone;
	ctx->process.total_in  += idone;
	ctx->process.total_out += odone;

	clip_cnt = *(SOXR(&gr, num_clips, r->resampler));
	if (clip_cnt - r->old_clips) {
		LOG_SDEBUG("[%p]: resampling clips: %u", ctx, (unsigned)(clip_cnt - r->old_clips));
		r->old_clips = clip_cnt;
	}
}
Example #4
0
static void *decode_thread() {

	while (running) {
		size_t bytes, space;
		bool toend;
		bool ran = false;

		LOCK_S;
		bytes = _buf_used(streambuf);
		toend = (stream.state <= DISCONNECT);
		UNLOCK_S;
		LOCK_O;
		space = _buf_space(outputbuf);
		UNLOCK_O;

		LOCK_D;

		if (decode.state == DECODE_RUNNING && codec) {
		
			LOG_SDEBUG("streambuf bytes: %u outputbuf space: %u", bytes, space);
			
			if (space > codec->min_space && (bytes > codec->min_read_bytes || toend)) {
				
				decode.state = codec->decode();

				if (decode.state != DECODE_RUNNING) {

					LOG_INFO("decode %s", decode.state == DECODE_COMPLETE ? "complete" : "error");

					LOCK_O;
					if (output.fade_mode) _checkfade(false);
					UNLOCK_O;

					wake_controller();
				}

				ran = true;
			}
		}
		
		UNLOCK_D;

		if (!ran) {
			usleep(100000);
		}
	}

	return 0;
}
Example #5
0
static void sendSTAT(const char *event, u32_t server_timestamp) {
	struct STAT_packet pkt;
	u32_t now = gettime_ms();
	u32_t ms_played;

	if (status.current_sample_rate && status.frames_played && status.frames_played > status.device_frames) {
		ms_played = (u32_t)(((u64_t)(status.frames_played - status.device_frames) * (u64_t)1000) / (u64_t)status.current_sample_rate);
		if (now > status.updated) ms_played += (now - status.updated);
	} else {
		ms_played = 0;
	}
	
	memset(&pkt, 0, sizeof(struct STAT_packet));
	memcpy(&pkt.opcode, "STAT", 4);
	pkt.length = htonl(sizeof(struct STAT_packet) - 8);
	memcpy(&pkt.event, event, 4);
	// num_crlf
	// mas_initialized; mas_mode;
	packN(&pkt.stream_buffer_fullness, status.stream_full);
	packN(&pkt.stream_buffer_size, status.stream_size);
	packN(&pkt.bytes_received_H, (u64_t)status.stream_bytes >> 32);
	packN(&pkt.bytes_received_L, (u64_t)status.stream_bytes & 0xffffffff);
	pkt.signal_strength = 0xffff;
	packN(&pkt.jiffies, now);
	packN(&pkt.output_buffer_size, status.output_size);
	packN(&pkt.output_buffer_fullness, status.output_full);
	packN(&pkt.elapsed_seconds, ms_played / 1000);
	// voltage;
	packN(&pkt.elapsed_milliseconds, ms_played);
	pkt.server_timestamp = server_timestamp; // keep this is server format - don't unpack/pack
	// error_code;

	LOG_INFO("STAT: %s", event);

	if (loglevel == lSDEBUG) {
		LOG_SDEBUG("received bytesL: %u streambuf: %u outputbuf: %u calc elapsed: %u real elapsed: %u (diff: %u) device: %u delay: %d",
				   (u32_t)status.stream_bytes, status.stream_full, status.output_full, ms_played, now - status.stream_start,
				   ms_played - now + status.stream_start, status.device_frames * 1000 / status.current_sample_rate, now - status.updated);
	}

	send_packet((u8_t *)&pkt, sizeof(pkt));
}
Example #6
0
frames_t _output_frames(frames_t avail) {

	frames_t frames, size;
	bool silence;
	
	s32_t cross_gain_in = 0, cross_gain_out = 0; s32_t *cross_ptr = NULL;
	
	s32_t gainL = output.current_replay_gain ? gain(output.gainL, output.current_replay_gain) : output.gainL;
	s32_t gainR = output.current_replay_gain ? gain(output.gainR, output.current_replay_gain) : output.gainR;

	if (output.invert) { gainL = -gainL; gainR = -gainR; }

	frames = _buf_used(outputbuf) / BYTES_PER_FRAME;
	silence = false;

	// start when threshold met
	if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 && frames > output.start_frames) {
		output.state = OUTPUT_RUNNING;
		LOG_INFO("start buffer frames: %u", frames);
		wake_controller();
	}
	
	// skip ahead - consume outputbuf but play nothing
	if (output.state == OUTPUT_SKIP_FRAMES) {
		if (frames > 0) {
			frames_t skip = min(frames, output.skip_frames);
			LOG_INFO("skip %u of %u frames", skip, output.skip_frames);
			frames -= skip;
			output.frames_played += skip;
			while (skip > 0) {
				frames_t cont_frames = min(skip, _buf_cont_read(outputbuf) / BYTES_PER_FRAME);
				skip -= cont_frames;
				_buf_inc_readp(outputbuf, cont_frames * BYTES_PER_FRAME);
			}
		}
		output.state = OUTPUT_RUNNING;
	}
	
	// pause frames - play silence for required frames
	if (output.state == OUTPUT_PAUSE_FRAMES) {
		LOG_INFO("pause %u frames", output.pause_frames);
		if (output.pause_frames == 0) {
			output.state = OUTPUT_RUNNING;
		} else {
			silence = true;
			frames = min(avail, output.pause_frames);
			frames = min(frames, MAX_SILENCE_FRAMES);
			output.pause_frames -= frames;
		}
	}
	
	// start at - play silence until jiffies reached
	if (output.state == OUTPUT_START_AT) {
		u32_t now = gettime_ms();
		if (now >= output.start_at || output.start_at > now + 10000) {
			output.state = OUTPUT_RUNNING;
		} else {
			u32_t delta_frames = (output.start_at - now) * output.current_sample_rate / 1000;
			silence = true;
			frames = min(avail, delta_frames);
			frames = min(frames, MAX_SILENCE_FRAMES);
		}
	}
	
	// play silence if buffering or no frames
	if (output.state <= OUTPUT_BUFFER || frames == 0) {
		silence = true;
		frames = min(avail, MAX_SILENCE_FRAMES);
	}

	LOG_SDEBUG("avail: %d frames: %d silence: %d", avail, frames, silence);
	frames = min(frames, avail);
	size = frames;
	
	while (size > 0) {
		frames_t out_frames;
		frames_t cont_frames = _buf_cont_read(outputbuf) / BYTES_PER_FRAME;
		int wrote;
		
		if (output.track_start && !silence) {
			if (output.track_start == outputbuf->readp) {
				unsigned delay = 0;
				if (output.current_sample_rate != output.next_sample_rate) {
					delay = output.rate_delay;
				}
				IF_DSD(
				   if (output.dop != output.next_dop) {
					   delay = output.dop_delay;
				   }
				)
				frames -= size;
				// add silence delay in two halves, before and after track start on rate or pcm-dop change
				if (delay) {
					output.state = OUTPUT_PAUSE_FRAMES;
					if (!output.delay_active) {
						output.pause_frames = output.current_sample_rate * delay / 2000;
						output.delay_active = true;  // first delay - don't process track start
						break;
					} else {
						output.pause_frames = output.next_sample_rate * delay / 2000;
						output.delay_active = false; // second delay - process track start
					}
				}
				LOG_INFO("track start sample rate: %u replay_gain: %u", output.next_sample_rate, output.next_replay_gain);
				output.frames_played = 0;
				output.track_started = true;
				output.track_start_time = gettime_ms();
				output.current_sample_rate = output.next_sample_rate;
				IF_DSD(
				   output.dop = output.next_dop;
				)
				if (output.fade != FADE_ACTIVE || output.fade_mode != FADE_CROSSFADE) {
					output.current_replay_gain = output.next_replay_gain;
				}
				output.track_start = NULL;
				break;
			} else if (output.track_start > outputbuf->readp) {
Example #7
0
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;
}
Example #8
0
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;
		);