| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 | 
							- /* 
 
-  *  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/>.
 
-  *
 
-  */
 
- // sample processing - only included when building with PROCESS set
 
- #include "squeezelite.h"
 
- #if PROCESS
 
- extern log_level loglevel;
 
- extern struct buffer *outputbuf;
 
- extern struct decodestate decode;
 
- struct processstate process;
 
- extern struct codec *codec;
 
- #define LOCK_D   mutex_lock(decode.mutex);
 
- #define UNLOCK_D mutex_unlock(decode.mutex);
 
- #define LOCK_O   mutex_lock(outputbuf->mutex)
 
- #define UNLOCK_O mutex_unlock(outputbuf->mutex)
 
- // macros to map to processing functions - currently only resample.c
 
- // this can be made more generic when multiple processing mechanisms get added
 
- #if RESAMPLE || RESAMPLE16
 
- #define SAMPLES_FUNC resample_samples
 
- #define DRAIN_FUNC   resample_drain
 
- #define NEWSTREAM_FUNC resample_newstream
 
- #define FLUSH_FUNC   resample_flush
 
- #define INIT_FUNC    resample_init
 
- #endif
 
- // transfer all processed frames to the output buf
 
- static void _write_samples(void) {
 
- 	frames_t frames = process.out_frames;
 
- 	ISAMPLE_T *iptr   = (ISAMPLE_T *) process.outbuf;
 
- 	unsigned cnt  = 10;
 
- 	LOCK_O;
 
- 	while (frames > 0) {
 
- 		frames_t f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
 
- 		ISAMPLE_T *optr = (ISAMPLE_T*) outputbuf->writep;
 
- 		if (f > 0) {
 
- 			f = min(f, frames);
 
- 			
 
- 			memcpy(optr, iptr, f * BYTES_PER_FRAME);
 
- 			
 
- 			frames -= f;
 
- 			
 
- 			_buf_inc_writep(outputbuf, f * BYTES_PER_FRAME);
 
- 			iptr += f * BYTES_PER_FRAME / sizeof(*iptr);
 
- 		} else if (cnt--) {
 
- 			// there should normally be space in the output buffer, but may need to wait during drain phase
 
- 			UNLOCK_O;
 
- 			usleep(10000);
 
- 			LOCK_O;
 
- 		} else {
 
- 			// bail out if no space found after 100ms to avoid locking
 
- 			LOG_ERROR("unable to get space in output buffer");
 
- 			UNLOCK_O;
 
- 			return;
 
- 		}
 
- 	}
 
- 	UNLOCK_O;
 
- }
 
- // process samples - called with decode mutex set
 
- void process_samples(void) {
 
- 	SAMPLES_FUNC(&process);
 
- 	_write_samples();
 
- 	process.in_frames = 0;
 
- }
 
- // drain at end of track - called with decode mutex set
 
- void process_drain(void) {
 
- 	bool done;
 
- 	do {
 
- 		done = DRAIN_FUNC(&process);
 
- 		_write_samples();
 
- 	} while (!done);
 
- 	LOG_DEBUG("processing track complete - frames in: %lu out: %lu", process.total_in, process.total_out);
 
- }	
 
- // new stream - called with decode mutex set
 
- unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned supported_rates[]) {
 
- 	bool active = NEWSTREAM_FUNC(&process, raw_sample_rate, supported_rates);
 
- 	LOG_INFO("processing: %s", active ? "active" : "inactive");
 
- 	*direct = !active;
 
- 	if (active) {
 
- 		unsigned max_in_frames, max_out_frames;
 
- 		process.in_frames = process.out_frames = 0;
 
- 		process.total_in = process.total_out = 0;
 
- 		max_in_frames = codec->min_space / BYTES_PER_FRAME ;
 
- 		// increase size of output buffer by 10% as output rate is not an exact multiple of input rate
 
- 		if (process.out_sample_rate % process.in_sample_rate == 0) {
 
- 			max_out_frames = max_in_frames * (process.out_sample_rate / process.in_sample_rate);
 
- 		} else {
 
- 			max_out_frames = (int)(1.1 * (float)max_in_frames * (float)process.out_sample_rate / (float)process.in_sample_rate);
 
- 		}
 
- 		if (process.max_in_frames != max_in_frames) {
 
- 			LOG_DEBUG("creating process buf in frames: %u", max_in_frames);
 
- 			if (process.inbuf) free(process.inbuf);
 
- 			process.inbuf = malloc(max_in_frames * BYTES_PER_FRAME);
 
- 			process.max_in_frames = max_in_frames;
 
- 		}
 
- 		
 
- 		if (process.max_out_frames != max_out_frames) {
 
- 			LOG_DEBUG("creating process buf out frames: %u", max_out_frames);
 
- 			if (process.outbuf) free(process.outbuf);
 
- 			process.outbuf = malloc(max_out_frames * BYTES_PER_FRAME);
 
- 			process.max_out_frames = max_out_frames;
 
- 		}
 
- 		
 
- 		if (!process.inbuf || !process.outbuf) {
 
- 			LOG_ERROR("malloc fail creating process buffers");
 
- 			*direct = true;
 
- 			return raw_sample_rate;
 
- 		}
 
- 		
 
- 		return process.out_sample_rate;
 
- 	}
 
- 	return raw_sample_rate;
 
- }
 
- // process flush - called with decode mutex set
 
- void process_flush(void) {
 
- 	LOG_INFO("process flush");
 
- 	FLUSH_FUNC();
 
- 	process.in_frames = 0;
 
- }
 
- // init - called with no mutex
 
- void process_init(char *opt) {
 
- 	bool enabled = INIT_FUNC(opt);
 
- 	memset(&process, 0, sizeof(process));
 
- 	if (enabled) {
 
- 		LOCK_D;
 
- 		decode.process = true;
 
- 		UNLOCK_D;
 
- 	}
 
- }
 
- #endif // #if PROCESS
 
 
  |