浏览代码

Initial commit

faad does not work yet
philippe44 5 年之前
父节点
当前提交
66b2f74ebe
共有 11 个文件被更改,包括 224 次插入122 次删除
  1. 26 15
      main/alac.c
  2. 1 1
      main/component.mk
  3. 23 6
      main/faad.c
  4. 25 13
      main/flac.c
  5. 10 7
      main/mad.c
  6. 1 1
      main/output.c
  7. 62 12
      main/pcm.c
  8. 9 1
      main/squeezelite.h
  9. 15 6
      main/vorbis.c
  10. 45 60
      output_bt.c
  11. 7 0
      sdkconfig.defaults

+ 26 - 15
main/alac.c

@@ -23,6 +23,18 @@
 
 #include <alac_wrapper.h>
 
+#if BYTES_PER_FRAME == 4		
+#define ALIGN8(n) 	(n << 8)		
+#define ALIGN16(n) 	(n)
+#define ALIGN24(n)	(n >> 8) 
+#define ALIGN32(n)	(n >> 16)
+#else
+#define ALIGN8(n) 	(n << 24)		
+#define ALIGN16(n) 	(n << 16)
+#define ALIGN24(n)	(n << 8) 
+#define ALIGN32(n)	(n)
+#endif
+
 #define BLOCK_SIZE (4096 * BYTES_PER_FRAME)
 #define MIN_READ    BLOCK_SIZE
 #define MIN_SPACE  (MIN_READ * 4)
@@ -433,15 +445,15 @@ static decode_state alac_decode(void) {
 
 	while (frames > 0) {
 		size_t f, count;
-		s32_t *optr;
+		ISAMPLE_T *optr;
 
 		IF_DIRECT(
 			f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
-			optr = (s32_t *)outputbuf->writep;
+			optr = (ISAMPLE_T *)outputbuf->writep;
 		);
 		IF_PROCESS(
 			f = min(frames, process.max_in_frames - process.in_frames);
-			optr = (s32_t *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
+			optr = (ISAMPLE_T *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
 		);
 
 		f = min(f, frames);
@@ -449,32 +461,31 @@ static decode_state alac_decode(void) {
 
 		if (l->sample_size == 8) {
 			while (count--) {
-				*optr++ = (*(u32_t*) iptr) << 24;
-				*optr++ = (*(u32_t*) (iptr + 1)) << 24;
-				iptr += 2;
+				*optr++ = ALIGN8(*iptr++);
+				*optr++ = ALIGN8(*iptr++);
 			}
 		} else if (l->sample_size == 16) {
+			u16_t *_iptr = (u16_t*) iptr;
 			while (count--) {
-				*optr++ = (*(u32_t*) iptr) << 16;
-				*optr++ = (*(u32_t*) (iptr + 2)) << 16;
-				iptr += 4;
+				*optr++ = ALIGN16(*_iptr++);
+				*optr++ = ALIGN16(*_iptr++);
 			}
 		} else if (l->sample_size == 24) {
 			while (count--) {
-				*optr++ = (*(u32_t*) iptr) << 8;
-				*optr++ = (*(u32_t*) (iptr + 3)) << 8;
+				*optr++ = ALIGN24(*(u32_t*) iptr);
+				*optr++ = ALIGN24(*(u32_t*) (iptr + 3));
 				iptr += 6;
 			}
 		} else if (l->sample_size == 32) {
+			u32_t *_iptr = (u32_t*) iptr;
 			while (count--) {
-				*optr++ = (*(u32_t*) iptr);
-				*optr++ = (*(u32_t*) (iptr + 4));
-				iptr += 8;
+				*optr++ = ALIGN32(*_iptr++);
+				*optr++ = ALIGN32(*_iptr++);
 			}
 		} else {
 			LOG_ERROR("unsupported bits per sample: %u", l->sample_size);
 		}
-
+		
 		frames -= f;
 
 		IF_DIRECT(

+ 1 - 1
main/component.mk

@@ -2,7 +2,7 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
-CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY		\
+CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY	-DBYTES_PER_FRAME=4	\
 	-I$(COMPONENT_PATH)/../components/codecs/inc		\
 	-I$(COMPONENT_PATH)/../components/codecs/inc/mad 	\
 	-I$(COMPONENT_PATH)/../components/codecs/inc/faad2	\

+ 23 - 6
main/faad.c

@@ -23,6 +23,12 @@
 
 #include <neaacdec.h>
 
+#if BYTES_PER_FRAME == 4		
+#define ALIGN(n) 	(n)
+#else
+#define ALIGN(n) 	(n << 8)		
+#endif
+
 #define WRAPBUF_LEN 2048
 
 struct chunk_table {
@@ -315,7 +321,7 @@ static decode_state faad_decode(void) {
 	size_t bytes_total;
 	size_t bytes_wrap;
 	static NeAACDecFrameInfo info;
-	s32_t *iptr;
+	ISAMPLE_T *iptr;
 	bool endstream;
 	frames_t frames;
 
@@ -491,29 +497,35 @@ static decode_state faad_decode(void) {
 	while (frames > 0) {
 		frames_t f;
 		frames_t count;
-		s32_t *optr;
+		ISAMPLE_T *optr;
 
 		IF_DIRECT(
 			f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME;
-			optr = (s32_t *)outputbuf->writep;
+			optr = (ISAMPLE_T *)outputbuf->writep;
 		);
 		IF_PROCESS(
 			f = process.max_in_frames;
-			optr = (s32_t *)process.inbuf;
+			optr = (ISAMPLE_T *)process.inbuf;
 		);
 
 		f = min(f, frames);
 		count = f;
 		
 		if (info.channels == 2) {
+#if BYTES_PER_FRAME == 4			
+			memcpy(optr, iptr, count * BYTES_PER_FRAME);
+			iptr += count * 2;
+			optr += count * 2;
+#else 			
 			while (count--) {
 				*optr++ = *iptr++ << 8;
 				*optr++ = *iptr++ << 8;
 			}
+#endif			
 		} else if (info.channels == 1) {
 			while (count--) {
-				*optr++ = *iptr << 8;
-				*optr++ = *iptr++ << 8;
+				*optr++ = ALIGN(*iptr);
+				*optr++ = ALIGN(*iptr++);
 			}
 		} else {
 			LOG_WARN("unsupported number of channels");
@@ -563,7 +575,12 @@ static void faad_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
 
 	conf = NEAAC(a, GetCurrentConfiguration, a->hAac);
 
+#if BYTES_PER_FRAME == 4
+	conf->outputFormat = FAAD_FMT_16BIT;
+#else
 	conf->outputFormat = FAAD_FMT_24BIT;
+#endif
+    conf->defSampleRate = 44100;
 	conf->downMatrix = 1;
 
 	if (!NEAAC(a, SetConfiguration, a->hAac, conf)) {

+ 25 - 13
main/flac.c

@@ -22,6 +22,18 @@
 
 #include <FLAC/stream_decoder.h>
 
+#if BYTES_PER_FRAME == 4		
+#define ALIGN8(n) 	(n << 8)		
+#define ALIGN16(n) 	(n)
+#define ALIGN24(n)	(n >> 8) 
+#define ALIGN32(n)	(n >> 16)
+#else
+#define ALIGN8(n) 	(n << 24)		
+#define ALIGN16(n) 	(n << 16)
+#define ALIGN24(n)	(n << 8) 
+#define ALIGN32(n)	(n)
+#endif
+
 struct flac {
 	FLAC__StreamDecoder *decoder;
 #if !LINKALL
@@ -149,45 +161,45 @@ static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decode
 	while (frames > 0) {
 		frames_t f;
 		frames_t count;
-		s32_t *optr;
+		ISAMPLE_T *optr;
 
 		IF_DIRECT( 
-			optr = (s32_t *)outputbuf->writep; 
+			optr = (ISAMPLE_T *)outputbuf->writep; 
 			f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; 
 		);
 		IF_PROCESS(
-			optr = (s32_t *)process.inbuf;
+			optr = (ISAMPLE_T *)process.inbuf;
 			f = process.max_in_frames;
 		);
 
 		f = min(f, frames);
 
 		count = f;
-
+				
 		if (bits_per_sample == 8) {
 			while (count--) {
-				*optr++ = *lptr++ << 24;
-				*optr++ = *rptr++ << 24;
+				*optr++ = ALIGN8(*lptr++);
+				*optr++ = ALIGN8(*rptr++);
 			}
 		} else if (bits_per_sample == 16) {
 			while (count--) {
-				*optr++ = *lptr++ << 16;
-				*optr++ = *rptr++ << 16;
+				*optr++ = ALIGN16(*lptr++);
+				*optr++ = ALIGN16(*rptr++);
 			}
 		} else if (bits_per_sample == 24) {
 			while (count--) {
-				*optr++ = *lptr++ << 8;
-				*optr++ = *rptr++ << 8;
+				*optr++ = ALIGN24(*lptr++);
+				*optr++ = ALIGN24(*rptr++);
 			}
 		} else if (bits_per_sample == 32) {
 			while (count--) {
-				*optr++ = *lptr++;
-				*optr++ = *rptr++;
+				*optr++ = ALIGN32(*lptr++);
+				*optr++ = ALIGN32(*rptr++);
 			}
 		} else {
 			LOG_ERROR("unsupported bits per sample: %u", bits_per_sample);
 		}
-
+				
 		frames -= f;
 
 		IF_DIRECT(

+ 10 - 7
main/mad.c

@@ -88,15 +88,18 @@ extern struct processstate process;
 #endif
 
 // based on libmad minimad.c scale
-static inline u32_t scale(mad_fixed_t sample) {
+static inline ISAMPLE_T scale(mad_fixed_t sample) {
 	sample += (1L << (MAD_F_FRACBITS - 24));
 	
 	if (sample >= MAD_F_ONE)
 		sample = MAD_F_ONE - 1;
 	else if (sample < -MAD_F_ONE)
 		sample = -MAD_F_ONE;
-	
-	return (s32_t)(sample >> (MAD_F_FRACBITS + 1 - 24)) << 8;
+#if BYTES_PER_FRAME == 4	
+	return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) >> 8);
+#else	
+	return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) << 8);
+#endif	
 }
 
 // check for id3.2 tag at start of file - http://id3.org/id3v2.4.0-structure, return length
@@ -300,15 +303,15 @@ static decode_state mad_decode(void) {
 
 		while (frames > 0) {
 			size_t f, count;
-			s32_t *optr;
+			ISAMPLE_T *optr;
 
 			IF_DIRECT(
 				f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
-				optr = (s32_t *)outputbuf->writep;
+				optr = (ISAMPLE_T *)outputbuf->writep;
 			);
 			IF_PROCESS(
 				f = min(frames, process.max_in_frames - process.in_frames);
-				optr = (s32_t *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
+				optr = (ISAMPLE_T *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
 			);
 
 			count = f;
@@ -317,7 +320,7 @@ static decode_state mad_decode(void) {
 				*optr++ = scale(*iptrl++);
 				*optr++ = scale(*iptrr++);
 			}
-
+			
 			frames -= f;
 
 			IF_DIRECT(

+ 1 - 1
main/output.c

@@ -59,7 +59,7 @@ frames_t _output_frames(frames_t avail) {
 	silence = false;
 
 	// start when threshold met
-	if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 && frames > output.start_frames) {
+	if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 10 && frames > output.start_frames) {
 		output.state = OUTPUT_RUNNING;
 		LOG_INFO("start buffer frames: %u", frames);
 		wake_controller();

+ 62 - 12
main/pcm.c

@@ -21,6 +21,14 @@
 
 #include "squeezelite.h"
 
+#if BYTES_PER_FRAME == 4
+#define SHIFT 16
+#define OPTR_T	u16_t
+#else
+#define OPTR_T	u32_t	
+#define SHIFT 0
+#endif
+
 extern log_level loglevel;
 
 extern struct buffer *streambuf;
@@ -175,9 +183,9 @@ static void _check_header(void) {
 static decode_state pcm_decode(void) {
 	unsigned bytes, in, out;
 	frames_t frames, count;
-	u32_t *optr;
+	OPTR_T *optr;
 	u8_t  *iptr;
-	u8_t tmp[16];
+	u8_t tmp[3*8];
 	
 	LOCK_S;
 
@@ -236,10 +244,10 @@ static decode_state pcm_decode(void) {
 	}
 
 	IF_DIRECT(
-		optr = (u32_t *)outputbuf->writep;
+		optr = (OPTR_T *)outputbuf->writep;
 	);
 	IF_PROCESS(
-		optr = (u32_t *)process.inbuf;
+		optr = (OPTR_T *)process.inbuf;
 	);
 	iptr = (u8_t *)streambuf->readp;
 
@@ -261,47 +269,73 @@ static decode_state pcm_decode(void) {
 		LOG_INFO("reached end of audio");
 		frames = audio_left / bytes_per_frame;
 	}
-
+	
 	count = frames * channels;
 
 	if (channels == 2) {
 		if (sample_size == 1) {
 			while (count--) {
-				*optr++ = *iptr++ << 24;
+				*optr++ = *iptr++ << (24-SHIFT);
 			}
 		} else if (sample_size == 2) {
 			if (bigendian) {
+#if BYTES_PER_FRAME == 4 && !SL_LITTLE_ENDIAN			
+				// while loop below works as is, but memcpy is a win for that 16/16 typical case
+				memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
+#else				
 				while (count--) {
-					*optr++ = *(iptr) << 24 | *(iptr+1) << 16;
+					*optr++ = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
 					iptr += 2;
 				}
+#endif				
 			} else {
+#if BYTES_PER_FRAME == 4 && SL_LITTLE_ENDIAN			
+				// while loop below works as is, but memcpy is a win for that 16/16 typical case
+				memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
+#else
 				while (count--) {
-					*optr++ = *(iptr) << 16 | *(iptr+1) << 24;
+					*optr++ = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
 					iptr += 2;
 				}
+#endif	
 			}
 		} else if (sample_size == 3) {
 			if (bigendian) {
 				while (count--) {
+#if BYTES_PER_FRAME == 4				
+					*optr++ = *(iptr) << 8 | *(iptr+1);
+#else					
 					*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
+#endif	
 					iptr += 3;
 				}
 			} else {
 				while (count--) {
+#if BYTES_PER_FRAME == 4									
+					*optr++ = *(iptr+1) | *(iptr+2) << 8;
+#else
 					*optr++ = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
+#endif	
 					iptr += 3;
 				}
 			}
 		} else if (sample_size == 4) {
 			if (bigendian) {
 				while (count--) {
+#if BYTES_PER_FRAME == 4														
+					*optr++ = *(iptr) << 8 | *(iptr+1);
+#else
 					*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
+#endif	
 					iptr += 4;
 				}
 			} else {
 				while (count--) {
+#if BYTES_PER_FRAME == 4																			
+					*optr++ = *(iptr+2) | *(iptr+3) << 8;
+#else
 					*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
+#endif	
 					iptr += 4;
 				}
 			}
@@ -309,21 +343,21 @@ static decode_state pcm_decode(void) {
 	} else if (channels == 1) {
 		if (sample_size == 1) {
 			while (count--) {
-				*optr = *iptr++ << 24;
+				*optr = *iptr++ << (24-SHIFT);
 				*(optr+1) = *optr;
 				optr += 2;
 			}
 		} else if (sample_size == 2) {
 			if (bigendian) {
 				while (count--) {
-					*optr = *(iptr) << 24 | *(iptr+1) << 16;
+					*optr = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
 					*(optr+1) = *optr;
 					iptr += 2;
 					optr += 2;
 				}
 			} else {
 				while (count--) {
-					*optr = *(iptr) << 16 | *(iptr+1) << 24;
+					*optr = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
 					*(optr+1) = *optr;
 					iptr += 2;
 					optr += 2;
@@ -332,14 +366,22 @@ static decode_state pcm_decode(void) {
 		} else if (sample_size == 3) {
 			if (bigendian) {
 				while (count--) {
+#if BYTES_PER_FRAME == 4				
+					*optr++ = *(iptr) << 8 | *(iptr+1);
+#else					
 					*optr = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
+#endif				
 					*(optr+1) = *optr;
 					iptr += 3;
 					optr += 2;
 				}
 			} else {
 				while (count--) {
+#if BYTES_PER_FRAME == 4														
+					*optr++ = *(iptr+1) | *(iptr+2) << 8;
+#else					
 					*optr = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
+#endif				
 					*(optr+1) = *optr;
 					iptr += 3;
 					optr += 2;
@@ -348,14 +390,22 @@ static decode_state pcm_decode(void) {
 		} else if (sample_size == 4) {
 			if (bigendian) {
 				while (count--) {
+#if BYTES_PER_FRAME == 4														
+					*optr++ = *(iptr) << 8 | *(iptr+1);
+#else					
 					*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
+#endif				
 					*(optr+1) = *optr;
 					iptr += 4;
 					optr += 2;
 				}
 			} else {
 				while (count--) {
+#if BYTES_PER_FRAME == 4																			
+					*optr++ = *(iptr+2) | *(iptr+3) << 8;
+#else					
 					*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
+#endif				
 					*(optr+1) = *optr;
 					iptr += 4;
 					optr += 2;
@@ -365,7 +415,7 @@ static decode_state pcm_decode(void) {
 	} else {
 		LOG_ERROR("unsupported channels");
 	}
-
+	
 	LOG_SDEBUG("decoded %u frames", frames);
 
 	_buf_inc_readp(streambuf, frames * bytes_per_frame);

+ 9 - 1
main/squeezelite.h

@@ -444,7 +444,15 @@ void _wake_create(event_event*);
 
 #define FIXED_ONE 0x10000
 
+#ifndef BYTES_PER_FRAME
 #define BYTES_PER_FRAME 8
+#endif
+
+#if BYTES_PER_FRAME == 8
+#define ISAMPLE_T 		s32_t
+#else
+#define ISAMPLE_T		s16_t
+#endif
 
 #define min(a,b) (((a) < (b)) ? (a) : (b))
 
@@ -643,7 +651,7 @@ struct outputstate {
 	unsigned latency;
 	int pa_hostapi_option;
 #endif
-	int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
+	int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
 	unsigned start_frames;
 	unsigned frames_played;
 	unsigned frames_played_dmp;// frames played at the point delay is measured

+ 15 - 6
main/vorbis.c

@@ -21,6 +21,12 @@
 
 #include "squeezelite.h"
 
+#if BYTES_PER_FRAME == 4		
+#define ALIGN(n) 	(n)
+#else
+#define ALIGN(n) 	(n << 16)		
+#endif
+
 // automatically select between floating point (preferred) and fixed point libraries:
 // NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu
 
@@ -207,26 +213,29 @@ static decode_state vorbis_decode(void) {
 
 		frames_t count;
 		s16_t *iptr;
-		s32_t *optr;
+		ISAMPLE_T *optr;
 
 		frames = n / 2 / channels;
 		count = frames * channels;
 
-		// work backward to unpack samples to 4 bytes per sample
 		iptr = (s16_t *)write_buf + count;
-		optr = (s32_t *)write_buf + frames * 2;
+		optr = (ISAMPLE_T *)write_buf + frames * 2;
 
 		if (channels == 2) {
+#if BYTES_PER_FRAME == 4			
+			memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
+#else
 			while (count--) {
 				*--optr = *--iptr << 16;
 			}
+#endif			
 		} else if (channels == 1) {
 			while (count--) {
-				*--optr = *--iptr << 16;
-				*--optr = *iptr   << 16;
+				*--optr = ALIGN(*--iptr);
+				*--optr = ALIGN(*iptr);
 			}
 		}
-
+		
 		IF_DIRECT(
 			_buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
 		);

+ 45 - 60
output_bt.c

@@ -29,6 +29,7 @@ static bool running = true;
 
 extern struct outputstate output;
 extern struct buffer *outputbuf;
+extern struct buffer *streambuf;
 
 #define LOCK   mutex_lock(outputbuf->mutex)
 #define UNLOCK mutex_unlock(outputbuf->mutex)
@@ -36,20 +37,19 @@ extern struct buffer *outputbuf;
 #define FRAME_BLOCK MAX_SILENCE_FRAMES
 
 extern u8_t *silencebuf;
+static u8_t *optr;
 
-// buffer to hold output data so we can block on writing outside of output lock, allocated on init
-static u8_t *buf;
-static unsigned buffill;
-static int bytes_per_frame;
-
-static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
-								s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
+static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
+								s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
 
 void set_volume(unsigned left, unsigned right) {
 	LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
 	LOCK;
 	output.gainL = left;
 	output.gainR = right;
+	// TODO
+	output.gainL = FIXED_ONE;
+	output.gainR = FIXED_ONE;
 	UNLOCK;
 }
 
@@ -127,26 +127,12 @@ void output_init_dac(log_level level, unsigned output_buf_size, char *params, un
 
 	LOG_INFO("init output BT");
 
-	buf = malloc(FRAME_BLOCK * BYTES_PER_FRAME);
-	if (!buf) {
-		LOG_ERROR("unable to malloc buf");
-		return;
-	}
-	buffill = 0;
-
 	memset(&output, 0, sizeof(output));
 
-	output.format = S32_LE;
 	output.start_frames = FRAME_BLOCK * 2;
-	output.write_cb = &_bt_write_frames;
+	output.write_cb = &_write_frames;
 	output.rate_delay = rate_delay;
 
-	if (params) {
-		if (!strcmp(params, "32"))	output.format = S32_LE;
-		if (!strcmp(params, "24")) output.format = S24_3LE;
-		if (!strcmp(params, "16")) output.format = S16_LE;
-	}
-
 	// ensure output rate is specified to avoid test open
 	if (!rates[0]) {
 		rates[0] = 44100;
@@ -226,32 +212,46 @@ void output_close_dac(void) {
 	running = false;
 	UNLOCK;
 
-	free(buf);
-
 	output_close_common();
 }
 
-static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
-								s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
-
-	u8_t *obuf;
-
+static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
+						 s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
+	
 	if (!silence) {
-
+		
+		/* TODO need 16 bit fix 
 		if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
 			_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
 		}
-
-		obuf = outputbuf->readp;
+		
+		if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
+			_apply_gain(outputbuf, out_frames, gainL, gainR);
+		}
+		*/
+
+#if BYTES_PER_FRAME == 4		
+		memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
+#else
+	{	
+		frames_t count = out_frames;
+		s32_t *_iptr = (s32_t*) outputbuf->readp;
+		s16_t *_optr = (s32_t*) optr;
+		while (count--) {
+			*_optr++ = *_iptr++ >> 16;
+			*_optr++ = *_iptr++ >> 16;
+		}
+	}	
+#endif	
 
 	} else {
 
-		obuf = silencebuf;
-	}
+		u8_t *buf = silencebuf;
 
-	_scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format);
-
-	buffill += out_frames;
+		memcpy(optr, buf, out_frames * 4);
+	}
+	
+	optr += out_frames * 4;
 
 	return (int)out_frames;
 }
@@ -495,18 +495,16 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
 static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
 {
 	frames_t frames;
-	int i;
-	s16_t *optr = (s16_t*) data;
-	s32_t *iptr = (s32_t*) buf;
+	static int count = 0;
 	
-    if (len < 0 || data == NULL) {
+	if (len < 0 || data == NULL) {
         return 0;
     }
     
    	LOCK;
 	
 /* TODO
-	Normally, we would want BT to not call us back unless we have not in BUFFERING state. 
+	Normally, we would want BT to not call us back unless we are not in BUFFERING state. 
 	That requires BT to not start until we are > OUTPUT_BUFFER
 	// come back later, we are buffering (or stopped, need to handle that case ...) but we don't want silence 
 	if (output.state <= OUTPUT_BUFFER) {
@@ -515,34 +513,21 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
 	}		
 */	
 
-   	switch (output.format) {
-   	case S32_LE:
-   		bytes_per_frame = 4 * 2; break;
-   	case S24_3LE:
-   		bytes_per_frame = 3 * 2; break;
-   	case S16_LE:
-   		bytes_per_frame = 2 * 2; break;
-   	default:
-   		bytes_per_frame = 4 * 2; break;
-   		break;
-   	}
-
-	// TODO update with proper bytes_per_frame handling
    	frames = len / 4;
    	output.device_frames = 0;
    	output.updated = gettime_ms();
    	output.frames_played_dmp = output.frames_played;
+	if (!output.threshold) output.threshold = 20;
+
+	optr = data;
   	frames = _output_frames(frames);
 	
 	UNLOCK;
 	
-	for (i = 0; i < frames*2; i++) {
-		*optr++ = *iptr++ >> 16;
-		*optr++ = *iptr++ >> 16;
+	if (!(count++ & 0x1ff)) {
+		LOG_INFO("frames %d (count:%d) (out:%d, stream:%d)", frames, count, _buf_used(outputbuf), _buf_used(streambuf));
 	}
 	
-	buffill = 0;
-   
 	return frames * 4;
 }
 

+ 7 - 0
sdkconfig.defaults

@@ -11,6 +11,7 @@ CONFIG_BT_SPP_ENABLED=n
 CONFIG_GATTS_ENABLE=n
 CONFIG_GATTC_ENABLE=n
 CONFIG_BLE_SMP_ENABLE=n
+SW_COEXIST_PREFERENCE_BALANCE=y
 #enable SPIRAM
 CONFIG_SPIRAM_SUPPORT=y
 CONFIG_SPIRAM_BOOT_INIT=y
@@ -31,3 +32,9 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
 CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
 CONFIG_PARTITION_TABLE_OFFSET=0x8000
 CONFIG_PARTITION_TABLE_MD5=y
+# CPU & threads options
+ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0=
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1=y
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=1