| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 | /*  *  Squeezelite - lightweight headless squeezebox emulator * *  (c) Adrian Smith 2012-2015, triode1@btinternet.com *      Ralph Irving 2015-2017, ralph_irving@hotmail.com * * 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 3 of the License, or * (at your option) any later version. *  * This program 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 program.  If not, see <http://www.gnu.org/licenses/>. * */// fifo bufffers #ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include "squeezelite.h"// _* called with muxtex lockedinline unsigned _buf_used(struct buffer *buf) {	return buf->writep >= buf->readp ? buf->writep - buf->readp : buf->size - (buf->readp - buf->writep);}unsigned _buf_space(struct buffer *buf) {	return buf->size - _buf_used(buf) - 1; // reduce by one as full same as empty otherwise}unsigned _buf_cont_read(struct buffer *buf) {	return buf->writep >= buf->readp ? buf->writep - buf->readp : buf->wrap - buf->readp;}unsigned _buf_cont_write(struct buffer *buf) {	return buf->writep >= buf->readp ? buf->wrap - buf->writep : buf->readp - buf->writep;}void _buf_inc_readp(struct buffer *buf, unsigned by) {	buf->readp += by;	if (buf->readp >= buf->wrap) {		buf->readp -= buf->size;	}}void _buf_inc_writep(struct buffer *buf, unsigned by) {	buf->writep += by;	if (buf->writep >= buf->wrap) {		buf->writep -= buf->size;	}}void buf_flush(struct buffer *buf) {	mutex_lock(buf->mutex);	buf->readp  = buf->buf;	buf->writep = buf->buf;	mutex_unlock(buf->mutex);}void _buf_flush(struct buffer *buf) {	buf->readp  = buf->buf;	buf->writep = buf->buf;}// adjust buffer to multiple of mod bytes so reading in multiple always wraps on frame boundaryvoid buf_adjust(struct buffer *buf, size_t mod) {	mutex_lock(buf->mutex);	buf->base_size = ((size_t)(buf->size / mod)) * mod;	buf->readp  = buf->writep = buf->buf;	buf->wrap   = buf->buf + buf->base_size;	buf->size   = buf->base_size;	mutex_unlock(buf->mutex);}// called with mutex locked to resize, does not retain contents, reverts to original size if failsvoid _buf_resize(struct buffer *buf, size_t size) {	if (size == buf->size) return;	free(buf->buf);	buf->buf = malloc(size);	if (!buf->buf) {		size    = buf->size;		buf->buf = malloc(size);		if (!buf->buf) size = 0;	}	buf->writep = buf->readp  = buf->buf;	buf->wrap   = buf->buf + size;	buf->true_size = buf->base_size = buf->size = size;}size_t _buf_limit(struct buffer *buf, size_t limit) {	if (limit) {		buf->size = limit;		buf->readp = buf->writep = buf->buf;	} else {		buf->size = buf->base_size;	}	buf->wrap = buf->buf + buf->size;	return buf->base_size - buf->size;}void _buf_unwrap(struct buffer *buf, size_t cont) {	ssize_t len, by = cont - (buf->wrap - buf->readp);	size_t size;	u8_t *scratch;	// do nothing if we have enough space	if (by <= 0 || cont >= buf->size) return;	// buffer already unwrapped, just move it up	if (buf->writep >= buf->readp) {		memmove(buf->readp - by, buf->readp, buf->writep - buf->readp);		buf->readp -= by;		buf->writep -= by;		return;	 }	// how much is overlapping	size = by - (buf->readp - buf->writep);	len = buf->writep - buf->buf;	// buffer is wrapped and enough free space to move data up directly	if (size <= 0) {		memmove(buf->readp - by, buf->readp, buf->wrap - buf->readp);		buf->readp -= by;		memcpy(buf->wrap - by, buf->buf, min(len, by));		if (len > by) {			memmove(buf->buf, buf->buf + by, len - by);			buf->writep -= by;		} else {			buf->writep += buf->size - by;		}		return;	}	scratch = malloc(size);	// buffer is wrapped but not enough free room => use scratch zone	if (scratch) {		memcpy(scratch, buf->writep - size, size);		memmove(buf->readp - by, buf->readp, buf->wrap - buf->readp);		buf->readp -= by;		memcpy(buf->wrap - by, buf->buf, by);		memmove(buf->buf, buf->buf + by, len - by - size);		buf->writep -= by;		memcpy(buf->writep - size, scratch, size);		free(scratch);	} else {		_buf_unwrap(buf, cont / 2);        _buf_unwrap(buf, cont - cont / 2);	}}void buf_init(struct buffer *buf, size_t size) {	buf->buf    = malloc(size);	buf->readp  = buf->buf;	buf->writep = buf->buf;	buf->wrap   = buf->buf + size;	buf->true_size = buf->base_size = buf->size = size;	mutex_create_p(buf->mutex);}void buf_destroy(struct buffer *buf) {	if (buf->buf) {		free(buf->buf);		buf->buf = NULL;		buf->size = buf->base_size = buf->true_size = 0;		mutex_destroy(buf->mutex);	}}
 |