|  | @@ -77,6 +77,7 @@ sure that using rate_delay would fix that
 | 
	
		
			
				|  |  |  	RESET_MIN_MAX(buffering);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  #define STATS_PERIOD_MS 5000
 | 
	
		
			
				|  |  | +#define STAT_STACK_SIZE	(3*1024)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  extern struct outputstate output;
 | 
	
		
			
				|  |  |  extern struct buffer *streambuf;
 | 
	
	
		
			
				|  | @@ -92,18 +93,21 @@ static bool jack_mutes_amp;
 | 
	
		
			
				|  |  |  static bool running, isI2SStarted;
 | 
	
		
			
				|  |  |  static i2s_config_t i2s_config;
 | 
	
		
			
				|  |  |  static int bytes_per_frame;
 | 
	
		
			
				|  |  | -static thread_type thread, stats_thread;
 | 
	
		
			
				|  |  |  static u8_t *obuf;
 | 
	
		
			
				|  |  |  static frames_t oframes;
 | 
	
		
			
				|  |  |  static bool spdif;
 | 
	
		
			
				|  |  |  static size_t dma_buf_frames;
 | 
	
		
			
				|  |  | +static pthread_t thread;
 | 
	
		
			
				|  |  | +static TaskHandle_t stats_task;
 | 
	
		
			
				|  |  | +static bool stats;
 | 
	
		
			
				|  |  | +static int amp_gpio = -1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  DECLARE_ALL_MIN_MAX;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int _i2s_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);
 | 
	
		
			
				|  |  | -static void *output_thread_i2s();
 | 
	
		
			
				|  |  | -static void *output_thread_i2s_stats();
 | 
	
		
			
				|  |  | +static void *output_thread_i2s(void *arg);
 | 
	
		
			
				|  |  | +static void *output_thread_i2s_stats(void *arg);
 | 
	
		
			
				|  |  |  static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
 | 
	
		
			
				|  |  |  static void (*jack_handler_chain)(bool inserted);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -254,6 +258,16 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
 | 
	
		
			
				|  |  |  	if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false);
 | 
	
		
			
				|  |  |  	else adac->speaker(true);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  | +	p = config_alloc_get_default(NVS_TYPE_STR, "amp_GPIO", NULL, 0);
 | 
	
		
			
				|  |  | +	if (p) {
 | 
	
		
			
				|  |  | +		amp_gpio = atoi(p);
 | 
	
		
			
				|  |  | +		gpio_pad_select_gpio(amp_gpio);
 | 
	
		
			
				|  |  | +		gpio_set_direction(amp_gpio, GPIO_MODE_OUTPUT);
 | 
	
		
			
				|  |  | +		gpio_set_level(amp_gpio, 0);
 | 
	
		
			
				|  |  | +		LOG_INFO("setting amplifier GPIO %d", amp_gpio);
 | 
	
		
			
				|  |  | +		free(p);
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  |  	esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |      cfg.thread_name= "output_i2s";
 | 
	
	
		
			
				|  | @@ -263,11 +277,17 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
 | 
	
		
			
				|  |  |      esp_pthread_set_cfg(&cfg);
 | 
	
		
			
				|  |  |  	pthread_create(&thread, NULL, output_thread_i2s, NULL);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  | -	cfg.thread_name= "output_i2s_sts";
 | 
	
		
			
				|  |  | -	cfg.prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT - 1;
 | 
	
		
			
				|  |  | -    cfg.stack_size = 2048;	
 | 
	
		
			
				|  |  | -	esp_pthread_set_cfg(&cfg);
 | 
	
		
			
				|  |  | -	pthread_create(&stats_thread, NULL, output_thread_i2s_stats, NULL);
 | 
	
		
			
				|  |  | +	// do we want stats
 | 
	
		
			
				|  |  | +	p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
 | 
	
		
			
				|  |  | +	stats = p && (*p == '1' || *p == 'Y' || *p == 'y');
 | 
	
		
			
				|  |  | +	free(p);
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	// memory still used but at least task is not created
 | 
	
		
			
				|  |  | +	if (stats) {
 | 
	
		
			
				|  |  | +		static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
 | 
	
		
			
				|  |  | +		static EXT_RAM_ATTR StackType_t xStack[STAT_STACK_SIZE] __attribute__ ((aligned (4)));
 | 
	
		
			
				|  |  | +		stats_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s_stats, "output_i2s_sts", STAT_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -279,7 +299,7 @@ void output_close_i2s(void) {
 | 
	
		
			
				|  |  |  	running = false;
 | 
	
		
			
				|  |  |  	UNLOCK;
 | 
	
		
			
				|  |  |  	pthread_join(thread, NULL);
 | 
	
		
			
				|  |  | -	pthread_join(stats_thread, NULL);
 | 
	
		
			
				|  |  | +	if (stats) vTaskDelete(stats_task);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	i2s_driver_uninstall(CONFIG_I2S_NUM);
 | 
	
		
			
				|  |  |  	free(obuf);
 | 
	
	
		
			
				|  | @@ -345,7 +365,7 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  |   * Main output thread
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -static void *output_thread_i2s() {
 | 
	
		
			
				|  |  | +static void *output_thread_i2s(void *arg) {
 | 
	
		
			
				|  |  |  	size_t count = 0, bytes;
 | 
	
		
			
				|  |  |  	frames_t iframes = FRAME_BLOCK;
 | 
	
		
			
				|  |  |  	uint32_t timer_start = 0;
 | 
	
	
		
			
				|  | @@ -369,8 +389,11 @@ static void *output_thread_i2s() {
 | 
	
		
			
				|  |  |  		// manage led display & analogue
 | 
	
		
			
				|  |  |  		if (state != output.state) {
 | 
	
		
			
				|  |  |  			LOG_INFO("Output state is %d", output.state);
 | 
	
		
			
				|  |  | -			if (output.state == OUTPUT_OFF) led_blink(LED_GREEN, 100, 2500);
 | 
	
		
			
				|  |  | -			else if (output.state == OUTPUT_STOPPED) {
 | 
	
		
			
				|  |  | +			if (output.state == OUTPUT_OFF) {
 | 
	
		
			
				|  |  | +				led_blink(LED_GREEN, 100, 2500);
 | 
	
		
			
				|  |  | +				if (amp_gpio != -1) gpio_set_level(amp_gpio, 0);
 | 
	
		
			
				|  |  | +				LOG_INFO("switching off amp GPIO %d", amp_gpio);
 | 
	
		
			
				|  |  | +			} else if (output.state == OUTPUT_STOPPED) {
 | 
	
		
			
				|  |  |  				adac->speaker(false);
 | 
	
		
			
				|  |  |  				led_blink(LED_GREEN, 200, 1000);
 | 
	
		
			
				|  |  |  			} else if (output.state == OUTPUT_RUNNING) {
 | 
	
	
		
			
				|  | @@ -432,6 +455,7 @@ static void *output_thread_i2s() {
 | 
	
		
			
				|  |  |  			i2s_zero_dma_buffer(CONFIG_I2S_NUM);
 | 
	
		
			
				|  |  |  			i2s_start(CONFIG_I2S_NUM);
 | 
	
		
			
				|  |  |  			adac->power(ADAC_ON);	
 | 
	
		
			
				|  |  | +			if (amp_gpio != -1) gpio_set_level(amp_gpio, 1);
 | 
	
		
			
				|  |  |  		} 
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  		// this does not work well as set_sample_rates resets the fifos (and it's too early)
 | 
	
	
		
			
				|  | @@ -476,13 +500,12 @@ static void *output_thread_i2s() {
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  |   * Stats output thread
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -static void *output_thread_i2s_stats() {
 | 
	
		
			
				|  |  | -	//return;
 | 
	
		
			
				|  |  | -	while (running) {
 | 
	
		
			
				|  |  | -		LOCK;
 | 
	
		
			
				|  |  | +static void *output_thread_i2s_stats(void *arg) {
 | 
	
		
			
				|  |  | +	while (1) {
 | 
	
		
			
				|  |  | +		// no need to lock
 | 
	
		
			
				|  |  |  		output_state state = output.state;
 | 
	
		
			
				|  |  | -		UNLOCK;
 | 
	
		
			
				|  |  | -		if(state>OUTPUT_STOPPED){
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +		if(stats && state>OUTPUT_STOPPED){
 | 
	
		
			
				|  |  |  			LOG_INFO( "Output State: %d, current sample rate: %d, bytes per frame: %d",state,output.current_sample_rate, bytes_per_frame);
 | 
	
		
			
				|  |  |  			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD1);
 | 
	
		
			
				|  |  |  			LOG_INFO( LINE_MIN_MAX_FORMAT_HEAD2);
 | 
	
	
		
			
				|  | @@ -502,7 +525,7 @@ static void *output_thread_i2s_stats() {
 | 
	
		
			
				|  |  |  			LOG_INFO("              ----------+----------+-----------+-----------+");
 | 
	
		
			
				|  |  |  			RESET_ALL_MIN_MAX;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -		usleep(STATS_PERIOD_MS *1000);
 | 
	
		
			
				|  |  | +		vTaskDelay( pdMS_TO_TICKS( STATS_PERIOD_MS ) );
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return NULL;
 | 
	
		
			
				|  |  |  }
 |