|  | @@ -5,15 +5,17 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define DECLARE_ALL_MIN_MAX \
 | 
	
		
			
				|  |  | -	DECLARE_MIN_MAX(req); \
 | 
	
		
			
				|  |  | -	DECLARE_MIN_MAX(rec); \
 | 
	
		
			
				|  |  | -	DECLARE_MIN_MAX(over); \
 | 
	
		
			
				|  |  |  	DECLARE_MIN_MAX(o); \
 | 
	
		
			
				|  |  |  	DECLARE_MIN_MAX(s); \
 | 
	
		
			
				|  |  |  	DECLARE_MIN_MAX(loci2sbuf); \
 | 
	
		
			
				|  |  | -	DECLARE_MIN_MAX(buffering); \
 | 
	
		
			
				|  |  | +	DECLARE_MIN_MAX(req); \
 | 
	
		
			
				|  |  | +	DECLARE_MIN_MAX(rec); \
 | 
	
		
			
				|  |  | +	DECLARE_MIN_MAX(over); \
 | 
	
		
			
				|  |  | +	DECLARE_MIN_MAX(i2savailable);\
 | 
	
		
			
				|  |  |  	DECLARE_MIN_MAX(i2s_time); \
 | 
	
		
			
				|  |  | -	DECLARE_MIN_MAX(i2savailable);
 | 
	
		
			
				|  |  | +	DECLARE_MIN_MAX(buffering);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #define RESET_ALL_MIN_MAX \
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(o); \
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(s); \
 | 
	
	
		
			
				|  | @@ -21,9 +23,10 @@
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(req);  \
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(rec);  \
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(over);  \
 | 
	
		
			
				|  |  | -	RESET_MIN_MAX(over);  \
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(i2savailable);\
 | 
	
		
			
				|  |  | -	RESET_MIN_MAX(i2s_time);
 | 
	
		
			
				|  |  | +	RESET_MIN_MAX(i2s_time);\
 | 
	
		
			
				|  |  | +	RESET_MIN_MAX(buffering);
 | 
	
		
			
				|  |  | +#define STATS_PERIOD_MS 5000
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Prevent compile errors if dac output is
 | 
	
		
			
				|  |  |  // included in the build and not actually activated in menuconfig
 | 
	
	
		
			
				|  | @@ -138,8 +141,10 @@ void output_init_dac(log_level level, char *device, unsigned output_buf_size, ch
 | 
	
		
			
				|  |  |  	i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;           //2-channels
 | 
	
		
			
				|  |  |  	i2s_config.communication_format = I2S_COMM_FORMAT_I2S| I2S_COMM_FORMAT_I2S_MSB;
 | 
	
		
			
				|  |  |  	// todo: tune this parameter. Expressed in number of samples. Byte size depends on bit depth.
 | 
	
		
			
				|  |  | -	i2s_config.dma_buf_count = 64; //todo: tune this parameter. Expressed in numbrer of buffers.
 | 
	
		
			
				|  |  | -	i2s_config.dma_buf_len =  128;
 | 
	
		
			
				|  |  | +	i2s_config.dma_buf_count = 10;
 | 
	
		
			
				|  |  | +	// From the I2S driver source, the DMA buffer size is 4092 bytes.
 | 
	
		
			
				|  |  | +	// so buf_len * 2 channels * 2 bytes/sample should be < 4092 or else it will be resized.
 | 
	
		
			
				|  |  | +	i2s_config.dma_buf_len =  FRAME_BLOCK/2;
 | 
	
		
			
				|  |  |  	i2s_config.use_apll = false;
 | 
	
		
			
				|  |  |  	i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -154,7 +159,7 @@ void output_init_dac(log_level level, char *device, unsigned output_buf_size, ch
 | 
	
		
			
				|  |  |  	isI2SStarted=false;
 | 
	
		
			
				|  |  |  	i2s_stop(CONFIG_I2S_NUM);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	dac_buffer_size = 10*FRAME_BLOCK*get_bytes_per_frame(output.format);
 | 
	
		
			
				|  |  | +	dac_buffer_size = 5*FRAME_BLOCK*get_bytes_per_frame(output.format);
 | 
	
		
			
				|  |  |  	LOG_DEBUG("Allocating local DAC transfer buffer of %u bytes.",dac_buffer_size);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	buf_init(dacbuffer,dac_buffer_size );
 | 
	
	
		
			
				|  | @@ -257,9 +262,11 @@ static void *output_thread_dac() {
 | 
	
		
			
				|  |  |  	frames_t frames=0;
 | 
	
		
			
				|  |  |  	frames_t available_frames_space=0;
 | 
	
		
			
				|  |  |  	size_t bytes_to_send_i2s=0, // Contiguous buffer which can be addressed
 | 
	
		
			
				|  |  | -		 i2s_bytes_written = 0; //actual size that the i2s port was able to write
 | 
	
		
			
				|  |  | +		 i2s_bytes_written = 0,
 | 
	
		
			
				|  |  | +		 i2s_total_bytes_written=0; //actual size that the i2s port was able to write
 | 
	
		
			
				|  |  |  	uint32_t timer_start=0;
 | 
	
		
			
				|  |  |  	static int count = 0;
 | 
	
		
			
				|  |  | +	output_state state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	DECLARE_ALL_MIN_MAX;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -270,8 +277,8 @@ static void *output_thread_dac() {
 | 
	
		
			
				|  |  |  		bytes_to_send_i2s=0, // Contiguous buffer which can be addressed
 | 
	
		
			
				|  |  |  		i2s_bytes_written = 0; //actual size that the i2s port was able to write
 | 
	
		
			
				|  |  |  		TIME_MEASUREMENT_START(timer_start);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  		LOCK;
 | 
	
		
			
				|  |  | +		state =output.state;
 | 
	
		
			
				|  |  |  		if (output.state == OUTPUT_OFF) {
 | 
	
		
			
				|  |  |  			UNLOCK;
 | 
	
		
			
				|  |  |  			LOG_INFO("Output state is off.");
 | 
	
	
		
			
				|  | @@ -284,22 +291,34 @@ static void *output_thread_dac() {
 | 
	
		
			
				|  |  |  			continue;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(dacbuffer),_buf_cont_read(dacbuffer));
 | 
	
		
			
				|  |  | -		available_frames_space = min(BYTES_TO_FRAME(min(_buf_space(dacbuffer), _buf_cont_write(dacbuffer))),FRAME_BLOCK);
 | 
	
		
			
				|  |  | -		frames = _output_frames( available_frames_space ); // Keep the transfer buffer full
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		do{
 | 
	
		
			
				|  |  | +			// fill our buffer
 | 
	
		
			
				|  |  | +			available_frames_space = BYTES_TO_FRAME(min(_buf_space(dacbuffer), _buf_cont_write(dacbuffer)));
 | 
	
		
			
				|  |  | +			if(available_frames_space)
 | 
	
		
			
				|  |  | +			{
 | 
	
		
			
				|  |  | +				frames = _output_frames( available_frames_space ); // Keep the transfer buffer full
 | 
	
		
			
				|  |  | +				SET_MIN_MAX( available_frames_space,req);
 | 
	
		
			
				|  |  | +				SET_MIN_MAX(frames,rec);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		}while(available_frames_space>0 && frames>0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size);
 | 
	
		
			
				|  |  | +		SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size);
 | 
	
		
			
				|  |  |  		UNLOCK;
 | 
	
		
			
				|  |  |  		LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(dacbuffer),_buf_cont_read(dacbuffer));
 | 
	
		
			
				|  |  | -		SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering);
 | 
	
		
			
				|  |  | -		SET_MIN_MAX( available_frames_space,req);
 | 
	
		
			
				|  |  | -		SET_MIN_MAX(frames,rec);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +		SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		SET_MIN_MAX_SIZED(_buf_used(dacbuffer),loci2sbuf,dacbuffer->size);
 | 
	
		
			
				|  |  |  		bytes_to_send_i2s = _buf_cont_read(dacbuffer);
 | 
	
		
			
				|  |  |  		SET_MIN_MAX(bytes_to_send_i2s,i2savailable);
 | 
	
		
			
				|  |  |  		int pass=0;
 | 
	
		
			
				|  |  | -		while (bytes_to_send_i2s>0 && pass++ < 1 )
 | 
	
		
			
				|  |  | +		i2s_total_bytes_written=0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		while (bytes_to_send_i2s>0 )
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  | -			// now pass twice
 | 
	
		
			
				|  |  | +			// now send all the data
 | 
	
		
			
				|  |  |  			TIME_MEASUREMENT_START(timer_start);
 | 
	
		
			
				|  |  |  			if(!isI2SStarted)
 | 
	
		
			
				|  |  |  			{
 | 
	
	
		
			
				|  | @@ -325,70 +344,59 @@ static void *output_thread_dac() {
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			LOG_SDEBUG("DONE Outputting to I2S. Wrote: %d bytes out of %d", i2s_bytes_written,bytes_to_send_i2s);
 | 
	
		
			
				|  |  |  			LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(dacbuffer),_buf_cont_read(dacbuffer));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			output.device_frames =0;
 | 
	
		
			
				|  |  | -			output.updated = gettime_ms();
 | 
	
		
			
				|  |  | -			output.frames_played_dmp = output.frames_played;
 | 
	
		
			
				|  |  | +			i2s_total_bytes_written+=i2s_bytes_written;
 | 
	
		
			
				|  |  |  			SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),i2s_time);
 | 
	
		
			
				|  |  | +			if(bytes_to_send_i2s>0) {
 | 
	
		
			
				|  |  | +				SET_MIN_MAX(bytes_to_send_i2s-i2s_bytes_written,over);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  			bytes_to_send_i2s = _buf_cont_read(dacbuffer);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -//		if(frames>0){
 | 
	
		
			
				|  |  | -//				//LOG_DEBUG("Frames available : %u.",frames);
 | 
	
		
			
				|  |  | -//		}
 | 
	
		
			
				|  |  | -//		else
 | 
	
		
			
				|  |  | -//		{
 | 
	
		
			
				|  |  | -//			//LOG_DEBUG("No frame available");
 | 
	
		
			
				|  |  | -//			usleep(10000);
 | 
	
		
			
				|  |  | -//		}
 | 
	
		
			
				|  |  | -		SET_MIN_MAX(bytes_to_send_i2s-i2s_bytes_written,over);
 | 
	
		
			
				|  |  | -		SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size);
 | 
	
		
			
				|  |  | -		SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size);
 | 
	
		
			
				|  |  | +			SET_MIN_MAX(bytes_to_send_i2s,i2savailable);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		/*
 | 
	
		
			
				|  |  | -		 * Statistics reporting
 | 
	
		
			
				|  |  | -		 */
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		output.device_frames =0;
 | 
	
		
			
				|  |  | +		output.updated = gettime_ms();
 | 
	
		
			
				|  |  | +		output.frames_played_dmp = output.frames_played;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		//wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		/*
 | 
	
		
			
				|  |  |  		 * Statistics reporting
 | 
	
		
			
				|  |  |  		 */
 | 
	
		
			
				|  |  | -#define STATS_PERIOD_MS 5000
 | 
	
		
			
				|  |  |  		count++;
 | 
	
		
			
				|  |  |  		TIMED_SECTION_START_MS(STATS_PERIOD_MS);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		LOG_INFO( "count:%d, current sample rate: %d, bytes per frame: %d, avg cycle duration (ms): %d",count,output.current_sample_rate, out_bytes_per_frame,STATS_PERIOD_MS/count);
 | 
	
		
			
				|  |  | -		LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD1);
 | 
	
		
			
				|  |  | -		LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD2);
 | 
	
		
			
				|  |  | -		LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD3);
 | 
	
		
			
				|  |  | -		LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD4);
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local free",loci2sbuf));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT_FOOTER);
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("i2swrite",i2savailable));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("overflow",over));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_FORMAT_FOOTER);
 | 
	
		
			
				|  |  | -		LOG_INFO("");
 | 
	
		
			
				|  |  | -		LOG_INFO("              ----------+----------+-----------+-----------+  ");
 | 
	
		
			
				|  |  | -		LOG_INFO("              max (us)  | min (us) |   avg(us) |  count    |  ");
 | 
	
		
			
				|  |  | -		LOG_INFO("              ----------+----------+-----------+-----------+  ");
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
 | 
	
		
			
				|  |  | -		LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("i2s tfr(us)",i2s_time));
 | 
	
		
			
				|  |  | -		LOG_INFO("              ----------+----------+-----------+-----------+");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		RESET_ALL_MIN_MAX;
 | 
	
		
			
				|  |  | +		if(state>OUTPUT_STOPPED){
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			LOG_INFO( "count:%d, Output State: %d, current sample rate: %d, bytes per frame: %d, avg cycle duration (ms): %d",count,state,output.current_sample_rate, out_bytes_per_frame,STATS_PERIOD_MS/count);
 | 
	
		
			
				|  |  | +			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD1);
 | 
	
		
			
				|  |  | +			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD2);
 | 
	
		
			
				|  |  | +			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD3);
 | 
	
		
			
				|  |  | +			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD4);
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("dac buf used",loci2sbuf));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT_FOOTER);
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("i2swrite",i2savailable));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("overflow",over));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_FORMAT_FOOTER);
 | 
	
		
			
				|  |  | +			LOG_INFO("");
 | 
	
		
			
				|  |  | +			LOG_INFO("              ----------+----------+-----------+-----------+  ");
 | 
	
		
			
				|  |  | +			LOG_INFO("              max (us)  | min (us) |   avg(us) |  count    |  ");
 | 
	
		
			
				|  |  | +			LOG_INFO("              ----------+----------+-----------+-----------+  ");
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
 | 
	
		
			
				|  |  | +			LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("i2s tfr(us)",i2s_time));
 | 
	
		
			
				|  |  | +			LOG_INFO("              ----------+----------+-----------+-----------+");
 | 
	
		
			
				|  |  | +			RESET_ALL_MIN_MAX;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else {
 | 
	
		
			
				|  |  | +			LOG_INFO( "count:%d, Output State: %d",count,state);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  		count=0;
 | 
	
		
			
				|  |  |  		TIMED_SECTION_END;
 | 
	
		
			
				|  |  |  		/*
 | 
	
		
			
				|  |  |  		 * End Statistics reporting
 | 
	
		
			
				|  |  |  		 */
 | 
	
		
			
				|  |  | -//		wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written),75);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return 0;
 | 
	
		
			
				|  |  |  }
 |