Browse Source

refactor step 1 - BT

philippe44 5 years ago
parent
commit
6c5ce6ba80

+ 1 - 0
.gitignore

@@ -65,3 +65,4 @@ libs/
 
 /cdump.cmd
 /_codecs
+sdkconfig

+ 38 - 211
components/platform_esp32/platform_esp32.c → components/platform_esp32/bt_app_handler.c

@@ -1,54 +1,32 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
-#include "esp_log.h"
-#include "esp_system.h"
-#include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
+
+#include "esp_log.h"
 #include "esp_bt.h"
 #include "esp_bt_device.h"
 #include "esp_bt_main.h"
 #include "esp_gap_bt_api.h"
 #include "esp_a2dp_api.h"
-#include "esp_avrc_api.h"
 #include "esp_console.h"
 #include "esp_pthread.h"
 #include "esp_system.h"
 #include "esp_wifi.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/event_groups.h"
-#include "freertos/task.h"
 #include "freertos/timers.h"
-#include "nvs.h"
-#include "nvs_flash.h"
-#include "nvs_utilities.h"
-#include "pthread.h"
-#include "string.h"
-//#include "esp_event.h"
-#include "sys/socket.h"
-#include <signal.h>
-
-#include <signal.h>
-#include "platform_esp32.h"
-#include "../../main/squeezelite.h"
 #include "argtable3/argtable3.h"
 
-#define STATS_REPORT_DELAY_MS 15000
+#include "bt_app_core.h"
+
+#include "platform_esp32.h"
+
 static const char * TAG = "platform";
-extern char * get_output_state_desc(output_state state);
-
-extern struct outputstate output;
-extern struct buffer *outputbuf;
-extern struct buffer *streambuf;
-extern uint8_t * btout;
-time_t disconnect_time=0;
-#define LOCK_S   pthread_mutex_lock(&(streambuf->mutex))
-#define UNLOCK_S pthread_mutex_unlock(&(streambuf->mutex))
-
-#define LOCK   pthread_mutex_lock(&(outputbuf->mutex))
-#define UNLOCK pthread_mutex_unlock(&(outputbuf->mutex))
+
+extern int32_t 	output_bt_data(uint8_t *data, int32_t len);
+extern void 	output_bt_tick(void);
+extern char*	output_state_str(void);
+extern bool		output_stopped(void);
+
 int64_t connecting_timeout = 0;
 
 static const char *  art_a2dp_connected[]={"\n",
@@ -76,34 +54,8 @@ static void bt_app_av_state_connecting(uint16_t event, void *param);
 #define A2DP_TIMER_INIT connecting_timeout = esp_timer_get_time() +(CONFIG_A2DP_CONNECT_TIMEOUT_MS * 1000)
 #define IS_A2DP_TIMER_OVER esp_timer_get_time() >= connecting_timeout
 
-#define FRAME_TO_BYTES(f) f*BYTES_PER_FRAME
-#define BYTES_TO_FRAME(b) b/BYTES_PER_FRAME
-
-
-#define RESET_ALL_MIN_MAX RESET_MIN_MAX(req); RESET_MIN_MAX(rec); RESET_MIN_MAX(bt);RESET_MIN_MAX(under); RESET_MIN_MAX_DURATION(stream_buf); RESET_MIN_MAX_DURATION(lock_out_time)
-
-DECLARE_MIN_MAX(stream_buf);
-DECLARE_MIN_MAX(req);
-DECLARE_MIN_MAX(rec);
-DECLARE_MIN_MAX(bt);
-DECLARE_MIN_MAX(under);
-DECLARE_MIN_MAX_DURATION(lock_out_time);
-
 static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param);
 
-void get_mac(u8_t mac[]) {
-    esp_read_mac(mac, ESP_MAC_WIFI_STA);
-}
-
-_sig_func_ptr signal(int sig, _sig_func_ptr func) {
-	return NULL;
-}
-
-void *audio_calloc(size_t nmemb, size_t size) {
-		return calloc(nmemb, size);
-}
-
-
 /* event for handler "bt_av_hdl_stack_up */
 enum {
     BT_APP_EVT_STACK_UP = 0,
@@ -181,16 +133,12 @@ static struct {
 void hal_bluetooth_init(const char * options)
 {
 	ESP_LOGD(TAG,"Initializing Bluetooth HAL");
-	//CONFIG_A2DP_SINK_NAME
-	//CONFIG_A2DP_CONTROL_DELAY_MS
-	//CONFIG_A2DP_CONNECT_TIMEOUT_MS
 
 	squeezelite_args.sink_name = arg_str1("n", "name", "<sink name>", "the name of the bluetooth to connect to");
 	squeezelite_args.control_delay = arg_int0("d", "delay", "<control delay>", "the delay between each pass at the A2DP control loop");
 	squeezelite_args.connect_timeout_delay = arg_int0("t","timeout", "<timeout>", "the timeout duration for connecting to the A2DP sink");
 	squeezelite_args.end = arg_end(2);
 
-
 	ESP_LOGD(TAG,"Copying parameters");
 	char * opts = strdup(options);
 	char **argv = malloc(sizeof(char**)*15);
@@ -280,42 +228,7 @@ void hal_bluetooth_init(const char * options)
 	esp_bt_gap_set_pin(pin_type, 0, pin_code);
 
 }
-static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
-{
-	int32_t avail_data=0,wanted_len=0, start_timer=0;
-
-	if (len < 0 || data == NULL ) {
-		return 0;
-	}
-	btout=data;
-
-	// This is how the BTC layer calculates the number of bytes to
-	// for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes
-	wanted_len=len;
-	SET_MIN_MAX(len,req);
-	TIME_MEASUREMENT_START(start_timer);
-	LOCK;
-	output.device_frames = 0; // todo: check if this is the right way do to this.
-	output.updated = gettime_ms();
-	output.frames_played_dmp = output.frames_played;
-	SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size);
-	do {
-		avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full
-		wanted_len-=avail_data;
-	} while (wanted_len > 0 && avail_data != 0);
-	if(wanted_len>0)
-	{
-		SET_MIN_MAX(wanted_len, under);
-	}
 
-	UNLOCK;
-	SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
-	SET_MIN_MAX((len-wanted_len), rec);
-	TIME_MEASUREMENT_START(start_timer);
-	output_bt_check_buffer();
-
-	return len-wanted_len;
-}
 static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
 {
     bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
@@ -415,10 +328,10 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param)
 {
     switch (s_a2d_state) {
     case APP_AV_STATE_DISCOVERING:
-    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
+    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, output_state_str());
     	break;
     case APP_AV_STATE_DISCOVERED:
-    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
+    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, output_state_str());
         break;
     case APP_AV_STATE_UNCONNECTED:
         bt_app_av_state_unconnected(event, param);
@@ -562,7 +475,6 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     }
 }
 
-
 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
 {
 
@@ -579,7 +491,7 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
 
         /* initialize A2DP source */
         esp_a2d_register_callback(&bt_app_a2d_cb);
-        esp_a2d_source_register_data_callback(bt_app_a2d_data_cb);
+        esp_a2d_source_register_data_callback(&output_bt_data);
         esp_a2d_source_init();
 
         /* set discoverable and connectable mode */
@@ -605,39 +517,15 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
     }
 }
 
-#ifdef BTAUDIO
-bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
-
-//	running_test  = true;
-//	while(running_test)
-//	{
-//		// wait until BT playback has started
-//		// this will allow querying the sample rate
-//		usleep(100000);
-//	}
-
-	memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned));
-	if (!strcmp(device, "BT")) {
-		rates[0] = 44100;
-	} else {
-		unsigned _rates[] = { 96000, 88200, 48000, 44100, 32000, 0 };
-		memcpy(rates, _rates, sizeof(_rates));
-	}
-	return true;
-}
-#endif
 static void bt_app_av_media_proc(uint16_t event, void *param)
 {
     esp_a2d_cb_param_t *a2d = NULL;
-    LOCK;
-    output_state out_state=output.state;
-    UNLOCK;
     switch (s_media_state) {
     case APP_AV_MEDIA_STATE_IDLE: {
     	if (event == BT_APP_HEART_BEAT_EVT) {
-            if(out_state > OUTPUT_STOPPED)
+            if(!output_stopped())
             {
-            	ESP_LOGI(TAG,"Output state is %s, Checking if A2DP is ready.", get_output_state_desc(out_state));
+            	ESP_LOGI(TAG,"Output state is %s, Checking if A2DP is ready.", output_state_str());
             	esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
             }
 
@@ -671,40 +559,12 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
     }
     case APP_AV_MEDIA_STATE_STARTED: {
         if (event == BT_APP_HEART_BEAT_EVT) {
-        	if(out_state <= OUTPUT_STOPPED) {
-        		ESP_LOGI(TAG,"Output state is %s. Stopping a2dp media ...", get_output_state_desc(out_state));
+        	if(output_stopped()) {
+        		ESP_LOGI(TAG,"Output state is %s. Stopping a2dp media ...", output_state_str());
                 s_media_state = APP_AV_MEDIA_STATE_STOPPING;
                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
-            }
-        	else
-        	{
-        		LOCK_S;
-        		SET_MIN_MAX_SIZED(_buf_used(streambuf),stream_buf,streambuf->size);
-        		UNLOCK_S;
-        		static time_t lastTime=0;
-        		if (lastTime <= gettime_ms() )
-				{
-					lastTime = gettime_ms() + 15000;
-					ESP_LOGD(TAG, "Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000);
-					ESP_LOGD(TAG, "              +==========+==========+================+=====+================+");
-					ESP_LOGD(TAG, "              |      max |      min |        average | avg |          count |");
-					ESP_LOGD(TAG, "              |  (bytes) |  (bytes) |        (bytes) | pct |                |");
-					ESP_LOGD(TAG, "              +==========+==========+================+=====+================+");
-					ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf));
-					ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt));
-					ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
-					ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
-					ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under));
-					ESP_LOGD(TAG, "              +==========+==========+================+=====+================+");
-					ESP_LOGD(TAG,"\n");
-					ESP_LOGD(TAG,"              ==========+==========+===========+===========+  ");
-					ESP_LOGD(TAG,"              max (us)  | min (us) |   avg(us) |  count    |  ");
-					ESP_LOGD(TAG,"              ==========+==========+===========+===========+  ");
-					ESP_LOGD(TAG,LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time));
-					ESP_LOGD(TAG,"              ==========+==========+===========+===========+");
-					RESET_ALL_MIN_MAX;
-				}
-
+            } else {
+				output_bt_tick();	
         	}
         }
         break;
@@ -716,16 +576,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
             if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP &&
                     a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
                 ESP_LOGI(TAG,"a2dp media stopped successfully...");
-                //s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT;
-              //  if(CONFIG_A2DP_DISCONNECT_MS==0){
-                	// we're not going to disconnect.
-                	s_media_state = APP_AV_MEDIA_STATE_IDLE;
-//                }
-//                else
-//                {
-//                	disconnect_time = gettime_ms()+CONFIG_A2DP_DISCONNECT_MS;
-//                	s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT;
-//                }
+               	s_media_state = APP_AV_MEDIA_STATE_IDLE;
             } else {
                 ESP_LOGI(TAG,"a2dp media stopping...");
                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
@@ -735,20 +586,15 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
     }
 
     case APP_AV_MEDIA_STATE_WAIT_DISCONNECT:{
-    	if(gettime_ms()>disconnect_time){
-    		// we've reached timeout
-			esp_a2d_source_disconnect(s_peer_bda);
-			s_a2d_state = APP_AV_STATE_DISCONNECTING;
-    	}
+    	esp_a2d_source_disconnect(s_peer_bda);
+		s_a2d_state = APP_AV_STATE_DISCONNECTING;
+		ESP_LOGI(TAG,"a2dp disconnecting...");
     }
     }
 }
 
 static void bt_app_av_state_unconnected(uint16_t event, void *param)
 {
-//	LOCK;
-//	output_state out_state= output.state;
-//	UNLOCK;
 	switch (event) {
     case ESP_A2D_CONNECTION_STATE_EVT:
     	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_CONNECTION_STATE_EVT));
@@ -772,8 +618,6 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
     	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_MEDIA_CTRL_ACK_EVT));
     	break;
     case BT_APP_HEART_BEAT_EVT: {
-       // uint8_t *p = s_peer_bda;
-       // ESP_LOGI(TAG,"BT_APP_HEART_BEAT_EVT a2dp connecting to peer: %02x:%02x:%02x:%02x:%02x:%02x",p[0], p[1], p[2], p[3], p[4], p[5]);
         switch (esp_bluedroid_get_status()) {
 		case ESP_BLUEDROID_STATUS_UNINITIALIZED:
 			ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_UNINITIALIZED.");
@@ -787,21 +631,18 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
 		default:
 			break;
 		}
-//        if(out_state > OUTPUT_STOPPED){
-        	// only attempt a connect when playback isn't stopped
-			for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){
-				ESP_LOGI(TAG,"%s",art_a2dp_connecting[l]);
-			}
-			ESP_LOGI(TAG,"Device: %s", s_peer_bdname);
-			if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {
-				A2DP_TIMER_INIT;
-				s_a2d_state = APP_AV_STATE_CONNECTING;
-			}
-			else {
-				// there was an issue connecting... continue to discover
-				ESP_LOGE(TAG,"Attempt at connecting failed, restart at discover...");
-				esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
-	//		}
+		for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){
+			ESP_LOGI(TAG,"%s",art_a2dp_connecting[l]);
+		}
+		ESP_LOGI(TAG,"Device: %s", s_peer_bdname);
+		if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {
+			A2DP_TIMER_INIT;
+			s_a2d_state = APP_AV_STATE_CONNECTING;
+		}
+		else {
+			// there was an issue connecting... continue to discover
+			ESP_LOGE(TAG,"Attempt at connecting failed, restart at discover...");
+			esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
         }
         break;
     }
@@ -928,18 +769,4 @@ static void bt_app_av_state_disconnecting(uint16_t event, void *param)
         ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
         break;
     }
-}
-const char *loc_logtime(void) {
-	static char buf[100];
-#if WIN
-	SYSTEMTIME lt;
-	GetLocalTime(&lt);
-	sprintf(buf, "[%02d:%02d:%02d.%03d]", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
-#else
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	strftime(buf, sizeof(buf), "[%T.", localtime(&tv.tv_sec));
-	sprintf(buf+strlen(buf), "%06ld]", (long)tv.tv_usec);
-#endif
-	return buf;
-}
+}

+ 1 - 0
components/platform_esp32/cmd_squeezelite.c

@@ -7,6 +7,7 @@
 
 #include "esp_log.h"
 #include "esp_console.h"
+#include "esp_pthread.h"
 #include "argtable3/argtable3.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/event_groups.h"

+ 0 - 1
components/platform_esp32/component.mk

@@ -6,5 +6,4 @@
 # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
 # please read the SDK documents if you need to do this.
 #
-CFLAGS += -Os -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 	
 CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG

+ 21 - 141
components/platform_esp32/esp_app_main.c

@@ -1,147 +1,27 @@
-/* Scan Example
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-
-/*
-    This example shows how to use the All Channel Scan or Fast Scan to connect
-    to a Wi-Fi network.
-
-    In the Fast Scan mode, the scan will stop as soon as the first network matching
-    the SSID is found. In this mode, an application can set threshold for the
-    authentication mode and the Signal strength. Networks that do not meet the
-    threshold requirements will be ignored.
-
-    In the All Channel Scan mode, the scan will end only after all the channels
-    are scanned, and connection will start with the best network. The networks
-    can be sorted based on Authentication Mode or Signal Strength. The priority
-    for the Authentication mode is:  WPA2 > WPA > WEP > Open
-*/
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.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/>.
+ *
+ */
+ 
 #include "platform_esp32.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "esp_bt.h"
-#include "esp_bt_device.h"
-#include "esp_bt_main.h"
-#include "esp_gap_bt_api.h"
-#include "esp_a2dp_api.h"
-#include "esp_avrc_api.h"
-#include "esp_log.h"
-#include "esp_pthread.h"
-#include "esp_system.h"
-#include "esp_wifi.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/event_groups.h"
-#include "freertos/task.h"
-#include "freertos/timers.h"
-#include "nvs.h"
-#include "nvs_flash.h"
-#include "nvs_utilities.h"
-#include "pthread.h"
-#include "string.h"
-#include "sys/socket.h"
-#include <signal.h>
-#include "esp_system.h"
-#include <signal.h>
-
-/*Set the SSID and Password via "make menuconfig"*/
-#define DEFAULT_SSID CONFIG_WIFI_SSID
-#define DEFAULT_PWD CONFIG_WIFI_PASSWORD
-
-#if CONFIG_WIFI_ALL_CHANNEL_SCAN
-#define DEFAULT_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
-#elif CONFIG_WIFI_FAST_SCAN
-#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
-#else
-#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
-#endif /*CONFIG_SCAN_METHOD*/
-
-#if CONFIG_WIFI_CONNECT_AP_BY_SIGNAL
-#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
-#elif CONFIG_WIFI_CONNECT_AP_BY_SECURITY
-#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY
-#else
-#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
-#endif /*CONFIG_SORT_METHOD*/
-
-#if CONFIG_FAST_SCAN_THRESHOLD
-#define DEFAULT_RSSI CONFIG_FAST_SCAN_MINIMUM_SIGNAL
-#if CONFIG_EXAMPLE_OPEN
-#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
-#elif CONFIG_EXAMPLE_WEP
-#define DEFAULT_AUTHMODE WIFI_AUTH_WEP
-#elif CONFIG_EXAMPLE_WPA
-#define DEFAULT_AUTHMODE WIFI_AUTH_WPA_PSK
-#elif CONFIG_EXAMPLE_WPA2
-#define DEFAULT_AUTHMODE WIFI_AUTH_WPA2_PSK
-#else
-#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
-#endif
-#else
-#define DEFAULT_RSSI -127
-#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
-#endif /*CONFIG_FAST_SCAN_THRESHOLD*/
-extern char current_namespace[];
-static const char * TAG = "platform_esp32";
-
-
-
-//static void event_handler(void* arg, esp_event_base_t event_base,
-//                                int32_t event_id, void* event_data)
-//{
-//    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
-//        esp_wifi_connect();
-//    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
-//        esp_wifi_connect();
-//    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
-//        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
-//        ESP_LOGI(TAG, "got ip: %s.", ip4addr_ntoa(&event->ip_info.ip));
-//        ESP_LOGD(TAG,"Signaling wifi connected. Locking.\n");
-//    	pthread_mutex_lock(&wifi_connect_suspend_mutex);
-//    	ESP_LOGD(TAG,"Signaling wifi connected. Broadcasting.\n");
-//		pthread_cond_broadcast(&wifi_connect_suspend_cond);
-//		ESP_LOGD(TAG,"Signaling wifi connected. Unlocking.\n");
-//		pthread_mutex_unlock(&wifi_connect_suspend_mutex);
-//    }
-//}
-//
-///* Initialize Wi-Fi as sta and set scan method */
-//static void wifi_scan(void)
-//{
-//
-//    tcpip_adapter_init();
-//    ESP_ERROR_CHECK(esp_event_loop_create_default());
-//
-//    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-//    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
-//
-//    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
-//    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
-//
-//    wifi_config_t wifi_config = {
-//        .sta = {
-//            .ssid = DEFAULT_SSID,
-//            .password = DEFAULT_PWD,
-//            .scan_method = DEFAULT_SCAN_METHOD,
-//            .sort_method = DEFAULT_SORT_METHOD,
-//            .threshold.rssi = DEFAULT_RSSI,
-//            .threshold.authmode = DEFAULT_AUTHMODE,
-//        },
-//    };
-//    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
-//    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
-//    ESP_ERROR_CHECK(esp_wifi_start());
-//}
-
 
 void app_main()
 {
-
 	console_start();
 }

+ 23 - 3
components/platform_esp32/perf_trace.h

@@ -1,8 +1,28 @@
-
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.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/>.
+ *
+ */
+ 
 #pragma once
-#include "time.h"
+
 #include "sys/time.h"
-#include "esp_system.h"
+
 #define PERF_MAX LONG_MAX
 #define MIN_MAX_VAL(x) x==PERF_MAX?0:x
 #define CURR_SAMPLE_RATE output.current_sample_rate>0?output.current_sample_rate:1

+ 28 - 77
components/platform_esp32/platform_esp32.h

@@ -1,93 +1,44 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.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/>.
+ *
+ */
+ 
 #pragma once
+
 #ifdef __cplusplus
 extern "C" {
 #endif
-#include "bt_app_core.h"
-#include "perf_trace.h"
+
 #include "esp_pthread.h"
+
 #ifndef QUOTE
 #define QUOTE(name) #name
-#define STR(macro)  QUOTE(macro)
 #endif
+
+#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e)
+
 extern void run_command(char * line);
 extern bool wait_for_wifi();
-
-//typedef struct {
-//	char opt_slimproto_logging[11];
-//	char opt_stream_logging[11];
-//	char opt_decode_logging[11];
-//	char opt_output_logging[11];
-//	char opt_player_name[11];
-//	char opt_output_rates[21];
-//	char opt_buffer[11];
-//} str_squeezelite_options ;
 extern void console_start();
 extern pthread_cond_t wifi_connect_suspend_cond;
 extern pthread_t wifi_connect_suspend_mutex;
-//static const char * art_wifi[]={
-//		"\n",
-//		"o          `O ooOoOOo OOooOoO ooOoOOo\n",
-//		"O           o    O    o          O   \n",
-//		"o           O    o    O          o   \n",
-//		"O           O    O    oOooO      O   \n",
-//		"o     o     o    o    O          o   \n",
-//		"O     O     O    O    o          O   \n",
-//		"`o   O o   O'    O    o          O   \n",
-//		" `OoO' `OoO'  ooOOoOo O'      ooOOoOo\n",
-//		"\n",
-//		""
-//};
-//static const char * art_wifi_connecting[]={
-//		" .oOOOo.",
-//		".O     o                                        o               \n",
-//		"o                                           O                   \n",
-//		"o                                          oOo                  \n",
-//		"o         .oOo. 'OoOo. 'OoOo. .oOo. .oOo    o   O  'OoOo. .oOoO \n",
-//		"O         O   o  o   O  o   O OooO' O       O   o   o   O o   O \n",
-//		"`o     .o o   O  O   o  O   o O     o       o   O   O   o O   o \n",
-//		" `OoooO'  `OoO'  o   O  o   O `OoO' `OoO'   `oO o'  o   O `OoOo \n",
-//		"                                                              O \n",
-//		"                                                           OoO' \n",
-//		"\n",
-//		""
-//};
-//static const char * art_wifi_connected[]={
-//		" .oOOOo.                                                   o       oO\n",
-//		".O     o                                                  O        OO\n",
-//		"o                                           O             o        oO\n",
-//		"o                                          oOo            o        Oo\n",
-//		"o         .oOo. 'OoOo. 'OoOo. .oOo. .oOo    o   .oOo. .oOoO        oO\n",
-//		"O         O   o  o   O  o   O OooO' O       O   OooO' o   O          \n",
-//		"`o     .o o   O  O   o  O   o O     o       o   O     O   o        Oo\n",
-//		" `OoooO'  `OoO'  o   O  o   O `OoO' `OoO'   `oO `OoO' `OoO'o       oO\n",
-//		"\n",
-//		""
-//};
-#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e)
-const char *loc_logtime(void);
-//#define MY_ESP_LOG
-#ifdef MY_ESP_LOG
-#ifdef ESP_LOGI
-#undef ESP_LOGI
-#define ESP_LOGI(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO,    tag, "%s %d " format,loc_logtime(),  __LINE__, ##__VA_ARGS__)
-#endif
-#ifdef ESP_LOGE
-#undef ESP_LOGE
-#define ESP_LOGE(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR,    tag, "%s %d " format,loc_logtime(),  __LINE__, ##__VA_ARGS__)
-#endif
-#ifdef ESP_LOGW
-#undef ESP_LOGW
-#define ESP_LOGW(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN,    tag, "%s %d " format,loc_logtime(),  __LINE__, ##__VA_ARGS__)
-#endif
-#ifdef ESP_LOGD
-#undef ESP_LOGD
-#define ESP_LOGD(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG,    tag, "%s %d " format,loc_logtime(),  __LINE__, ##__VA_ARGS__)
-#endif
-#ifdef ESP_LOGV
-#undef ESP_LOGV
-#define ESP_LOGV(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, "%s %d " format,loc_logtime(),  __LINE__, ##__VA_ARGS__)
-#endif
-#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 8
main/Kconfig.projbuild

@@ -134,7 +134,7 @@ menu "Squeezelite-ESP32"
 		    
 		config OUTPUT_RATES
 			string "Output rates"
-			default "48000,44100"
+			default "44100"
 			help
 				<rates>[:<delay>]	Sample rates supported, allows output to be off when squeezelite is started; rates = <maxrate>|<minrate>-<maxrate>|<rate1>,<rate2>,<rate3>; delay = optional delay switching rates in ms
 		menu "DAC I2S settings"  
@@ -196,13 +196,6 @@ menu "Squeezelite-ESP32"
 		        default 1000
 		        help
 		            Increasing this value will give more chance for less stable connections to be established.	   
-	        config A2DP_DISCONNECT_MS
-	        	int "Time in ms before disconnecting from A2DP audio sink. Set to 0 for no disconnect."
-	        	default 10000
-	        	help
-	        		Controls how long to wait before disconnecting from the A2DP audio sink after playback is stopped
-	        		Longer delay will ensure better responsiveness at the expense of locking the audio sink for a longer period. 
-	        		A shorter period may cause the player to disconnect between tracks change.
 		endmenu
 	endmenu
 

+ 2 - 2
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 += -O3 -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 	\
+CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -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/alac		\
@@ -10,7 +10,7 @@ CFLAGS += -O3 -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DT
 	-I$(COMPONENT_PATH)/../components/codecs/inc/vorbis 	\
 	-I$(COMPONENT_PATH)/../components/codecs/inc/soxr 		\
 	-I$(COMPONENT_PATH)/../components/codecs/inc/resample16	\
-	-I$(COMPONENT_PATH)/../components/platform_esp32 
+	-I$(COMPONENT_PATH)/../components/platform_esp32
 	
 LDFLAGS += -s
 

+ 5 - 2
main/decode.c

@@ -199,8 +199,8 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud
 	LOG_DEBUG("include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs);
 
 	mutex_create(decode.mutex);
-	PTHREAD_SET_NAME("decode");
-#if LINUX || OSX || FREEBSD || POSIX
+
+#if LINUX || OSX || FREEBSD || EMBEDDED
 	pthread_attr_t attr;
 	pthread_attr_init(&attr);
 #ifdef PTHREAD_STACK_MIN
@@ -208,6 +208,9 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud
 #endif
 	pthread_create(&thread, &attr, decode_thread, NULL);
 	pthread_attr_destroy(&attr);
+#if HAS_PTHREAD_SETNAME_NP	
+	pthread_setname_np(thread, "decode");
+#endif
 #endif
 #if WIN
 	thread = CreateThread(NULL, DECODE_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&decode_thread, NULL, 0, NULL);

+ 44 - 0
main/embedded.c

@@ -0,0 +1,44 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.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/>.
+ *
+ */
+#include "squeezelite.h"
+#include "esp_pthread.h"
+#include "esp_system.h"
+
+void get_mac(u8_t mac[]) {
+    esp_read_mac(mac, ESP_MAC_WIFI_STA);
+}
+
+_sig_func_ptr signal(int sig, _sig_func_ptr func) {
+	return NULL;
+}
+
+void *audio_calloc(size_t nmemb, size_t size) {
+		return calloc(nmemb, size);
+}
+
+int pthread_setname_np(pthread_t thread, const char *name) { 
+	esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); 
+	cfg.thread_name= name; 
+	cfg.inherit_cfg = true; 
+	return esp_pthread_set_cfg(&cfg); 
+}
+
+

+ 21 - 5
main/embedded.h

@@ -1,6 +1,22 @@
-#pragma once
-#if defined(ESP_PLATFORM)
-#include "sdkconfig.h"
-#include "esp_pthread.h"
-#define PTHREAD_SET_NAME(n) 	{ esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); cfg.thread_name= n; cfg.inherit_cfg = true; esp_pthread_set_cfg(&cfg); }
+#ifndef EMBEDDED_H
+#define EMBEDDED_H
+
+#include <inttypes.h>
+
+#define HAS_MUTEX_CREATE_P		0
+#define HAS_PTHREAD_SETNAME_NP	1
+
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN	256
 #endif
+
+typedef int16_t   s16_t;
+typedef int32_t   s32_t;
+typedef int64_t   s64_t;
+typedef unsigned long long u64_t;
+
+#define exit(code) { int ret = code; pthread_exit(&ret); }
+
+int pthread_setname_np(pthread_t thread, const char *name);
+
+#endif // EMBEDDED_H

+ 17 - 21
main/main.c

@@ -169,6 +169,9 @@ static void usage(const char *argv0) {
 		   "18"
 #endif
 #endif
+#if EMBEDDED
+			" EMBEDDED"
+#endif	
 #if EVENTFD
 		   " EVENTFD"
 #endif
@@ -381,7 +384,7 @@ int main(int argc, char **argv) {
 		} else {
 			fprintf(stderr, "\nOption error: -%s\n\n", opt);
 			usage(argv[0]);
-			local_exit(1);
+			exit(1);
 		}
 
 		switch (opt[0]) {
@@ -432,7 +435,7 @@ int main(int argc, char **argv) {
 				} else {
 					fprintf(stderr, "\nDebug settings error: -d %s\n\n", optarg);
 					usage(argv[0]);
-					local_exit(1);
+					exit(1);
 				}
 			}
 			break;
@@ -532,7 +535,7 @@ int main(int argc, char **argv) {
 			pidfile = optarg;
 			break;
 #endif
-#if !CONFIG_DACAUDIO && !CONFIG_BTAUDIO
+#ifndef EMBEDDED
 		case 'l':
 			list_devices();
 			exit(0);
@@ -675,12 +678,11 @@ int main(int argc, char **argv) {
 #endif
 		case 't':
 			license();
-			local_exit(0);
-			break; // mute compiler warning
+			exit(0);
 		case '?':
 			usage(argv[0]);
-			local_exit(0);
-			break; // mute compiler warning
+			exit(0);
+			break;
 		default:
 			fprintf(stderr, "Arg error: %s\n", argv[optind]);
 			break;
@@ -691,7 +693,7 @@ int main(int argc, char **argv) {
 	if (optind < argc) {
 		fprintf(stderr, "\nError: command line argument error\n\n");
 		usage(argv[0]);
-		local_exit(1);
+		exit(1);
 	}
 
 	signal(SIGINT, sighandler);
@@ -757,13 +759,9 @@ int main(int argc, char **argv) {
 #endif
 
 	stream_init(log_stream, stream_buf_size);
-#ifdef EMBEDDED
-if(strstr(output_device,"BT")!=NULL || strstr(output_device,"bt")!=NULL) {
-	output_init_bt(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
-}
-else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){
-	output_init_dac(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
-}
+
+#if EMBEDDED
+	output_init_embedded(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
 #else
 	if (!strcmp(output_device, "-")) {
 		output_init_stdout(log_output, output_buf_size, output_params, rates, rate_delay);
@@ -804,7 +802,7 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){
 
 	if (name && namefile) {
 		fprintf(stderr, "-n and -N option should not be used at same time\n");
-		local_exit(1);
+		exit(1);
 	}
 
 	slimproto(log_slimproto, server, mac, name, namefile, modelname, maxSampleRate);
@@ -812,10 +810,8 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){
 	decode_close();
 	stream_close();
 
-#if CONFIG_DACAUDIO
-	output_close_dac();	
-#elif CONFIG_BTAUDIO
-	output_close_bt();
+#if EMBEDDED
+	output_close_embedded();	
 #else
 	if (!strcmp(output_device, "-")) {
 		output_close_stdout();
@@ -848,5 +844,5 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){
 	free_ssl_symbols();
 #endif	
 
-	local_exit(0);
+	exit(0);
 }

+ 3 - 3
main/output.c

@@ -352,13 +352,13 @@ void output_init_common(log_level level, const char *device, unsigned output_buf
 	buf_init(outputbuf, output_buf_size);
 	if (!outputbuf->buf) {
 		LOG_ERROR("unable to malloc output buffer");
-		local_exit(0);
+		exit(0);
 	}
 
 	silencebuf = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
 	if (!silencebuf) {
 		LOG_ERROR("unable to malloc silence buffer");
-		local_exit(0);
+		exit(0);
 	}
 	memset(silencebuf, 0, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
 
@@ -389,7 +389,7 @@ void output_init_common(log_level level, const char *device, unsigned output_buf
 	else {
 		if (!test_open(output.device, output.supported_rates, user_rates)) {
 			LOG_ERROR("unable to open output device: %s", output.device);
-			local_exit(0);
+			exit(0);
 		}
 	}
 

+ 91 - 317
main/output_bt.c

@@ -1,352 +1,59 @@
 #include "squeezelite.h"
 #include "perf_trace.h"
 
-static log_level loglevel;
-
-static bool running = true;
-
 extern struct outputstate output;
 extern struct buffer *outputbuf;
 extern struct buffer *streambuf;
-
+extern u8_t *silencebuf;
 
 #define LOCK   mutex_lock(outputbuf->mutex)
 #define UNLOCK mutex_unlock(outputbuf->mutex)
-
-#ifdef USE_BT_RING_BUFFER
-size_t bt_buffer_size=0;
-uint8_t bt_buf_used_threshold = 25;
-uint16_t output_bt_thread_heartbeat_ms=1000;
-thread_type thread_bt;
-#define LOCK_BT   mutex_lock(btbuf->mutex)
-#define UNLOCK_BT mutex_unlock(btbuf->mutex)
-thread_cond_type output_bt_suspend_cond;
-mutex_type output_bt_suspend_mutex;
-static struct buffer bt_buf_structure;
-struct buffer *btbuf=&bt_buf_structure;
-static void *output_thread_bt();
-extern void wait_for_frames(size_t frames, uint8_t pct);
-#else
-uint8_t * btout;
-#endif
+#define LOCK_S   mutex_lock(streambuf->mutex)
+#define UNLOCK_S mutex_unlock(streambuf->mutex)
 
 #define FRAME_BLOCK MAX_SILENCE_FRAMES
-extern u8_t *silencebuf;
+
+#define STATS_REPORT_DELAY_MS 15000
 
 extern void hal_bluetooth_init(const char * options);
 
+static log_level loglevel;
+uint8_t * btout;
+
 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);
+								
 #define DECLARE_ALL_MIN_MAX \
 	DECLARE_MIN_MAX(req);\
 	DECLARE_MIN_MAX(rec);\
-	DECLARE_MIN_MAX(o);\
-	DECLARE_MIN_MAX(s);\
-	DECLARE_MIN_MAX(locbtbuff);\
+	DECLARE_MIN_MAX(bt);\
 	DECLARE_MIN_MAX(under);\
-	DECLARE_MIN_MAX_DURATION(mutex1);\
-	DECLARE_MIN_MAX_DURATION(mutex2);\
-	DECLARE_MIN_MAX_DURATION(buffering);\
-	DECLARE_MIN_MAX_DURATION(sleep_time);
+	DECLARE_MIN_MAX(stream_buf);\
+	DECLARE_MIN_MAX_DURATION(lock_out_time)								
+	
 #define RESET_ALL_MIN_MAX \
-	RESET_MIN_MAX(o); \
-	RESET_MIN_MAX(s); \
-	RESET_MIN_MAX(locbtbuff); \
+	RESET_MIN_MAX(bt);	\
 	RESET_MIN_MAX(req);  \
 	RESET_MIN_MAX(rec);  \
 	RESET_MIN_MAX(under);  \
-	RESET_MIN_MAX_DURATION(mutex1);  \
-	RESET_MIN_MAX_DURATION(mutex2);  \
-	RESET_MIN_MAX_DURATION(sleep_time);  \
-	RESET_MIN_MAX_DURATION(buffering);
-
-
-#if CONFIG_BTAUDIO
-void set_volume_bt(unsigned left, unsigned right) {
-	LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
-	LOCK;
-	output.gainL = left;
-	output.gainR = right;
-	UNLOCK;
-}
-#endif
-
-
-
-void output_bt_check_buffer()
-{
-#ifdef USE_BT_RING_BUFFER
-	LOCK_BT;
-	uint8_t tot_buf_used_pct=100*_buf_used(btbuf)/btbuf->size;
-	UNLOCK_BT;
-	if(tot_buf_used_pct<bt_buf_used_threshold)
-	{
-		// tell the thread to resume
-		LOG_SDEBUG("Below threshold. Locking suspend mutex.");
-		mutex_lock(output_bt_suspend_mutex);
-		LOG_SDEBUG("Broadcasting suspend condition.");
-		mutex_broadcast_cond(output_bt_suspend_cond);
-		LOG_SDEBUG("Unlocking suspend mutex.");
-		mutex_unlock(output_bt_suspend_mutex);
-	}
-#endif
-}
-void output_bt_suspend()
-{
-#ifdef USE_BT_RING_BUFFER
-	struct timespec   ts;
-	struct timeval    tp;
-	int               rc;
-
-
-	// if suspended, suspend until resumed
-	LOG_SDEBUG("Locking suspend mutex.");
-	mutex_lock(output_bt_suspend_mutex);
-	LOG_SDEBUG("Waiting on condition to be signaled.");
-
-	// suspend for up to a predetermined wait time.
-	// this will allow flushing the BT buffer when the
-	// playback stops.
-	gettimeofday(&tp, NULL);
-	/* Convert from timeval to timespec */
-	ts.tv_sec  = tp.tv_sec;
-	ts.tv_nsec = tp.tv_usec * 1000;
-	ts.tv_nsec +=  output_bt_thread_heartbeat_ms*1000000; // micro seconds to nanosecs
-
-	rc = pthread_cond_timedwait(&output_bt_suspend_cond,&output_bt_suspend_mutex,&ts);
-	if(rc==ETIMEDOUT)
-	{
-		LOG_SDEBUG("Wait timed out. Resuming output.");
-	}
-    LOG_SDEBUG("Unlocking suspend mutex.");
-    mutex_unlock(output_bt_suspend_mutex);
-#endif
-}
-
+	RESET_MIN_MAX(stream_buf); \
+	RESET_MIN_MAX_DURATION(lock_out_time)
+	
+DECLARE_ALL_MIN_MAX;	
+	
 void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
 	loglevel = level;
-
-	LOG_INFO("init output BT");
-
-	memset(&output, 0, sizeof(output));
-
-	// ensure output rate is specified to avoid test open
-	if (!rates[0]) {
-		rates[0] = 44100;
-	}
 	hal_bluetooth_init(device);
-/*
- * Bluetooth audio source init Start
- */
-//	device = CONFIG_OUTPUT_NAME;
-	output_init_common(level, device, output_buf_size, rates, idle);
-#ifdef USE_BT_RING_BUFFER
-	LOG_DEBUG("Allocating local BT transfer buffer of %u bytes.",bt_buffer_size);
-	buf_init(btbuf, bt_buffer_size );
-	if (!btbuf->buf) {
-		LOG_ERROR("unable to malloc BT buffer");
-		exit(0);
-	}
-	mutex_create_p(output_bt_suspend_mutex);
-	mutex_cond_init(output_bt_suspend_cond);
-	PTHREAD_SET_NAME("output_bt");
-
-#if LINUX || OSX || FREEBSD || POSIX
-	pthread_attr_t attr;
-	pthread_attr_init(&attr);
-#ifdef PTHREAD_STACK_MIN
-	pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
-#endif
-
-	pthread_create(&thread_bt, &attr, output_thread_bt, NULL);
-#endif
-	pthread_attr_destroy(&attr);
-
-#if WIN
-	thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread_bt, NULL, 0, NULL);
-#endif
-#else
-	output.start_frames =  FRAME_BLOCK;
 	output.write_cb = &_write_frames;
-	output.rate_delay = rate_delay;
-#endif
-	LOG_INFO("Init completed.");
-
-}
-
-/****************************************************************************************
- * Main output thread
- */
-#ifdef USE_BT_RING_BUFFER
-static void *output_thread_bt() {
-
-	frames_t frames=0;
-	frames_t requested_frames=0;
-	uint32_t timer_start=0, mutex_start=0;
-	unsigned btbuf_used=0;
-	output_state state;
-	DECLARE_ALL_MIN_MAX;
-	while (running) {
-		frames=0;
-		requested_frames=0;
-		TIME_MEASUREMENT_START(timer_start);
-
-		// Get output state
-		TIME_MEASUREMENT_START(mutex_start);
-		LOCK;
-		state=output.state;
-		SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1);
-
-		if(state < OUTPUT_STOPPED ){
-			// Flushing the buffer will automatically
-			// lock the mutex
-			LOG_SDEBUG("Flushing BT buffer");
-			buf_flush(btbuf);
-		}
-		if (state == OUTPUT_OFF) {
-			UNLOCK;
-			LOG_SDEBUG("Output state is off.");
-			usleep(200000);
-			continue;
-		}
-		output.device_frames = 0; // todo: check if this is the right way do to this.
-		output.updated = gettime_ms();
-		output.frames_played_dmp = output.frames_played;
-
-		TIME_MEASUREMENT_START(mutex_start);
-		LOCK_BT;
-		SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex2);
-		btbuf_used=_buf_used(btbuf);
-		SET_MIN_MAX_SIZED(btbuf_used,locbtbuff,btbuf->size);
-
-
-		// only output more frames if we need them
-		// so we can release the mutex as quickly as possible
-		requested_frames = min(_buf_space(btbuf), _buf_cont_write(btbuf))/BYTES_PER_FRAME;
-		SET_MIN_MAX( requested_frames*BYTES_PER_FRAME,req);
-		SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size);
-		SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size);
-		if(requested_frames>0)
-		{
-			frames = _output_frames( requested_frames ); // Keep the transfer buffer full
-			SET_MIN_MAX(frames*BYTES_PER_FRAME,rec);
-			if(requested_frames>frames){
-				SET_MIN_MAX((requested_frames-frames)*BYTES_PER_FRAME,under);
-			}
-		}
-
-		UNLOCK;
-		UNLOCK_BT;
-		SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering);
-		SET_MIN_MAX( requested_frames,req);
-
-		// When playback has started, we want to
-		// hold the BT out thread
-		// so the BT data callback isn't constantly interrupted.
-		TIME_MEASUREMENT_START(timer_start);
-		if(state>OUTPUT_BUFFER){
-			output_bt_suspend();
-		}
-		SET_MIN_MAX(TIME_MEASUREMENT_GET(timer_start),sleep_time);
-
-		/*
-		 * Statistics reporting
-		 */
-		static time_t lastTime=0;
-		if (lastTime <= gettime_ms() )
-		{
-#define STATS_PERIOD_MS 15000
-			lastTime = gettime_ms() + STATS_PERIOD_MS;
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD1);
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD2);
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD3);
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD4);
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local bt buf",locbtbuff));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER );
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("Underrun",under));
-			LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER );
-			LOG_DEBUG("");
-			LOG_DEBUG("              ----------+----------+-----------+-----------+  ");
-			LOG_DEBUG("              max (us)  | min (us) |   avg(us) |  count    |  ");
-			LOG_DEBUG("              ----------+----------+-----------+-----------+  ");
-			LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
-			LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Output mux(us)",mutex1));
-			LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("BT mux(us)",mutex2));
-			LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("sleep(us)",mutex2));
-			LOG_DEBUG("              ----------+----------+-----------+-----------+");
-			RESET_ALL_MIN_MAX;
-		}
-		/*
-		 * End Statistics reporting
-		 */
-
-
-
-	}
-	return NULL;
-}
-#endif
-void output_close_bt(void) {
-	LOG_INFO("close output");
-	LOCK;
-	running = false;
-	UNLOCK;
-#ifdef USE_BT_RING_BUFFER
-	LOCK_BT;
-	buf_destroy(btbuf);
-	UNLOCK_BT;
-#endif
-	output_close_common();
 }
 
 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) {
-#ifdef USE_BT_RING_BUFFER
-	if (!silence ) {
-		DEBUG_LOG_TIMED(200,"Not silence, Writing audio out.");
-		// 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);
-		}
-
-		if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
-			_apply_gain(outputbuf, out_frames, gainL, gainR);
-		}
-
-#if BYTES_PER_FRAME == 4
-
-		memcpy(btbuf->writep, outputbuf->readp, out_frames * BYTES_PER_FRAME);
-		_buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME);
-
-#else
-	{
-		frames_t count = out_frames;
-		s32_t *_iptr = (s32_t*) outputbuf->readp;
-		s16_t *_optr = (s16_t*) bt_optr;
-		while (count--) {
-			*_optr++ = *_iptr++ >> 16;
-			*_optr++ = *_iptr++ >> 16;
-		}
-	}
-#endif
-
-	} else if(output.state >OUTPUT_BUFFER){
-		// Don't fill our local buffer with silence frames.
-		u8_t *buf = silencebuf;
-		memcpy(btbuf->writep, buf, out_frames * BYTES_PER_FRAME);
-		_buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME);
-	}
-#else
-	assert(btout!=NULL);
+	
+	assert(btout != NULL);
+	
 	if (!silence ) {
-		DEBUG_LOG_TIMED(200,"Not silence, Writing audio out.");
-		// 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);
 		}
@@ -374,7 +81,74 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
 		u8_t *buf = silencebuf;
 		memcpy(btout, buf, out_frames * BYTES_PER_FRAME);
 	}
-#endif
 
 	return (int)out_frames;
 }
+
+int32_t output_bt_data(uint8_t *data, int32_t len) {
+	int32_t avail_data = 0, wanted_len = 0, start_timer = 0;
+
+	if (len < 0 || data == NULL ) {
+		return 0;
+	}
+	
+	btout = data;
+
+	// This is how the BTC layer calculates the number of bytes to
+	// for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes
+	wanted_len=len;
+	SET_MIN_MAX(len,req);
+	TIME_MEASUREMENT_START(start_timer);
+	LOCK;
+	output.device_frames = 0; // todo: check if this is the right way do to this.
+	output.updated = gettime_ms();
+	output.frames_played_dmp = output.frames_played;
+	SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size);
+	do {
+		avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full
+		wanted_len-=avail_data;
+	} while (wanted_len > 0 && avail_data != 0);
+	
+	if (wanted_len > 0) {
+		SET_MIN_MAX(wanted_len, under);
+	}
+
+	UNLOCK;
+	SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
+	SET_MIN_MAX((len-wanted_len), rec);
+	TIME_MEASUREMENT_START(start_timer);
+
+	return len-wanted_len;
+}
+
+void output_bt_tick(void) {
+	static time_t lastTime=0;
+	
+	LOCK_S;
+    SET_MIN_MAX_SIZED(_buf_used(streambuf), stream_buf, streambuf->size);
+    UNLOCK_S;
+	
+	if (lastTime <= gettime_ms() )
+	{
+		lastTime = gettime_ms() + STATS_REPORT_DELAY_MS;
+		LOG_INFO("Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000);
+		LOG_INFO("              +==========+==========+================+=====+================+");
+		LOG_INFO("              |      max |      min |        average | avg |          count |");
+		LOG_INFO("              |  (bytes) |  (bytes) |        (bytes) | pct |                |");
+		LOG_INFO("              +==========+==========+================+=====+================+");
+		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf));
+		LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt));
+		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("underrun",under));
+		LOG_INFO( "              +==========+==========+================+=====+================+");
+		LOG_INFO("\n");
+		LOG_INFO("              ==========+==========+===========+===========+  ");
+		LOG_INFO("              max (us)  | min (us) |   avg(us) |  count    |  ");
+		LOG_INFO("              ==========+==========+===========+===========+  ");
+		LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time));
+		LOG_INFO("              ==========+==========+===========+===========+");
+		RESET_ALL_MIN_MAX;
+	}	
+}	
+

+ 0 - 162
main/output_dac.c.tes

@@ -1,162 +0,0 @@
-#include "squeezelite.h"
-#include "driver/i2s.h"
-
-static log_level loglevel;
-
-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)
-
-#define FRAME_BLOCK MAX_SILENCE_FRAMES
-
-extern u8_t *silencebuf;
-
-#define I2S_NUM         (0)
-#define WAVE_FREQ_HZ    (100)
-#define PI              (3.14159265)
-#define I2S_BCK_IO      (GPIO_NUM_26)
-#define I2S_WS_IO       (GPIO_NUM_25)
-#define I2S_DO_IO       (GPIO_NUM_22)
-#define I2S_DI_IO       (-1)
-// buffer length is expressed in number of samples
-#define I2S_BUF_LEN		60
-
-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;
-}
-
-static void *output_thread(void *arg) {
-	bool start = true;
-	bool output_off = (output.state == OUTPUT_OFF);
-	bool probe_device = (arg != NULL);
-	int err;
-
-	while (running) {
-		// todo: implement output off logic?
-		// todo: call i2s_set_clock here if rate is changed
-		LOCK;
-
-		output.device_frames = 0;
-		output.updated = gettime_ms();
-		output.frames_played_dmp = output.frames_played;
-
-		_output_frames(I2S_BUF_LEN*2); // fill at least one DMA buffer with stereo signal
-
-		UNLOCK;
-	}
-
-	return 0;
-}
-
-static pthread_t thread;
-
-void output_init_dac(log_level level, char *device, unsigned output_buf_size,
-		char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
-	loglevel = level;
-
-	LOG_INFO("init output DAC");
-
-	memset(&output, 0, sizeof(output));
-
-	output.start_frames = 0; //CONFIG_ //FRAME_BLOCK * 2;
-	output.write_cb = &_write_frames;
-	output.rate_delay = rate_delay;
-
-	// ensure output rate is specified to avoid test open
-	if (!rates[0]) {
-		rates[0] = 44100;
-	}
-	device = "DAC";
-	output_init_common(level, device, output_buf_size, rates, idle);
-
-	i2s_config_t i2s_config = {
-			.mode = I2S_MODE_MASTER | I2S_MODE_TX,                    // Only TX
-			.sample_rate = output.current_sample_rate,
-			.bits_per_sample = BYTES_PER_FRAME * 8,
-			.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,           //2-channels
-			.communication_format = I2S_COMM_FORMAT_I2S
-					| I2S_COMM_FORMAT_I2S_MSB,
-			.dma_buf_count = 6, //todo: tune this parameter. Expressed in numbrer of buffers
-			.dma_buf_len = I2S_BUF_LEN, // todo: tune this parameter. Expressed in number of samples. Byte size depends on bit depth
-			.use_apll = false,
-			.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
-			};
-	i2s_pin_config_t pin_config = { .bck_io_num = I2S_BCK_IO, .ws_io_num =
-			I2S_WS_IO, .data_out_num = I2S_DO_IO, .data_in_num = I2S_DI_IO //Not used
-			};
-	i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
-	i2s_set_pin(I2S_NUM, &pin_config);
-	i2s_set_clk(I2S_NUM, output.current_sample_rate, i2s_config.bits_per_sample, 2);
-
-#if LINUX || OSX || FREEBSD || POSIX
-	pthread_attr_t attr;
-	pthread_attr_init(&attr);
-#ifdef PTHREAD_STACK_MIN
-	pthread_attr_setstacksize(&attr,
-			PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
-#endif
-	pthread_create(&thread, &attr, output_thread, NULL);
-	pthread_attr_destroy(&attr);
-#endif
-#if WIN
-	thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread, NULL, 0, NULL);
-#endif
-
-}
-
-void output_close_dac(void) {
-	LOG_INFO("close output");
-	LOCK;
-	running = false;
-	UNLOCK;
-
-	output_close_common();
-}
-
-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) {
-
-	u8_t *obuf;
-	size_t i2s_bytes_write = 0;
-
-	if (!silence) {
-
-		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;
-
-	} else {
-
-		obuf = silencebuf;
-	}
-
-	//_scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format);
-
-//	buffill += out_frames;
-	   i2s_write(I2S_NUM, obuf, out_frames  *BYTES_PER_FRAME, &i2s_bytes_write, 100);
-
-
-
-	return (int)i2s_bytes_write * BYTES_PER_FRAME;
-
-}
-

+ 119 - 0
main/output_embedded.c

@@ -0,0 +1,119 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.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/>.
+ *
+ */
+#include "squeezelite.h"
+
+extern struct outputstate output;
+extern struct buffer *outputbuf;
+
+#define FRAME_BLOCK MAX_SILENCE_FRAMES
+
+#define LOCK   mutex_lock(outputbuf->mutex)
+#define UNLOCK mutex_unlock(outputbuf->mutex)
+
+extern void set_volume_i2s(unsigned left, unsigned right);
+extern void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, 
+						  unsigned rates[], unsigned rate_delay, unsigned idle);
+extern void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, 
+						  unsigned rates[], unsigned rate_delay, unsigned idle);							  
+
+static log_level loglevel;
+
+static void (*volume_cb)(unsigned left, unsigned right);
+static void (*close_cb)(void);
+
+void output_init_embedded(log_level level, char *device, unsigned output_buf_size, char *params, 
+						  unsigned rates[], unsigned rate_delay, unsigned idle) {
+	loglevel = level;						
+	LOG_INFO("init device: %s", device);
+	
+	memset(&output, 0, sizeof(output));
+	output_init_common(level, device, output_buf_size, rates, idle);
+	output.start_frames =  FRAME_BLOCK;
+	output.rate_delay = rate_delay;
+	
+	if (strstr(device, "BT ")) {
+		LOG_INFO("init Bluetooth");
+		output_init_bt(level, device, output_buf_size, params, rates, rate_delay, idle);
+	} else {
+		LOG_INFO("init I2S");
+		//volume_cb = set_volume_i2s;
+		//close_cb = output_close_i2s;
+		//output_init_i2s(level, device, output_buf_size, params, rates, rate_delay, idle);
+	}	
+	
+	LOG_INFO("init completed.");
+}	
+
+void output_close_embedded(void) {
+	LOG_INFO("close output");
+	output_close_common();
+	if (close_cb) (*close_cb)();		
+}
+
+void set_volume(unsigned left, unsigned right) { 
+	LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
+	if (!volume_cb) {
+		LOCK;
+		output.gainL = left;
+		output.gainR = right;
+		UNLOCK;
+	} else (*volume_cb)(left, right); 	
+}
+
+bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
+	memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned));
+	if (!strcmp(device, "BT")) {
+		rates[0] = 44100;	
+	} else {
+		unsigned _rates[] = { 96000, 88200, 48000, 44100, 32000, 0 };	
+		memcpy(rates, _rates, sizeof(_rates));
+	}
+	return true;
+}
+
+char* output_state_str(void){
+	output_state state;
+	LOCK;
+	state = output.state;
+	UNLOCK;
+	switch (state) {
+	case OUTPUT_OFF: 			return STR(OUTPUT_OFF);
+	case OUTPUT_STOPPED:		return STR(OUTPUT_STOPPED);
+	case OUTPUT_BUFFER:			return STR(OUTPUT_BUFFER);
+	case OUTPUT_RUNNING:		return STR(OUTPUT_RUNNING);
+	case OUTPUT_PAUSE_FRAMES: 	return STR(OUTPUT_PAUSE_FRAMES);
+	case OUTPUT_SKIP_FRAMES:	return STR(OUTPUT_SKIP_FRAMES);
+	case OUTPUT_START_AT:		return STR(OUTPUT_START_AT);
+	default:					return "OUTPUT_UNKNOWN_STATE";
+	}
+}
+
+bool output_stopped(void) {
+	output_state state;
+	LOCK;
+	state = output.state;
+	UNLOCK;
+	return state <= OUTPUT_STOPPED;
+}	
+	
+
+
+

+ 1 - 6
main/slimproto.c

@@ -436,13 +436,8 @@ static void process_audg(u8_t *pkt, int len) {
 	audg->gainR = unpackN(&audg->gainR);
 
 	LOG_DEBUG("audg gainL: %u gainR: %u adjust: %u", audg->gainL, audg->gainR, audg->adjust);
-#if CONFIG_BTAUDIO
-	set_volume_bt(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE);
-#elif CONFIG_DACAUDIO
-	set_volume_dac(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE);
-#else
+
 	set_volume(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE);
-#endif
 }
 
 static void process_setd(u8_t *pkt, int len) {

+ 31 - 85
main/squeezelite.h

@@ -34,6 +34,7 @@
 #define VERSION "v" MAJOR_VERSION "." MINOR_VERSION "-" MICRO_VERSION
 #endif
 
+
 #if !defined(MODEL_NAME)
 #define MODEL_NAME SqueezeLite
 #endif
@@ -42,16 +43,11 @@
 #define STR(macro)  QUOTE(macro)
 #define MODEL_NAME_STRING STR(MODEL_NAME)
 
-#if defined(EMBEDDED)
-#define POSIX 1
-#include "embedded.h"
-#endif
-#ifndef PTHREAD_SET_NAME
-#define PTHREAD_SET_NAME(n)
-#endif
-
-// build detection
-#if defined(linux)
+// build detection 
+#if defined (EMBEDDED)
+#undef EMBEDDED
+#define EMBEDDED  1
+#elif defined(linux)
 #define LINUX     1
 #define OSX       0
 #define WIN       0
@@ -78,27 +74,19 @@
 #define PA18API   1
 #define OSX       0
 #define WIN       0
-#elif defined (POSIX)
-#undef POSIX
-#define POSIX 	  1
 #else
 #error unknown target
 #endif
 
-
-#if defined(CONFIG_DACAUDIO)
-#undef CONFIG_DACAUDIO
-#define CONFIG_DACAUDIO  1
-#elif defined(CONFIG_BTAUDIO)
-#undef CONFIG_BTAUDIO
-#define CONFIG_BTAUDIO 1
-#elif LINUX && !defined(PORTAUDIO)
+#if !EMBEDDED
+#if LINUX && !defined(PORTAUDIO)
 #define ALSA      1
 #define PORTAUDIO 0
 #else
 #define ALSA      0
 #define PORTAUDIO 1
 #endif
+#endif
 
 #if !defined(LOOPBACK)
 #if SUN
@@ -278,18 +266,18 @@
 #include <limits.h>
 #include <sys/types.h>
 
-#if LINUX || OSX || FREEBSD || POSIX
+#if EMBEDDED
+#include "embedded.h"
+#endif
+	
+#if LINUX || OSX || FREEBSD || EMBEDDED
 #include <unistd.h>
 #include <stdbool.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/time.h>
 #include <sys/socket.h>
-#if POSIX
 #include <sys/poll.h>
-#else
-#include <poll.h>
-#endif
 #if !LINKALL
 #include <dlfcn.h>
 #endif
@@ -299,14 +287,10 @@
 #include <sys/types.h>
 #endif /* SUN */
 
-#ifndef PTHREAD_STACK_MIN
-#define PTHREAD_STACK_MIN	256
-#endif
-
-#define STREAM_THREAD_STACK_SIZE  8 * 1024
-#define DECODE_THREAD_STACK_SIZE 20 * 1024
-#define OUTPUT_THREAD_STACK_SIZE  8 * 1024
-#define IR_THREAD_STACK_SIZE      8 * 1024
+#define STREAM_THREAD_STACK_SIZE  64 * 1024
+#define DECODE_THREAD_STACK_SIZE 128 * 1024
+#define OUTPUT_THREAD_STACK_SIZE  64 * 1024
+#define IR_THREAD_STACK_SIZE      64 * 1024
 #if !OSX
 #define thread_t pthread_t;
 #endif
@@ -314,13 +298,12 @@
 #define last_error() errno
 #define ERROR_WOULDBLOCK EWOULDBLOCK
 
+#if !EMBEDDED
 #ifdef SUN
 typedef uint8_t  u8_t;
 typedef uint16_t u16_t;
 typedef uint32_t u32_t;
 typedef uint64_t u64_t;
-#elif POSIX
-typedef unsigned long long u64_t;
 #else
 typedef u_int8_t  u8_t;
 typedef u_int16_t u16_t;
@@ -330,29 +313,20 @@ typedef u_int64_t u64_t;
 typedef int16_t   s16_t;
 typedef int32_t   s32_t;
 typedef int64_t   s64_t;
+#endif
 
 #define mutex_type pthread_mutex_t
 #define mutex_create(m) pthread_mutex_init(&m, NULL)
-#if POSIX
-#define mutex_create_p(m) mutex_create(m)
-#else
+#if HAS_MUTEX_CREATE_P
 #define mutex_create_p(m) pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); pthread_mutex_init(&m, &attr); pthread_mutexattr_destroy(&attr)
+#else
+#define mutex_create_p(m) mutex_create(m)
 #endif
 #define mutex_lock(m) pthread_mutex_lock(&m)
 #define mutex_unlock(m) pthread_mutex_unlock(&m)
 #define mutex_destroy(m) pthread_mutex_destroy(&m)
-#define mutex_broadcast_cond(m) pthread_cond_broadcast(&m)
-#define mutex_cond_wait(c,m) pthread_cond_wait(&c, &m)
-#define mutex_cond_init(c) pthread_cond_init(&c, NULL)
-#define thread_cond_type pthread_cond_t
 #define thread_type pthread_t
 #endif
-#ifdef EMBEDDED
-#define local_exit(r) {static int ret=r; pthread_exit(&ret);}
-#else
-#define local_exit(r) exit(r)
-#endif
-
 
 #if WIN
 
@@ -491,24 +465,7 @@ void logprint(const char *fmt, ...);
 #define LOG_INFO(fmt, ...)  if (loglevel >= lINFO)  logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #define LOG_DEBUG(fmt, ...) if (loglevel >= lDEBUG) logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #define LOG_SDEBUG(fmt, ...) if (loglevel >= lSDEBUG) logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-static inline void DEBUG_LOG_TIMED(uint32_t delayms, char * strFmt, ...)
-{
-	static log_level loglevel;
-	va_list args;
-	va_start(args, strFmt);
-	static uint32_t nextDebugLog=0;
-	if(esp_timer_get_time()>nextDebugLog)
-	{
-		if (loglevel >= lDEBUG)
-		{
-			logprint("%s %s:%d ", logtime(), __FUNCTION__, __LINE__);
-			logprint(strFmt , args);
-			logprint("\n");
-		}
-
-		nextDebugLog=esp_timer_get_time()+delayms*1000;
-	}
-}
+
 // utils.c (non logging)
 typedef enum { EVENT_TIMEOUT = 0, EVENT_READ, EVENT_WAKE } event_type;
 #if WIN && USE_SSL
@@ -670,8 +627,6 @@ typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE, U8, U16_LE, U16_BE, U32_LE, U32_
 #else
 typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE, S24_BE, S24_3BE, S16_BE, S8_BE } output_format;
 #endif
-extern uint8_t get_bytes_per_frame(output_format fmt);
-
 
 typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state;
 typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir;
@@ -763,26 +718,17 @@ void output_close_pa(void);
 void _pa_open(void);
 #endif
 
-// output_dac.c
-
-void set_volume_dac(unsigned left, unsigned right);
-bool test_open(const char *device, unsigned rates[], bool userdef_rates);
-void output_init_dac(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
-void output_close_dac(void);
-void hal_dac_init(const char * options);
-
-//output_bt.c
-void set_volume_bt(unsigned left, unsigned right);
+// output_embedded.c
+#if EMBEDDED
+void set_volume(unsigned left, unsigned right);
 bool test_open(const char *device, unsigned rates[], bool userdef_rates);
-void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
-void output_close_bt(void);
-extern void hal_bluetooth_init(const char * options);
-void output_bt_check_buffer();
-
-
+void output_init_embedded(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
+void output_close_embedded(void);
+#else 
 // output_stdout.c
 void output_init_stdout(log_level level, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay);
 void output_close_stdout(void);
+#endif
 
 // output_pack.c
 void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format);

+ 6 - 3
main/stream.c

@@ -373,7 +373,7 @@ void stream_init(log_level level, unsigned stream_buf_size) {
 	buf_init(streambuf, stream_buf_size);
 	if (streambuf->buf == NULL) {
 		LOG_ERROR("unable to malloc buffer");
-		local_exit(0);
+		exit(0);
 	}
 	
 #if USE_SSL
@@ -405,8 +405,8 @@ void stream_init(log_level level, unsigned stream_buf_size) {
 #if LINUX || FREEBSD
 	touch_memory(streambuf->buf, streambuf->size);
 #endif
-PTHREAD_SET_NAME("stream");
-#if LINUX || OSX || FREEBSD || POSIX
+
+#if LINUX || OSX || FREEBSD || EMBEDDED
 	pthread_attr_t attr;
 	pthread_attr_init(&attr);
 #ifdef PTHREAD_STACK_MIN	
@@ -414,6 +414,9 @@ PTHREAD_SET_NAME("stream");
 #endif
 	pthread_create(&thread, &attr, stream_thread, NULL);
 	pthread_attr_destroy(&attr);
+#if HAS_PTHREAD_SETNAME_NP	
+	pthread_setname_np(thread, "stream");
+#endif
 #endif
 #if WIN
 	thread = CreateThread(NULL, STREAM_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&stream_thread, NULL, 0, NULL);

+ 2 - 76
main/utils.c

@@ -21,7 +21,7 @@
 
 #include "squeezelite.h"
 
-#if LINUX || OSX || FREEBSD || POSIX
+#if LINUX || OSX || FREEBSD || EMBEDDED
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <netdb.h>
@@ -103,7 +103,7 @@ u32_t gettime_ms(void) {
 #if WIN
 	return GetTickCount();
 #else
-#if LINUX || FREEBSD || POSIX
+#if LINUX || FREEBSD || EMBEDDED
 	struct timespec ts;
 #ifdef CLOCK_MONOTONIC
 	if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
@@ -561,77 +561,3 @@ char *strcasestr(const char *haystack, const char *needle) {
 	return NULL;
 }
 #endif
-uint8_t get_bytes_per_frame(output_format fmt)
-{
-	uint8_t bpf=0;
-
-	switch (fmt) {
-		case S32_LE:
-			bpf=4*2;
-			break;
-		case S24_LE:
-			bpf=3*2;
-			break;
-		case S24_3LE:
-			bpf=3*2;
-			break;
-		case S16_LE:
-			bpf=2*2;
-			break;
-		case S24_BE:
-			bpf=3*2;
-			break;
-		case S24_3BE:
-			bpf=3*2;
-			break;
-		case S16_BE:
-			bpf=2*2;
-			break;
-		case S8_BE:
-			bpf=2*2;
-			break;
-#if DSD
-		case U8:
-			bpf=1*2;
-			break;
-		case U16_LE:
-			bpf=2*2;
-			break;
-		case U16_BE:
-			bpf=2*2;
-			break;
-		case U32_LE:
-			bpf=4*2;
-			break;
-		case U32_BE:
-			bpf=4*2;
-			break;
-#endif
-		default:
-			break;
-	}
-	assert(bpf>0);
-	return bpf;
-}
-
-char * get_output_state_desc(output_state state){
-	switch (state) {
-	case OUTPUT_OFF:
-		return STR(OUTPUT_OFF);
-	case OUTPUT_STOPPED:
-		return STR(OUTPUT_STOPPED);
-	case OUTPUT_BUFFER:
-		return STR(OUTPUT_BUFFER);
-	case OUTPUT_RUNNING:
-		return STR(OUTPUT_RUNNING);
-	case OUTPUT_PAUSE_FRAMES:
-		return STR(OUTPUT_PAUSE_FRAMES);
-	case OUTPUT_SKIP_FRAMES:
-		return STR(OUTPUT_SKIP_FRAMES);
-	case OUTPUT_START_AT:
-		return STR(OUTPUT_START_AT);
-	default:
-		return "OUTPUT_UNKNOWN_STATE";
-	}
-	return "";
-}