Forráskód Böngészése

Reworking BT output

Sebastien 4 éve
szülő
commit
8fbe1159f5

+ 3 - 7
CMakeLists.txt

@@ -1,15 +1,11 @@
 cmake_minimum_required(VERSION 3.5)
 set(EXTRA_COMPONENT_DIRS components/platform_console/app_recovery components/platform_console/app_squeezelite  )
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-add_definitions(-DbSqueezeESP32)
+add_definitions(-DMODEL_NAME=SqueezeESP32)
 message(STATUS  "Building RECOVERY")
 project(recovery)
 set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery )
-
 include(squeezelite.cmake)
-
-
 set(PROJECT_VER $ENV{PROJECT_VER})
-   
-#target_compile_definitions(__idf_squeezelite-ota PRIVATE DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE)
-#target_compile_definitions(__idf_driver_bt PRIVATE DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE)
+#target_compile_definitions(__idf_squeezelite-ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE)
+#target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG)

+ 2 - 19
build-scripts/ESP32-A1S-sdkconfig.defaults

@@ -180,13 +180,9 @@ CONFIG_BT_A2DP_ENABLE=y
 # CONFIG_BT_SPP_ENABLED is not set
 # CONFIG_BT_HFP_ENABLE is not set
 CONFIG_BT_SSP_ENABLED=y
-<<<<<<< HEAD
-# CONFIG_BT_BLE_ENABLED is not set
-CONFIG_BT_STACK_NO_LOG=y
-=======
 CONFIG_BT_BLE_ENABLED=n
 CONFIG_BT_BLE_SMP_ENABLE=y
-
+CONFIG_BT_STACK_NO_LOG=n
 
 
 
@@ -356,7 +352,6 @@ CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
 
 
 CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
->>>>>>> refs/remotes/origin/master
 CONFIG_BT_ACL_CONNECTIONS=4
 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
@@ -630,19 +625,7 @@ CONFIG_LWIP_MAX_SOCKETS=16
 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
 CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
-<<<<<<< HEAD
-# CONFIG_LWIP_SO_RCVBUF is not set
-# CONFIG_LWIP_IP_REASSEMBLY is not set
-# CONFIG_LWIP_IP_FRAG is not set
-# CONFIG_LWIP_STATS is not set
-# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
-=======
-CONFIG_LWIP_IP_REASSEMBLY=y
-
-
-
-
->>>>>>> refs/remotes/origin/master
+#CONFIG_LWIP_IP_REASSEMBLY is not set
 CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
 CONFIG_LWIP_GARP_TMR_INTERVAL=60
 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32

+ 2 - 188
build-scripts/I2S-4MFlash-sdkconfig.defaults

@@ -179,183 +179,10 @@ CONFIG_BT_A2DP_ENABLE=y
 # CONFIG_BT_SPP_ENABLED is not set
 # CONFIG_BT_HFP_ENABLE is not set
 CONFIG_BT_SSP_ENABLED=y
-<<<<<<< HEAD
 # CONFIG_BT_BLE_ENABLED is not set
-CONFIG_BT_STACK_NO_LOG=y
-=======
 CONFIG_BT_BLE_ENABLED=n
 CONFIG_BT_BLE_SMP_ENABLE=y
-
-
-
-
-CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_HID_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
->>>>>>> refs/remotes/origin/master
+CONFIG_BT_STACK_NO_LOG=n
 CONFIG_BT_ACL_CONNECTIONS=4
 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
@@ -507,11 +334,6 @@ CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40
 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
 CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12
-# CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set
-# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set
-
-
-
 
 CONFIG_ESP32_WIFI_NVS_ENABLED=y
 CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
@@ -633,19 +455,11 @@ CONFIG_LWIP_MAX_SOCKETS=16
 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
 CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
-<<<<<<< HEAD
 # CONFIG_LWIP_SO_RCVBUF is not set
 # CONFIG_LWIP_IP_FRAG is not set
-# CONFIG_LWIP_IP_REASSEMBLY is not set
+#CONFIG_LWIP_IP_REASSEMBLY is not set
 # CONFIG_LWIP_STATS is not set
 # CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
-=======
-CONFIG_LWIP_IP_REASSEMBLY=y
-
-
-
-
->>>>>>> refs/remotes/origin/master
 CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
 CONFIG_LWIP_GARP_TMR_INTERVAL=60
 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32

+ 2 - 187
build-scripts/SqueezeAmp-sdkconfig.defaults

@@ -180,183 +180,10 @@ CONFIG_BT_A2DP_ENABLE=y
 # CONFIG_BT_SPP_ENABLED is not set
 # CONFIG_BT_HFP_ENABLE is not set
 CONFIG_BT_SSP_ENABLED=y
-<<<<<<< HEAD
 # CONFIG_BT_BLE_ENABLED is not set
-CONFIG_BT_STACK_NO_LOG=y
-=======
+CONFIG_BT_STACK_NO_LOG=n
 CONFIG_BT_BLE_ENABLED=n
 CONFIG_BT_BLE_SMP_ENABLE=y
-
-
-
-
-CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_HCI_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTM_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_SDP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_GAP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_PAN_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_A2D_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_MCA_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_HID_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_APPL_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_GATT_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_SMP_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BTC_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_OSI_TRACE_LEVEL=2
-
-
-CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y
-
-
-
-
-CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2
->>>>>>> refs/remotes/origin/master
 CONFIG_BT_ACL_CONNECTIONS=4
 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
@@ -630,19 +457,7 @@ CONFIG_LWIP_MAX_SOCKETS=16
 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
 CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
-<<<<<<< HEAD
-# CONFIG_LWIP_SO_RCVBUF is not set
-# CONFIG_LWIP_IP_FRAG is not set
-# CONFIG_LWIP_IP_REASSEMBLY is not set
-# CONFIG_LWIP_STATS is not set
-# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
-=======
-CONFIG_LWIP_IP_REASSEMBLY=y
-
-
-
-
->>>>>>> refs/remotes/origin/master
+#CONFIG_LWIP_IP_REASSEMBLY is not set
 CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
 CONFIG_LWIP_GARP_TMR_INTERVAL=60
 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32

+ 0 - 1
components/driver_bt/bt_app_core.c

@@ -7,7 +7,6 @@
 */
 
 #include "bt_app_core.h"
-
 #include <stdint.h>
 #include "esp_system.h"
 #include <string.h>

+ 21 - 1
components/driver_bt/bt_app_core.h

@@ -15,9 +15,29 @@
 #include <stdio.h>
 
 #define BT_APP_CORE_TAG                   "BT_APP_CORE"
-
 #define BT_APP_SIG_WORK_DISPATCH          (0x01)
 
+/* A2DP global state */
+enum {
+    APP_AV_STATE_IDLE,
+    APP_AV_STATE_DISCOVERING,
+    APP_AV_STATE_DISCOVERED,
+    APP_AV_STATE_UNCONNECTED,
+    APP_AV_STATE_CONNECTING,
+    APP_AV_STATE_CONNECTED,
+    APP_AV_STATE_DISCONNECTING,
+};
+
+/* sub states of APP_AV_STATE_CONNECTED */
+enum {
+    APP_AV_MEDIA_STATE_IDLE,
+    APP_AV_MEDIA_STATE_STARTING,
+    APP_AV_MEDIA_STATE_STARTED,
+    APP_AV_MEDIA_STATE_STOPPING,
+	APP_AV_MEDIA_STATE_WAIT_DISCONNECT
+};
+extern int bt_app_source_get_a2d_state();
+extern int bt_app_source_get_media_state();
 /**
  * @brief     handler for the dispatched work
  */

+ 2 - 1
components/driver_bt/bt_app_sink.c

@@ -63,6 +63,7 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
 /* avrc TG event handler */
 static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
 static void volume_set_by_local_host(uint8_t volume);
+static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter);
 
 static const char *s_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
 static const char *s_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
@@ -378,7 +379,7 @@ static void bt_av_play_pos_changed(void)
     }
 }
 
-void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
+static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
 {
     switch (event_id) {
     case ESP_AVRC_RN_TRACK_CHANGE:

+ 565 - 219
components/driver_bt/bt_app_source.c

@@ -2,7 +2,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
-
 #include "bt_app_core.h"
 #include "esp_log.h"
 #include "esp_bt.h"
@@ -10,6 +9,7 @@
 #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"
@@ -18,40 +18,21 @@
 #include "argtable3/argtable3.h"
 #include "platform_config.h"
 #include "trace.h"
+#include "messaging.h"
+#include "cJSON.h"
 
 static const char * TAG = "bt_app_source";
-
+static const char * BT_RC_CT_TAG="RCCT";
 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",
-		"           ___  _____  _____     _____                            _           _ _ ",
-		"     /\\   |__ \\|  __ \\|  __ \\   / ____|                          | |         | | |",
-		"    /  \\     ) | |  | | |__) | | |     ___  _ __  _ __   ___  ___| |_ ___  __| | |",
-		"   / /\\ \\   / /| |  | |  ___/  | |    / _ \\| '_ \\| '_ \\ / _ \\/ __| __/ _ \\/ _` | |",
-		"  / ____ \\ / /_| |__| | |      | |___| (_) | | | | | | |  __/ (__| ||  __/ (_| |_|",
-		" /_/    \\_\\____|_____/|_|       \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__\\___|\\__,_(_)\n",
-		"\0"};
-static const char * art_a2dp_connecting[]= {"\n",
-		 "           ___  _____  _____     _____                            _   _                   ",
-		 "     /\\   |__ \\|  __ \\|  __ \\   / ____|                          | | (_)                  ",
-		 "    /  \\     ) | |  | | |__) | | |     ___  _ __  _ __   ___  ___| |_ _ _ __   __ _       ",
-		 "   / /\\ \\   / /| |  | |  ___/  | |    / _ \\| '_ \\| '_ \\ / _ \\/ __| __| | '_ \\ / _` |      ",
-		 "  / ____ \\ / /_| |__| | |      | |___| (_) | | | | | | |  __/ (__| |_| | | | | (_| |_ _ _ ",
-		 " /_/    \\_\\____|_____/|_|       \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__|_|_| |_|\\__, (_|_|_)",
-		 "                                                                               __/ |       ",
-		 "                                                                              |___/        \n",
-		 "\0"};
-
-static void bt_app_av_state_connecting(uint16_t event, void *param);
-
+extern void wifi_manager_update_status();
 
-#define IS_A2DP_TIMER_OVER esp_timer_get_time() >= connecting_timeout
+//int64_t connecting_timeout = 0;
 
+static void bt_app_av_state_connecting(uint16_t event, void *param);
 static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param);
 
 /* event for handler "bt_av_hdl_stack_up */
@@ -59,17 +40,6 @@ enum {
     BT_APP_EVT_STACK_UP = 0,
 };
 
-/* A2DP global state */
-enum {
-    APP_AV_STATE_IDLE,
-    APP_AV_STATE_DISCOVERING,
-    APP_AV_STATE_DISCOVERED,
-    APP_AV_STATE_UNCONNECTED,
-    APP_AV_STATE_CONNECTING,
-    APP_AV_STATE_CONNECTED,
-    APP_AV_STATE_DISCONNECTING,
-};
-
 char * APP_AV_STATE_DESC[] = {
 	    "APP_AV_STATE_IDLE",
 	    "APP_AV_STATE_DISCOVERING",
@@ -79,21 +49,23 @@ char * APP_AV_STATE_DESC[] = {
 	    "APP_AV_STATE_CONNECTED",
 	    "APP_AV_STATE_DISCONNECTING"
 };
-
-
-
-/* sub states of APP_AV_STATE_CONNECTED */
-
-enum {
-    APP_AV_MEDIA_STATE_IDLE,
-    APP_AV_MEDIA_STATE_STARTING,
-//	APP_AV_MEDIA_STATE_BUFFERING,
-    APP_AV_MEDIA_STATE_STARTED,
-    APP_AV_MEDIA_STATE_STOPPING,
-	APP_AV_MEDIA_STATE_WAIT_DISCONNECT
-};
+static char *  ESP_AVRC_CT_DESC[]={
+  "ESP_AVRC_CT_CONNECTION_STATE_EVT",
+  "ESP_AVRC_CT_PASSTHROUGH_RSP_EVT",
+  "ESP_AVRC_CT_METADATA_RSP_EVT",
+  "ESP_AVRC_CT_PLAY_STATUS_RSP_EVT",
+  "ESP_AVRC_CT_CHANGE_NOTIFY_EVT",
+  "ESP_AVRC_CT_REMOTE_FEATURES_EVT",
+  "ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT",
+  "ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT" 
+  };
 
 #define BT_APP_HEART_BEAT_EVT                (0xff00)
+// AVRCP used transaction label
+#define APP_RC_CT_TL_GET_CAPS            (0)
+#define APP_RC_CT_TL_RN_VOLUME_CHANGE    (1)
+#define PEERS_LIST_MAINTAIN_RESET -129
+#define PEERS_LIST_MAINTAIN_PURGE -129
 
 /// handler for bluetooth stack enabled events
 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
@@ -101,6 +73,12 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
 /// callback function for A2DP source
 static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
 
+/// callback function for AVRCP controller
+static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
+
+/// avrc CT event handler
+static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
+
 /// callback function for A2DP source audio data stream
 static void a2d_app_heart_beat(void *arg);
 
@@ -112,34 +90,145 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param);
 static void bt_app_av_state_connecting(uint16_t event, void *param);
 static void bt_app_av_state_connected(uint16_t event, void *param);
 static void bt_app_av_state_disconnecting(uint16_t event, void *param);
+static void handle_connect_state_unconnected(uint16_t event, esp_a2d_cb_param_t *param);
+static void handle_connect_state_connecting(uint16_t event, esp_a2d_cb_param_t *param);
+static void handle_connect_state_connected(uint16_t event, esp_a2d_cb_param_t *param);
+static void handle_connect_state_disconnecting(uint16_t event, esp_a2d_cb_param_t *param);
+static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter);
 
 static esp_bd_addr_t s_peer_bda = {0};
 static uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
-static int s_a2d_state = APP_AV_STATE_IDLE;
-static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
+int bt_app_source_a2d_state = APP_AV_STATE_IDLE;
+int bt_app_source_media_state = APP_AV_MEDIA_STATE_IDLE;
 static uint32_t s_pkt_cnt = 0;
-static TimerHandle_t s_tmr;
+static TimerHandle_t s_tmr=NULL;
+static int prev_duration=10000;
+static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
+static int s_connecting_intv = 0;
+cJSON * peers_list=NULL;
 
 static struct {
-	int control_delay;
-	int connect_timeout_delay;
+//	int control_delay;
+//	int connect_timeout_delay;
 	char * sink_name;
 } squeezelite_conf;	
 
+static cJSON * peers_list_get_entry(const char * s_peer_bdname){
+    cJSON * element=NULL;
+    cJSON_ArrayForEach(element,peers_list){
+        cJSON * name = cJSON_GetObjectItem(element,"name");
+        if(name && !strcmp(cJSON_GetStringValue(name),s_peer_bdname)){
+            ESP_LOGV(TAG,"Entry name %s found in current scan list", s_peer_bdname);
+            return element;
+        }
+    }
+    ESP_LOGV(TAG,"Entry name %s NOT found in current scan list", s_peer_bdname);
+    return NULL;
+}
+static void peers_list_reset(){
+    cJSON * element=NULL;
+    cJSON_ArrayForEach(element,peers_list){
+        cJSON * rssi = cJSON_GetObjectItem(element,"rssi");
+        if(rssi){
+            rssi->valuedouble = -129;
+            rssi->valueint = -129;
+        }
+    }
+}
+static void peers_list_purge(){
+    cJSON * element=NULL;
+    cJSON_ArrayForEach(element,peers_list){
+        cJSON * rssi_val = cJSON_GetObjectItem(element,"rssi");
+        if(rssi_val && rssi_val->valuedouble == -129){
+            cJSON * name = cJSON_GetObjectItem(element,"name");
+            ESP_LOGV(TAG,"Purging %s", cJSON_GetStringValue(name)?cJSON_GetStringValue(name):"Unknown");
+            cJSON_DetachItemViaPointer(peers_list,element);
+            cJSON_Delete(element);
+        }
+    }    
+}
+static cJSON * peers_list_create_entry(const char * s_peer_bdname, int32_t rssi){
+    cJSON * entry = cJSON_CreateObject();
+    cJSON_AddStringToObject(entry,"name",s_peer_bdname);
+    cJSON_AddNumberToObject(entry,"rssi",rssi);
+    return entry;
+}
+static void peers_list_update_add(const char * s_peer_bdname, int32_t rssi){
+    cJSON * element= peers_list_get_entry(s_peer_bdname);
+    if(element){
+        cJSON * rssi_val = cJSON_GetObjectItem(element,"rssi");
+        if(rssi_val && rssi_val->valuedouble != rssi){
+            ESP_LOGV(TAG,"Updating BT Sink Device: %s rssi to %i", s_peer_bdname,rssi);
+            rssi_val->valuedouble = rssi;
+            rssi_val->valueint = rssi;
+        }
+    }
+    else {
+        ESP_LOGI(TAG,"Found BT Sink Device: %s rssi is %i", s_peer_bdname,rssi);
+        element = peers_list_create_entry( s_peer_bdname,  rssi);
+        cJSON_AddItemToArray(peers_list,element);
+    }
+}
+static void peers_list_maintain(const char * s_peer_bdname, int32_t rssi){
+    if(!peers_list){
+        ESP_LOGV(TAG,"Initializing BT peers list");
+        peers_list=cJSON_CreateArray();
+    }
+    if(rssi==PEERS_LIST_MAINTAIN_RESET){
+        ESP_LOGV(TAG,"Resetting BT peers list");
+        peers_list_reset();
+    }
+    else if(rssi==PEERS_LIST_MAINTAIN_PURGE){
+        ESP_LOGV(TAG,"Purging BT peers list");
+        peers_list_purge();
+    }
+    if(s_peer_bdname) {
+        ESP_LOGV(TAG,"Adding/Updating peer %s rssi %i", s_peer_bdname,rssi);
+        peers_list_update_add(s_peer_bdname, rssi);
+    }
+    char * list_json = cJSON_Print(peers_list);
+    if(list_json){
+        messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_BT, list_json);
+        ESP_LOGV(TAG,"%s", list_json);
+        free(list_json);
+    }    
+}
+        
+int bt_app_source_get_a2d_state(){
+    ESP_LOGW(TAG,"a2dp status: %u = %s", bt_app_source_a2d_state, APP_AV_STATE_DESC[bt_app_source_a2d_state]);
+    return bt_app_source_a2d_state;
+}
+int bt_app_source_get_media_state(){
+    ESP_LOGW(TAG,"media state : %u ", bt_app_source_media_state);
+    return bt_app_source_media_state;
+}
+void set_app_source_state(int new_state){
+    if(bt_app_source_a2d_state!=new_state){
+        ESP_LOGD(TAG, "Updating state from %s to %s", APP_AV_STATE_DESC[bt_app_source_a2d_state], APP_AV_STATE_DESC[new_state]);
+        bt_app_source_a2d_state=new_state;
+        wifi_manager_update_status();
+    }
+}
+void set_a2dp_media_state(int new_state){
+    if(bt_app_source_media_state!=new_state){
+        bt_app_source_media_state=new_state;
+        wifi_manager_update_status();
+    }
+}
 void hal_bluetooth_init(const char * options)
 {
 	struct {
 		struct arg_str *sink_name;
-		struct arg_int *control_delay;
-		struct arg_int *connect_timeout_delay;
+//		struct arg_int *control_delay;
+//		struct arg_int *connect_timeout_delay;
 		struct arg_end *end;
 	} squeezelite_args;
 	
 	ESP_LOGD(TAG,"Initializing Bluetooth HAL");
 
-	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.sink_name = arg_str0("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");
@@ -163,30 +252,54 @@ void hal_bluetooth_init(const char * options)
 		free(argv);
 		return;
 	}
-	if(squeezelite_args.sink_name->count == 0)
-	{
-		squeezelite_conf.sink_name = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", CONFIG_A2DP_SINK_NAME, 0);
-    	if(squeezelite_conf.sink_name  == NULL){
-    		ESP_LOGW(TAG,"Unable to retrieve the a2dp sink name from nvs");
-    		squeezelite_conf.sink_name = strdup(CONFIG_A2DP_SINK_NAME);
-    	}
-	} else {
-		squeezelite_conf.sink_name=strdup(squeezelite_args.sink_name->sval[0]);
-	}
-	if(squeezelite_args.connect_timeout_delay->count == 0)
-	{
-		ESP_LOGD(TAG,"Using default connect timeout");
-		squeezelite_conf.connect_timeout_delay=CONFIG_A2DP_CONNECT_TIMEOUT_MS;
-	} else {
-		squeezelite_conf.connect_timeout_delay=squeezelite_args.connect_timeout_delay->ival[0];
-	}
-	if(squeezelite_args.control_delay->count == 0)
-	{
-		ESP_LOGD(TAG,"Using default control delay");
-		squeezelite_conf.control_delay=CONFIG_A2DP_CONTROL_DELAY_MS;
-	} else {
-		squeezelite_conf.control_delay=squeezelite_args.control_delay->ival[0];
-	}	
+
+    if(squeezelite_args.sink_name->count == 0)
+    {
+        squeezelite_conf.sink_name = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", NULL, 0);
+        if(!squeezelite_conf.sink_name  || strlen(squeezelite_conf.sink_name)==0 ){
+            ESP_LOGW(TAG,"Unable to retrieve the a2dp sink name from nvs.");
+        }
+    } else {
+        squeezelite_conf.sink_name=strdup(squeezelite_args.sink_name->sval[0]);
+        // sync with NVS
+        esp_err_t err=ESP_OK;
+        if((err= config_set_value(NVS_TYPE_STR, "a2dp_sink_name", squeezelite_args.sink_name->sval[0]))!=ESP_OK){
+            ESP_LOGE(TAG,"Error setting Bluetooth audio device name %s. %s",squeezelite_args.sink_name->sval[0], esp_err_to_name(err));
+        }
+        else {
+            ESP_LOGI(TAG,"Bluetooth audio device name changed to %s",squeezelite_args.sink_name->sval[0]);
+        }                
+    }
+
+
+	// if(squeezelite_args.connect_timeout_delay->count == 0)
+	// {
+	// 	ESP_LOGD(TAG,"Using default connect timeout");
+    //     char * p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctmt", NULL, 0);
+	//     if(p){
+    // 		squeezelite_conf.connect_timeout_delay=atoi(p);
+    //         free(p);
+    // 	}
+    //     else {
+    //         squeezelite_conf.connect_timeout_delay=CONFIG_A2DP_CONNECT_TIMEOUT_MS;
+    //     }
+	// } else {
+	// 	squeezelite_conf.connect_timeout_delay=squeezelite_args.connect_timeout_delay->ival[0];
+	// }
+	// if(squeezelite_args.control_delay->count == 0)
+	// {
+	// 	ESP_LOGD(TAG,"Using default control delay");
+    //     char * p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctrld", NULL, 0);
+	//     if(p){
+    // 		squeezelite_conf.control_delay=atoi(p);
+    //         free(p);
+    // 	}
+    //     else {
+    //         squeezelite_conf.control_delay=CONFIG_A2DP_CONNECT_TIMEOUT_MS;
+    //     }
+	// } else {
+	// 	squeezelite_conf.control_delay=squeezelite_args.control_delay->ival[0];
+	// }	
 	ESP_LOGD(TAG,"Freeing options");
 	free(argv);
 	free(opts);
@@ -259,7 +372,41 @@ 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);
 }
-
+static void handle_bt_gap_pin_req(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param){
+    char * pin_str = config_alloc_get_default(NVS_TYPE_STR, "a2dp_spin", "0000", 0);
+    int pinlen=pin_str?strlen(pin_str):0;
+    if (pin_str && ((!param->pin_req.min_16_digit && pinlen==4) || (param->pin_req.min_16_digit && pinlen==16)))  {
+        ESP_LOGI(TAG,"Input pin code %s: ",pin_str);
+        esp_bt_pin_code_t pin_code;
+        for (size_t i = 0; i < pinlen; i++)
+        {
+            pin_code[i] = pin_str[i];
+        }
+        esp_bt_gap_pin_reply(param->pin_req.bda, true, pinlen, pin_code);
+    }
+    else {
+        if(pinlen>0){
+            ESP_LOGW(TAG,"Pin length: %u does not match the length expected by the device: %u", pinlen, ((param->pin_req.min_16_digit)?16:4));
+        }
+        else {
+            ESP_LOGW(TAG, "No security Pin provided. Trying with default pins.");
+        }
+        if (param->pin_req.min_16_digit) {
+            ESP_LOGI(TAG,"Input pin code: 0000 0000 0000 0000");
+            esp_bt_pin_code_t pin_code = {0};
+            esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
+        } else {
+            ESP_LOGI(TAG,"Input pin code: 1234");
+            esp_bt_pin_code_t pin_code;
+            pin_code[0] = '1';
+            pin_code[1] = '2';
+            pin_code[2] = '3';
+            pin_code[3] = '4';
+            esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
+        }            
+    }
+    FREE_AND_NULL(pin_str);
+}
 static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
 {
 
@@ -271,10 +418,11 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
     case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
         if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED)
         {
-            if (s_a2d_state == APP_AV_STATE_DISCOVERED)
+            peers_list_maintain(NULL, PEERS_LIST_MAINTAIN_PURGE);
+            if (bt_app_source_a2d_state == APP_AV_STATE_DISCOVERED)
             {
             	ESP_LOGI(TAG,"Discovery completed.  Ready to start connecting to %s. ",s_peer_bdname);
-            	s_a2d_state = APP_AV_STATE_UNCONNECTED;
+            	set_app_source_state(APP_AV_STATE_UNCONNECTED);
             }
             else
             {
@@ -285,6 +433,7 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
         }
         else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
             ESP_LOGI(TAG,"Discovery started.");
+            peers_list_maintain(NULL, PEERS_LIST_MAINTAIN_RESET);
         }
         else
         {
@@ -307,23 +456,9 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
         }
         break;
     }
-    case ESP_BT_GAP_PIN_REQ_EVT: {
-    	ESP_LOGI(TAG,"ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
-        if (param->pin_req.min_16_digit) {
-            ESP_LOGI(TAG,"Input pin code: 0000 0000 0000 0000");
-            esp_bt_pin_code_t pin_code = {0};
-            esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
-        } else {
-            ESP_LOGI(TAG,"Input pin code: 1234");
-            esp_bt_pin_code_t pin_code;
-            pin_code[0] = '1';
-            pin_code[1] = '2';
-            pin_code[2] = '3';
-            pin_code[3] = '4';
-            esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
-        }
+    case ESP_BT_GAP_PIN_REQ_EVT: 
+        handle_bt_gap_pin_req(event, param);
         break;
-    }
 
 #if (CONFIG_BT_SSP_ENABLED == true)
     case ESP_BT_GAP_CFM_REQ_EVT:
@@ -344,20 +479,179 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
     }
     return;
 }
+int heart_beat_delay[] = {
+    1000,
+    1000,
+    1000,
+    1000,
+    10000,
+    500,
+    1000
+};
 
 static void a2d_app_heart_beat(void *arg)
 {
     bt_app_work_dispatch(bt_app_av_sm_hdlr, BT_APP_HEART_BEAT_EVT, NULL, 0, NULL);
+    int tmrduration=heart_beat_delay[bt_app_source_a2d_state];
+    if(prev_duration!=tmrduration){
+        xTimerChangePeriod(s_tmr,tmrduration, portMAX_DELAY);
+        ESP_LOGD(TAG,"New heartbeat is %u",tmrduration);
+        prev_duration=tmrduration;
+    }
+    else {
+        ESP_LOGD(TAG,"Starting Heart beat timer for %ums",tmrduration);
+    }
+    xTimerStart(s_tmr, portMAX_DELAY);
+}
+
+static const char * conn_state_str(esp_a2d_connection_state_t state){
+    char * statestr = "Unknown";
+     switch (state)
+        {
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTED:
+            statestr=STR(ESP_A2D_CONNECTION_STATE_DISCONNECTED);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTING:
+            statestr=STR(ESP_A2D_CONNECTION_STATE_CONNECTING);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTED:
+            statestr=STR(ESP_A2D_CONNECTION_STATE_CONNECTED);
+            break;
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTING:
+            statestr=STR(ESP_A2D_CONNECTION_STATE_DISCONNECTING);
+            break;
+        default:
+            break;
+        }
+    return statestr;
+}
+static void unexpected_connection_state(int from, esp_a2d_connection_state_t to)
+{
+    ESP_LOGW(TAG,"Unexpected connection state change. App State: %s (%u) Connection State %s (%u)", APP_AV_STATE_DESC[from], from,conn_state_str(to), to);
+}
+static void handle_connect_state_unconnected(uint16_t event, esp_a2d_cb_param_t *param){
+    ESP_LOGV(TAG, "A2DP Event while unconnected ");
+    switch (param->conn_stat.state)
+    {
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTED:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTED:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            ESP_LOGE(TAG,"Connection state event received while status was unconnected.  Routing message to connecting state handler. State : %u",param->conn_stat.state);
+            if (param->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
+                handle_connect_state_connecting(event, param);
+            }
+        break;
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            break;
+        default:
+            break;
+    }
+
+}
+static void handle_connect_state_connecting(uint16_t event, esp_a2d_cb_param_t *param){
+    ESP_LOGV(TAG, "A2DP connection state event : %s ",conn_state_str(param->conn_stat.state));
+    //    a2d = (esp_a2d_cb_param_t *)(param);
+    //     if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
+    //         ESP_LOGI(BT_AV_TAG, "a2dp connected");
+    //         s_a2d_state =  APP_AV_STATE_CONNECTED;
+    //         s_media_state = APP_AV_MEDIA_STATE_IDLE;
+    //         esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
+    //     } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
+    //         s_a2d_state =  APP_AV_STATE_UNCONNECTED;
+    //     }    
+    switch (param->conn_stat.state)
+    {
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTED:
+            if(param->conn_stat.disc_rsn!=ESP_A2D_DISC_RSN_NORMAL){
+                ESP_LOGE(TAG,"A2DP had an abnormal disconnect event");
+            }
+            else {
+                ESP_LOGW(TAG,"A2DP connect unsuccessful");
+            }
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTING: {
+            break;
+        }
+        case ESP_A2D_CONNECTION_STATE_CONNECTED:
+            set_app_source_state(APP_AV_STATE_CONNECTED);
+            set_a2dp_media_state(APP_AV_MEDIA_STATE_IDLE);
+            ESP_LOGD(TAG,"Setting scan mode to ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE");
+            esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
+            ESP_LOGD(TAG,"Done setting scan mode. App state is now CONNECTED and media state IDLE.");
+            break;
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state); 
+            set_app_source_state(APP_AV_STATE_DISCONNECTING);       
+            break;
+        default:
+            break;
+    }
+}
+static void handle_connect_state_connected(uint16_t event, esp_a2d_cb_param_t *param){
+    ESP_LOGV(TAG, "A2DP Event while connected ");
+    switch (param->conn_stat.state)
+    {
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTED:
+            ESP_LOGW(TAG,"a2dp disconnected");
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
+            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);  
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTED:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            break;
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTING:
+            set_app_source_state(APP_AV_STATE_DISCONNECTING);        
+
+            break;
+        default:
+            break;
+    }
+}
+
+static void handle_connect_state_disconnecting(uint16_t event, esp_a2d_cb_param_t *param){
+    ESP_LOGV(TAG, "A2DP Event while disconnecting ");
+    switch (param->conn_stat.state)
+    {
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTED:
+            ESP_LOGI(TAG,"a2dp disconnected");
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
+            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);        
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);  
+            break;
+        case ESP_A2D_CONNECTION_STATE_CONNECTED:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);  
+            break;
+        case ESP_A2D_CONNECTION_STATE_DISCONNECTING:
+            unexpected_connection_state(bt_app_source_a2d_state, param->conn_stat.state);
+            break;
+        default:
+            break;
+    }
+
 }
 
 static void bt_app_av_sm_hdlr(uint16_t event, void *param)
 {
-    switch (s_a2d_state) {
+    ESP_LOGV(TAG,"bt_app_av_sm_hdlr.%s a2d state: %s", event==BT_APP_HEART_BEAT_EVT?"Heart Beat.":"",APP_AV_STATE_DESC[bt_app_source_a2d_state]);
+    switch (bt_app_source_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, output_state_str());
+    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[bt_app_source_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, output_state_str());
+    	ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[bt_app_source_a2d_state], event, output_state_str());
         break;
     case APP_AV_STATE_UNCONNECTED:
         bt_app_av_state_unconnected(event, param);
@@ -372,7 +666,7 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param)
         bt_app_av_state_disconnecting(event, param);
         break;
     default:
-        ESP_LOGE(TAG,"%s invalid state %d", __func__, s_a2d_state);
+        ESP_LOGE(TAG,"%s invalid state %d", __func__, bt_app_source_a2d_state);
         break;
     }
 }
@@ -428,7 +722,8 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     uint8_t *eir = NULL;
     uint8_t nameLen = 0;
     esp_bt_gap_dev_prop_t *p;
-    if(s_a2d_state != APP_AV_STATE_DISCOVERING)
+    memset(bda_str, 0x00, sizeof(bda_str));
+    if(bt_app_source_a2d_state != APP_AV_STATE_DISCOVERING)
     {
     	// Ignore messages that might have been queued already
     	// when we've discovered the target device.
@@ -436,27 +731,29 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     }
     memset(s_peer_bdname, 0x00,sizeof(s_peer_bdname));
 
-    ESP_LOGI(TAG,"\n=======================\nScanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
+    bda2str(param->disc_res.bda, bda_str, 18);
+
+    ESP_LOGV(TAG,"\n=======================\nScanned device: %s",bda_str );
     for (int i = 0; i < param->disc_res.num_prop; i++) {
         p = param->disc_res.prop + i;
         switch (p->type) {
         case ESP_BT_GAP_DEV_PROP_COD:
             cod = *(uint32_t *)(p->val);
-            ESP_LOGI(TAG,"-- Class of Device: 0x%x", cod);
+            ESP_LOGV(TAG,"-- Class of Device: 0x%x", cod);
             break;
         case ESP_BT_GAP_DEV_PROP_RSSI:
             rssi = *(int8_t *)(p->val);
-            ESP_LOGI(TAG,"-- RSSI: %d", rssi);
+            ESP_LOGV(TAG,"-- RSSI: %d", rssi);
             break;
         case ESP_BT_GAP_DEV_PROP_EIR:
             eir = (uint8_t *)(p->val);
-            ESP_LOGI(TAG,"-- EIR: %u", *eir);
+            ESP_LOGV(TAG,"-- EIR: %u", *eir);
             break;
         case ESP_BT_GAP_DEV_PROP_BDNAME:
             nameLen = (p->len > ESP_BT_GAP_MAX_BDNAME_LEN) ? ESP_BT_GAP_MAX_BDNAME_LEN : (uint8_t)p->len;
             memcpy(s_peer_bdname, (uint8_t *)(p->val), nameLen);
             s_peer_bdname[nameLen] = '\0';
-            ESP_LOGI(TAG,"-- Name: %s", s_peer_bdname);
+            ESP_LOGV(TAG,"-- Name: %s", s_peer_bdname);
             break;
         default:
             break;
@@ -464,31 +761,34 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     }
     if (!esp_bt_gap_is_valid_cod(cod)){
     /* search for device with MAJOR service class as "rendering" in COD */
-    	ESP_LOGI(TAG,"--Invalid class of device. Skipping.\n");
+    	ESP_LOGV(TAG,"--Invalid class of device. Skipping.\n");
     	return;
     }
     else if (!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING))
     {
-    	ESP_LOGI(TAG,"--Not a rendering device. Skipping.\n");
+    	ESP_LOGV(TAG,"--Not a rendering device. Skipping.\n");
     	return;
     }
 
 
     /* search for device named "ESP_SPEAKER" in its extended inqury response */
     if (eir) {
-    	ESP_LOGI(TAG,"--Getting details from eir.\n");
+    	ESP_LOGV(TAG,"--Getting details from eir.\n");
         get_name_from_eir(eir, s_peer_bdname, NULL);
-        ESP_LOGI(TAG,"--Device name is %s\n",s_peer_bdname);
+        ESP_LOGV(TAG,"--Device name is %s\n",s_peer_bdname);
+    }
+    if(strlen((char *)s_peer_bdname)>0) {
+        peers_list_maintain((const char *)s_peer_bdname, rssi);    
     }
 
-    if (strcmp((char *)s_peer_bdname, squeezelite_conf.sink_name) == 0) {
-    	ESP_LOGI(TAG,"Found a target device! address %s, name %s", bda_str, s_peer_bdname);
-    	ESP_LOGI(TAG,"=======================\n");
+    if (squeezelite_conf.sink_name && strlen(squeezelite_conf.sink_name) >0 && strcmp((char *)s_peer_bdname, squeezelite_conf.sink_name) == 0) {
+        ESP_LOGI(TAG,"Found our target device. address %s, name %s", bda_str, s_peer_bdname);
+    	ESP_LOGV(TAG,"=======================\n");
         if(esp_bt_gap_cancel_discovery()!=ESP_ERR_INVALID_STATE)
         {
-        	ESP_LOGI(TAG,"Cancel device discovery ...");
+        	ESP_LOGD(TAG,"Cancel device discovery ...");
 			memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
-        	s_a2d_state = APP_AV_STATE_DISCOVERED;
+            set_app_source_state(APP_AV_STATE_DISCOVERED);
         }
         else
         {
@@ -497,7 +797,7 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     }
     else
     {
-    	ESP_LOGI(TAG,"Not the device we are looking for (%s). Continuing scan", squeezelite_conf.sink_name);
+    	ESP_LOGV(TAG,"Not the device we are looking for (%s). Continuing scan", squeezelite_conf.sink_name?squeezelite_conf.sink_name:"N/A");
     }
 }
 
@@ -525,6 +825,15 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
         /* register GAP callback function */
         esp_bt_gap_register_callback(bt_app_gap_cb);
 
+        /* initialize AVRCP controller */
+        esp_avrc_ct_init();
+        esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
+
+        esp_avrc_rn_evt_cap_mask_t evt_set = {0};
+        esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
+        assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
+
+
         /* initialize A2DP source */
         esp_a2d_register_callback(&bt_app_a2d_cb);
         esp_a2d_source_register_data_callback(&output_bt_data);
@@ -535,24 +844,13 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
 
         /* start device discovery */
         ESP_LOGI(TAG,"Starting device discovery...");
-        s_a2d_state = APP_AV_STATE_DISCOVERING;
+        set_app_source_state(APP_AV_STATE_DISCOVERING);
         esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
 
         /* create and start heart beat timer */
-        do {
-            int tmr_id = 0;
-            uint16_t ctr_delay_ms=CONFIG_A2DP_CONTROL_DELAY_MS;
-            char * value = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctrld", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS), 0);
-			if(value!=NULL){
-				ESP_LOGI(TAG,  "A2DP ctrl delay: %s", value);
-				ctr_delay_ms=atoi(value);
-			}
-			FREE_AND_NULL(value);
-
-            s_tmr = xTimerCreate("connTmr", ( ctr_delay_ms/ portTICK_RATE_MS),
-                               pdTRUE, (void *)tmr_id, a2d_app_heart_beat);
-            xTimerStart(s_tmr, portMAX_DELAY);
-        } while (0);
+        int tmr_id = 0;
+        s_tmr = xTimerCreate("connTmr", ( prev_duration/ portTICK_RATE_MS),pdFALSE, (void *)tmr_id, a2d_app_heart_beat);        
+        xTimerStart(s_tmr, portMAX_DELAY);
         break;
     }
     default:
@@ -560,11 +858,29 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
         break;
     }
 }
-
+static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
+{
+    switch (event) {
+    case ESP_AVRC_CT_METADATA_RSP_EVT:
+    case ESP_AVRC_CT_CONNECTION_STATE_EVT:
+    case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
+    case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
+    case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
+    case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
+    case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
+        ESP_LOGD(TAG,"Received %s message", ESP_AVRC_CT_DESC[event]);
+        bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
+        break;
+    }
+    default:
+        ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event);
+        break;
+    }
+}
 static void bt_app_av_media_proc(uint16_t event, void *param)
 {
     esp_a2d_cb_param_t *a2d = NULL;
-    switch (s_media_state) {
+    switch (bt_app_source_media_state) {
     case APP_AV_MEDIA_STATE_IDLE: {
     	if (event == BT_APP_HEART_BEAT_EVT) {
             if(!output_stopped())
@@ -579,7 +895,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
 					a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS
 					) {
 				ESP_LOGI(TAG,"a2dp media ready, starting playback!");
-				s_media_state = APP_AV_MEDIA_STATE_STARTING;
+				set_a2dp_media_state(APP_AV_MEDIA_STATE_STARTING);
 				esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
 			}
         }
@@ -592,11 +908,11 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
             if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
                     a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
             	ESP_LOGI(TAG,"a2dp media started successfully.");
-                s_media_state = APP_AV_MEDIA_STATE_STARTED;
+                set_a2dp_media_state(APP_AV_MEDIA_STATE_STARTED);
             } else {
                 // not started succesfully, transfer to idle state
             	ESP_LOGI(TAG,"a2dp media start failed.");
-                s_media_state = APP_AV_MEDIA_STATE_IDLE;
+                set_a2dp_media_state(APP_AV_MEDIA_STATE_IDLE);
             }
         }
         break;
@@ -605,7 +921,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
         if (event == BT_APP_HEART_BEAT_EVT) {
         	if(output_stopped()) {
         		ESP_LOGI(TAG,"Output state is %s. Stopping a2dp media ...", output_state_str());
-                s_media_state = APP_AV_MEDIA_STATE_STOPPING;
+                set_a2dp_media_state(APP_AV_MEDIA_STATE_STOPPING);
                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
             } else {
 				output_bt_tick();	
@@ -620,7 +936,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_IDLE;
+               	set_a2dp_media_state(APP_AV_MEDIA_STATE_IDLE);
             } else {
                 ESP_LOGI(TAG,"a2dp media stopping...");
                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
@@ -631,7 +947,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
 
     case APP_AV_MEDIA_STATE_WAIT_DISCONNECT:{
     	esp_a2d_source_disconnect(s_peer_bda);
-		s_a2d_state = APP_AV_STATE_DISCONNECTING;
+		set_app_source_state(APP_AV_STATE_DISCONNECTING);
 		ESP_LOGI(TAG,"a2dp disconnecting...");
     }
     }
@@ -639,17 +955,10 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
 
 static void bt_app_av_state_unconnected(uint16_t event, void *param)
 {
+    ESP_LOGV(TAG, "Handling state unconnected A2DP event");
 	switch (event) {
     case ESP_A2D_CONNECTION_STATE_EVT:
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_CONNECTION_STATE_EVT));
-    	// this could happen if connection was established
-    	// right after we timed out. Pass the call down to the connecting
-    	// handler.
-    	esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param);
-    	if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
-    		bt_app_av_state_connecting(event, param);
-    	}
-
+        handle_connect_state_unconnected(event, (esp_a2d_cb_param_t *)param);
     	break;
     case ESP_A2D_AUDIO_STATE_EVT:
     	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_STATE_EVT));
@@ -662,6 +971,7 @@ 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: {
+        ESP_LOG_DEBUG_EVENT(TAG,QUOTE(BT_APP_HEART_BEAT_EVT));
         switch (esp_bluedroid_get_status()) {
 		case ESP_BLUEDROID_STATUS_UNINITIALIZED:
 			ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_UNINITIALIZED.");
@@ -675,23 +985,14 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
 		default:
 			break;
 		}
-		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);
-		int64_t connecting_timeout_offset=CONFIG_A2DP_CONNECT_TIMEOUT_MS;
-		if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {
-			char * value = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS), 0);
-			if(value!=NULL){
-				ESP_LOGI(TAG,  "A2DP pairing timeout: %s", value);
-				connecting_timeout_offset=atoi(value);
-			}
-			FREE_AND_NULL(value);
-
-			connecting_timeout = esp_timer_get_time() +(connecting_timeout_offset * 1000);
-			s_a2d_state = APP_AV_STATE_CONNECTING;
+        uint8_t *p = s_peer_bda;
+        ESP_LOGI(TAG, "a2dp connecting to %s, BT peer: %02x:%02x:%02x:%02x:%02x:%02x",s_peer_bdname,p[0], p[1], p[2], p[3], p[4], p[5]);
+        if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {  
+            set_app_source_state(APP_AV_STATE_CONNECTING);
+            s_connecting_intv = 0;
 		}
 		else {
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
 			// 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);
@@ -706,26 +1007,10 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
 
 static void bt_app_av_state_connecting(uint16_t event, void *param)
 {
-    esp_a2d_cb_param_t *a2d = NULL;
-
     switch (event) {
-    case ESP_A2D_CONNECTION_STATE_EVT: {
-        a2d = (esp_a2d_cb_param_t *)(param);
-        if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
-            s_a2d_state =  APP_AV_STATE_CONNECTED;
-            s_media_state = APP_AV_MEDIA_STATE_IDLE;
-
-			ESP_LOGD(TAG,"Setting scan mode to ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE");
-            esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
-            ESP_LOGD(TAG,"Done setting scan mode. App state is now CONNECTED and media state IDLE.");
-			for(uint8_t l=0;art_a2dp_connected[l][0]!='\0';l++){
-				ESP_LOGI(TAG,"%s",art_a2dp_connected[l]);
-			}
-        } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
-            s_a2d_state =  APP_AV_STATE_UNCONNECTED;
-        }
+    case ESP_A2D_CONNECTION_STATE_EVT:
+        handle_connect_state_connecting(event, (esp_a2d_cb_param_t *)param);
         break;
-    }
     case ESP_A2D_AUDIO_STATE_EVT:
     	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_STATE_EVT));
     	break;
@@ -736,12 +1021,11 @@ static void bt_app_av_state_connecting(uint16_t event, void *param)
     	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_MEDIA_CTRL_ACK_EVT));
     	break;
     case BT_APP_HEART_BEAT_EVT:
-    	if (IS_A2DP_TIMER_OVER)
-    	{
-            s_a2d_state = APP_AV_STATE_UNCONNECTED;
+        if (++s_connecting_intv >= 2) {
+            set_app_source_state(APP_AV_STATE_UNCONNECTED);
             ESP_LOGW(TAG,"A2DP Connect time out!  Setting state to Unconnected. ");
+            s_connecting_intv = 0;
         }
-    	ESP_LOGV(TAG,"BT_APP_HEART_BEAT_EVT");
         break;
     default:
         ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
@@ -755,12 +1039,7 @@ static void bt_app_av_state_connected(uint16_t event, void *param)
     esp_a2d_cb_param_t *a2d = NULL;
     switch (event) {
     case ESP_A2D_CONNECTION_STATE_EVT: {
-    	a2d = (esp_a2d_cb_param_t *)(param);
-        if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
-            ESP_LOGI(TAG,"a2dp disconnected");
-            s_a2d_state = APP_AV_STATE_UNCONNECTED;
-            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
-        }
+        handle_connect_state_connected(event, (esp_a2d_cb_param_t *)param);
         break;
     }
     case ESP_A2D_AUDIO_STATE_EVT: {
@@ -793,32 +1072,99 @@ static void bt_app_av_state_connected(uint16_t event, void *param)
 
 static void bt_app_av_state_disconnecting(uint16_t event, void *param)
 {
-    esp_a2d_cb_param_t *a2d = NULL;
     switch (event) {
-    case ESP_A2D_CONNECTION_STATE_EVT: {
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_CONNECTION_STATE_EVT));
-        a2d = (esp_a2d_cb_param_t *)(param);
-        if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
-            ESP_LOGI(TAG,"a2dp disconnected");
-            s_a2d_state =  APP_AV_STATE_UNCONNECTED;
-            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+        case ESP_A2D_CONNECTION_STATE_EVT: 
+            handle_connect_state_disconnecting( event, (esp_a2d_cb_param_t *)param);
+            break;
+        case ESP_A2D_AUDIO_STATE_EVT:
+            ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_STATE_EVT));
+            break;
+        case ESP_A2D_AUDIO_CFG_EVT:
+            ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_CFG_EVT));
+            break;
+        case ESP_A2D_MEDIA_CTRL_ACK_EVT:
+            ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_MEDIA_CTRL_ACK_EVT));
+            break;
+        case BT_APP_HEART_BEAT_EVT:
+            ESP_LOG_DEBUG_EVENT(TAG,QUOTE(BT_APP_HEART_BEAT_EVT));
+            break;
+        default:
+            ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
+            break;
         }
+}
+
+static void bt_av_volume_changed(void)
+{
+    if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
+                                           ESP_AVRC_RN_VOLUME_CHANGE)) {
+        esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, ESP_AVRC_RN_VOLUME_CHANGE, 0);
+    }
+}
+
+static void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
+{
+    switch (event_id) {
+    case ESP_AVRC_RN_VOLUME_CHANGE:
+        ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
+        ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5);
+        esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5);
+        bt_av_volume_changed();
         break;
     }
-    case ESP_A2D_AUDIO_STATE_EVT:
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_STATE_EVT));
-    	break;
-    case ESP_A2D_AUDIO_CFG_EVT:
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_AUDIO_CFG_EVT));
-    	break;
-    case ESP_A2D_MEDIA_CTRL_ACK_EVT:
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_MEDIA_CTRL_ACK_EVT));
-    	break;
-    case BT_APP_HEART_BEAT_EVT:
-    	ESP_LOG_DEBUG_EVENT(TAG,QUOTE(BT_APP_HEART_BEAT_EVT));
-    	break;
+}
+static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
+{
+    ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event);
+    esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
+    switch (event) {
+    case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
+        uint8_t *bda = rc->conn_stat.remote_bda;
+        ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
+                 rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+        if (rc->conn_stat.connected) {
+            // get remote supported event_ids of peer AVRCP Target
+            esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
+        } else {
+            // clear peer notification capability record
+            s_avrc_peer_rn_cap.bits = 0;
+        }
+        break;
+    }
+    case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
+        break;
+    }
+    case ESP_AVRC_CT_METADATA_RSP_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
+        free(rc->meta_rsp.attr_text);
+        break;
+    }
+    case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
+        bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
+        break;
+    }
+    case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag);
+        break;
+    }
+    case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count,
+                 rc->get_rn_caps_rsp.evt_set.bits);
+        s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
+
+        bt_av_volume_changed();
+        break;
+    }
+    case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
+        ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume rsp: volume %d", rc->set_volume_rsp.volume);
+        break;
+    }
+
     default:
-        ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
+        ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event);
         break;
     }
 }

+ 279 - 2
components/platform_console/cmd_config.c

@@ -23,6 +23,7 @@ const char * desc_squeezelite ="Squeezelite Options";
 const char * desc_dac= "DAC Options";
 const char * desc_spdif= "SPDIF Options";
 const char * desc_audio= "General Audio Options";
+const char * desc_bt_source= "Bluetooth Audio Output Options";
 
 
 #define CODECS_BASE "flac|pcm|mp3|ogg"
@@ -59,7 +60,14 @@ const char * desc_audio= "General Audio Options";
 #define CODECS CODECS_BASE CODECS_AAC CODECS_FF CODECS_DSD CODECS_MP3
 #define NOT_OUTPUT "has input capabilities only"
 #define NOT_GPIO "is not a GPIO"
-
+typedef enum {
+    SEARCHING_FOR_BT,
+    SEARCHING_FOR_NAME,
+    SEARCHING_FOR_NAME_START,
+    SEARCHING_FOR_NAME_END,
+    SEARCHING_FOR_BT_CMD_END,
+    FINISHING
+} parse_state_t;
 static const char *TAG = "cmd_config";
 extern struct arg_end *getParmsEnd(struct arg_hdr * * argtable);
 //bck=<gpio>,ws=<gpio>,do=<gpio>[,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|AC101|I2S][,sda=<gpio>,scl=gpio[,i2c=<addr>]]
@@ -76,6 +84,15 @@ static struct {
 	struct arg_lit *clear;
     struct arg_end *end;
 } i2s_args;
+
+static struct{
+		struct arg_str *sink_name;
+		struct arg_str *pin_code;
+//		struct arg_dbl *connect_timeout_delay;
+//		struct arg_dbl *control_delay;
+		struct arg_end *end;
+} bt_source_args;
+
 static struct {
     struct arg_int *clock;
     struct arg_int *wordselect;
@@ -155,7 +172,224 @@ int check_missing_parm(struct arg_int * int_parm, FILE * f){
 	} 
 	return res;
 }
-	
+char * strip_bt_name(char * opt_str)
+{
+    char *result = malloc(strlen(opt_str)+1);
+    memset(result, 0x00, strlen(opt_str)+1);
+    char *str = strdup(opt_str);
+    const char * output_marker=" -o";
+    
+    if(!result ){
+        ESP_LOGE(TAG,"Error allocating memory for result.");
+        return opt_str;
+    }
+    if(!str){
+        ESP_LOGE(TAG,"Error duplicating command line string.");
+        return opt_str;
+    }	
+    bool quoted=false;
+    parse_state_t state = SEARCHING_FOR_BT;
+    char *start = strstr(str, output_marker);
+    if (start)
+    { 
+        ESP_LOGV(TAG,"Found output option : %s\n",start);
+        start+=strlen(output_marker);
+        strncpy(result, str, (size_t)(start - str));
+        char * pch=strtok(start," ");
+        while(pch){
+            ESP_LOGV(TAG,"Current output: %s\n[%s]",result,pch);
+            switch (state)
+            {
+                case SEARCHING_FOR_BT:
+                    if (strcasestr(pch, "BT") )
+                    {
+                        state = SEARCHING_FOR_NAME;
+                        quoted=strcasestr(pch, "BT")!=NULL;
+                        ESP_LOGV(TAG," - fount BT Start %s", quoted?"quoted":"");
+                    }
+                    else
+                    {
+                        ESP_LOGV(TAG," - Searching for BT, Ignoring");
+                    }
+                    strcat(result, " ");
+                    strcat(result, pch);
+                    break;
+                case SEARCHING_FOR_NAME:
+                    if (strcasestr(pch, "name") || strcasestr(pch, "n"))
+                    {
+                        ESP_LOGV(TAG," - Found name tag");
+                        state = SEARCHING_FOR_NAME_START;
+                    }
+                    else
+                    {
+                        strcat(result, " ");
+                        strcat(result, pch);
+                        ESP_LOGV(TAG," - Searching for name - added ");;
+                    }
+                    break;
+                case SEARCHING_FOR_NAME_START:
+                    ESP_LOGV(TAG," - Name start");
+                    state = SEARCHING_FOR_NAME_END;
+                break;
+                case SEARCHING_FOR_NAME_END:
+                    if (strcasestr(pch, "\"")){
+                        ESP_LOGV(TAG," - got quoted string");
+                        state = FINISHING;
+                    } 
+                    else if(pch[0]== '-'){
+                        strcat(result, " ");
+                        strcat(result, pch);
+                        ESP_LOGV(TAG," - got parameter marker");
+                        state = quoted?SEARCHING_FOR_BT_CMD_END:FINISHING;
+                    }
+                    else {
+                        ESP_LOGV(TAG," - name continued");
+                    }
+                    break;
+                case SEARCHING_FOR_BT_CMD_END:
+                    ESP_LOGV(TAG," - looking for quoted BT cmd end");
+                    if (strcasestr(pch, "\"")){
+                        ESP_LOGV(TAG," - got quote termination");
+                        state = FINISHING;
+                    } 
+                    strcat(result, " ");
+                    strcat(result, pch);
+                    break;
+                case FINISHING:
+                    strcat(result, " ");
+                    strcat(result, pch);
+                    break;
+                default:
+    
+                    break;
+            }
+            pch = strtok(NULL, " ");
+            ESP_LOGV(TAG,"\n");
+        }
+      
+    }
+    else
+    {
+        ESP_LOGE(TAG,"output option not found in %s\n",str);
+        strcpy(result,str);
+    }
+
+    ESP_LOGV(TAG,"Result commmand : %s\n", result);
+    free(str);
+    return result;
+}
+
+static int do_bt_source_cmd(int argc, char **argv){
+	esp_err_t err=ESP_OK;
+	int nerrors = arg_parse(argc, argv,(void **)&bt_source_args);
+	char *buf = NULL;
+	size_t buf_size = 0;
+//	char value[100] ={0};
+	FILE *f = open_memstream(&buf, &buf_size);
+	if (f == NULL) {
+		cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
+		return 1;
+	}
+	if(nerrors >0){
+		arg_print_errors(f,bt_source_args.end,desc_bt_source);
+		return 1;
+	}
+
+	if(bt_source_args.sink_name->count >0){
+		err = config_set_value(NVS_TYPE_STR, "a2dp_sink_name", bt_source_args.sink_name->sval[0]);
+		if(err!=ESP_OK){
+            nerrors++;
+            fprintf(f,"Error setting Bluetooth audio device name %s. %s\n",bt_source_args.sink_name->sval[0], esp_err_to_name(err));
+        }
+        else {
+            fprintf(f,"Bluetooth audio device name changed to %s\n",bt_source_args.sink_name->sval[0]);
+        }        
+		char * squeezelite_cmd = config_alloc_get_default(NVS_TYPE_STR, "autoexec1", NULL, 0);
+		if( squeezelite_cmd && strstr(squeezelite_cmd," -o ") ){
+			char * new_cmd = strip_bt_name(squeezelite_cmd);
+			if(strcmp(new_cmd,squeezelite_cmd)!=0){
+				fprintf(f,"Replacing old squeezelite command [%s] with [%s].\n",squeezelite_cmd,new_cmd);
+				config_set_value(NVS_TYPE_STR, "autoexec1", new_cmd);
+				if(err!=ESP_OK){
+					nerrors++;
+					fprintf(f,"Error updating squeezelite command line options . %s\n", esp_err_to_name(err));
+				}			
+			}
+			free(squeezelite_cmd);
+			free(new_cmd);
+		}
+
+	}
+	if(bt_source_args.pin_code->count >0){
+		const char * v=bt_source_args.pin_code->sval[0];
+		bool bInvalid=false;
+		for(int i=0;i<strlen(v) && !bInvalid;i++){
+			if(v[i]<'0' || v[i]>'9'){
+				bInvalid=true;
+			}
+		}
+		if(bInvalid || strlen(bt_source_args.pin_code->sval[0])>16 || strlen(bt_source_args.pin_code->sval[0])<4){
+            nerrors++;
+            fprintf(f,"Pin code %s invalid. Should be numbers only with length between 4 and 16 characters. \n",bt_source_args.pin_code->sval[0]);
+		}
+		else {
+			err = config_set_value(NVS_TYPE_STR, "a2dp_spin", bt_source_args.pin_code->sval[0]);
+			if(err!=ESP_OK){
+				nerrors++;
+				fprintf(f,"Error setting Bluetooth source pin to %s. %s\n",bt_source_args.pin_code->sval[0], esp_err_to_name(err));
+			}
+			else {
+				fprintf(f,"Bluetooth source pin changed to %s\n",bt_source_args.pin_code->sval[0]);
+			}        
+		}
+	}	
+	// if(bt_source_args.connect_timeout_delay->count >0){
+		
+	// 	snprintf(value,sizeof(value),"%d",(int)(bt_source_args.connect_timeout_delay->dval[0]*1000.0));
+	// 	if(bt_source_args.connect_timeout_delay->dval[0] <0.5 || bt_source_args.connect_timeout_delay->dval[0] >5.0){
+	// 		nerrors++;
+	// 		fprintf(f,"Invalid connection timeout %0.0f (%s milliseconds). Value must be between 0.5 sec and 5 sec.\n", bt_source_args.connect_timeout_delay->dval[0], value );
+	// 	}
+	// 	else {
+	// 		err = config_set_value(NVS_TYPE_STR, "a2dp_ctmt", value);
+	// 		if(err!=ESP_OK){
+	// 			nerrors++;
+	// 			fprintf(f,"Error setting connection timeout %0.0f sec (%s milliseconds). %s\n", bt_source_args.connect_timeout_delay->dval[0],value, esp_err_to_name(err));
+	// 		}
+	// 		else {
+	// 			fprintf(f,"Connection timeout changed to %0.0f sec (%s milliseconds)\n",bt_source_args.connect_timeout_delay->dval[0],value);
+	// 		}     
+	// 	}   
+	// }
+
+	// if(bt_source_args.control_delay->count >0){
+	// 	snprintf(value,sizeof(value),"%d",(int)(bt_source_args.control_delay->dval[0]*1000.0));
+	// 	if(bt_source_args.control_delay->dval[0] <0.1 || bt_source_args.control_delay->dval[0] >2.0){
+	// 		nerrors++;
+	// 		fprintf(f,"Invalid control delay %0.0f (%s milliseconds). Value must be between 0.1s and 2s.\n", bt_source_args.control_delay->dval[0], value );
+	// 	}
+	// 	else {
+	// 		err = config_set_value(NVS_TYPE_STR, "a2dp_ctrld", value);
+	// 		if(err!=ESP_OK){
+	// 			nerrors++;
+	// 			fprintf(f,"Error setting control delay to %0.0f sec (%s milliseconds). %s\n",bt_source_args.control_delay->dval[0],value, esp_err_to_name(err));
+	// 		}
+	// 		else {
+	// 			fprintf(f,"Control delay changed to %0.0f sec (%s milliseconds)\n",bt_source_args.control_delay->dval[0],value);
+	// 		}     
+	// 	}   
+	// }
+
+	if(!nerrors ){
+		fprintf(f,"Done.\n");
+	}
+	fflush (f);
+	cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
+	fclose(f);
+	FREE_AND_NULL(buf);
+	return (nerrors==0 && err==ESP_OK)?0:1;
+
+}
 static int do_audio_cmd(int argc, char **argv){
 	esp_err_t err=ESP_OK;
 	int nerrors = arg_parse(argc, argv,(void **)&audio_args);
@@ -399,6 +633,30 @@ cJSON * audio_cb(){
     FREE_AND_NULL(p);    
 	return values;
 }
+cJSON * bt_source_cb(){
+	cJSON * values = cJSON_CreateObject();
+	char * 	p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_sink_name", NULL, 0);
+	if(p){
+		cJSON_AddStringToObject(values,"sink_name",p);
+	}
+	FREE_AND_NULL(p);    
+	// p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctmt", NULL, 0);
+	// if(p){
+	// 	cJSON_AddNumberToObject(values,"connect_timeout_delay",((double)atoi(p)/1000.0));
+	// }
+	// FREE_AND_NULL(p);   
+	p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_spin", "0000", 0);
+	if(p){
+		cJSON_AddStringToObject(values,"pin_code",p);
+	}
+	FREE_AND_NULL(p);   
+	// p = config_alloc_get_default(NVS_TYPE_STR, "a2dp_ctrld", NULL, 0);
+	// if(p){
+	// 	cJSON_AddNumberToObject(values,"control_delay",((double)atoi(p)/1000.0));
+	// }
+	// FREE_AND_NULL(p);   
+	return values;
+}
 
 
 void get_str_parm_json(struct arg_str * parm, cJSON * entry){
@@ -541,6 +799,24 @@ static void register_i2s_config(void){
     ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
 }
 
+static void register_bt_source_config(void){
+	
+	bt_source_args.sink_name= arg_str1("n","sink_name", "name","Bluetooth audio device name. This applies when output mode is Bluetooth");
+	bt_source_args.pin_code= arg_str1("p","pin_code", "pin","Bluetooth security/pin code. Usually 0000. This applies when output mode is Bluetooth");
+//	bt_source_args.control_delay= arg_dbl0("d","control_delay","seconds","Control response delay, in seconds. This determines the response time of the system Bluetooth events. The default value should work for the majority of cases and changing this could lead to instabilities.");
+//	bt_source_args.connect_timeout_delay= arg_dbl0("t","connect_timeout_delay","seconds","Connection timeout. Determines the maximum amount of time, in seconds, that the system will wait when connecting to a bluetooth device. Beyond this delay, a new connect attempt will be made.");
+	bt_source_args.end= arg_end(1);
+	const esp_console_cmd_t cmd = {
+        .command = CFG_TYPE_AUDIO("bt_source"),
+        .help = desc_bt_source,
+        .hint = NULL,
+        .func = &do_bt_source_cmd,
+        .argtable = &bt_source_args
+    };
+    cmd_to_json_with_cb(&cmd,&bt_source_cb);
+    ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
+}
+
 
 static void register_audio_config(void){
 	audio_args.jack_behavior = arg_str0("j", "jack_behavior","Headphones|Subwoofer","On supported DAC, determines the audio jack behavior. Selecting headphones will cause the external amp to be muted on insert, while selecting Subwoofer will keep the amp active all the time.");
@@ -616,6 +892,7 @@ static void register_squeezelite_config(void){
 void register_config_cmd(void){
 	register_audio_config();
 //	register_squeezelite_config();
+	register_bt_source_config();
 	register_i2s_config();
 	register_spdif_config();
 }

+ 3 - 0
components/platform_console/cmd_system.c

@@ -33,7 +33,10 @@
 #include "platform_console.h"
 #include "trace.h"
 #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+#pragma message("Runtime stats enabled")
 #define WITH_TASKS_INFO 1
+#else 
+#pragma message("Runtime stats disabled")
 #endif
 static struct {
 	struct arg_str *scanmode;

+ 3 - 0
components/services/battery.c

@@ -40,6 +40,8 @@ static struct {
 	.cells = 2,
 };	
 
+extern void wifi_manager_update_status();
+
 /****************************************************************************************
  * 
  */
@@ -64,6 +66,7 @@ static void battery_callback(TimerHandle_t xTimer) {
 		battery.avg = battery.sum / battery.count;
 		battery.sum = battery.count = 0;
 		ESP_LOGI(TAG, "Voltage %.2fV", battery.avg);
+		wifi_manager_update_status();
 	}	
 }
 

+ 2 - 1
components/services/messaging.h

@@ -12,7 +12,8 @@ typedef enum {
 	MESSAGING_CLASS_OTA,
 	MESSAGING_CLASS_SYSTEM,
 	MESSAGING_CLASS_STATS,
-	MESSAGING_CLASS_CFGCMD
+	MESSAGING_CLASS_CFGCMD,
+	MESSAGING_CLASS_BT
 } messaging_classes;
 
 typedef struct messaging_list_t *messaging_handle_t;

+ 9 - 0
components/services/monitor.c

@@ -41,11 +41,14 @@ bool jack_inserted_svc(void);
 void (*spkfault_handler_svc)(bool inserted);
 bool spkfault_svc(void);
 
+extern void wifi_manager_update_status();
+
 /****************************************************************************************
  * 
  */
 static void task_stats( cJSON* top ) {
 #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY 
+#pragma message("Compiled with trace facility")
 	static struct {
 		TaskStatus_t *tasks;
 		uint32_t total, n;
@@ -60,6 +63,7 @@ static void task_stats( cJSON* top ) {
 	*scratch = '\0';
 
 #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+#pragma message("Compiled with runtime stats")
 	uint32_t elapsed = current.total - previous.total;
     
 	for(int i = 0, n = 0; i < current.n; i++ ) {
@@ -87,6 +91,8 @@ static void task_stats( cJSON* top ) {
 		}
 	}	
 #else
+#pragma message("Compiled WITHOUT runtime stats")
+
 	for (int i = 0, n = 0; i < current.n; i ++) {
 		n += sprintf(scratch + n, "%16s s:%5u\t", current.tasks[i].pcTaskName, current.tasks[i].usStackHighWaterMark);
 		cJSON * t=cJSON_CreateObject();
@@ -106,6 +112,8 @@ static void task_stats( cJSON* top ) {
 	cJSON_AddItemToObject(top,"tasks",tlist);
 	if (previous.tasks) free(previous.tasks);
 	previous = current;
+#else 
+#pragma message("Compiled WITHOUT trace facility")	
 #endif	
 }
  
@@ -140,6 +148,7 @@ static void monitor_callback(TimerHandle_t xTimer) {
 static void jack_handler_default(void *id, button_event_e event, button_press_e mode, bool long_press) {
 	ESP_LOGD(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed");
 	messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_SYSTEM,"jack is %s",BUTTON_PRESSED ? "inserted" : "removed");
+	wifi_manager_update_status();
 	if (jack_handler_svc) (*jack_handler_svc)(event == BUTTON_PRESSED);
 }
 

+ 1 - 1
components/squeezelite/output_embedded.c

@@ -78,7 +78,7 @@ void output_init_embedded(log_level level, char *device, unsigned output_buf_siz
 	output.start_frames = FRAME_BLOCK;
 	output.rate_delay = rate_delay;
 	
-	if (strcasestr(device, "BT ")) {
+	if (strcasestr(device, "BT ") || !strcasecmp(device, "BT")) {
 		LOG_INFO("init Bluetooth");
 		close_cb = &output_close_bt;
 		output_init_bt(level, device, output_buf_size, params, rates, rate_delay, idle);

+ 1 - 1
components/wifi-manager/CMakeLists.txt

@@ -1,7 +1,7 @@
 idf_component_register( SRC_DIRS .
 						INCLUDE_DIRS . ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32  ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/
 						REQUIRES squeezelite-ota json mdns 
-						PRIV_REQUIRES tools services platform_config esp_common json newlib freertos  spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console   
+						PRIV_REQUIRES tools services platform_config esp_common json newlib freertos  spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console   driver_bt
 						EMBED_FILES res/style.css.gz res/code.js.gz index.html res/bootstrap.css.gz res/yeti/bootstrap.css.gz res/jquery.js.gz res/bootstrap.js.gz res/favicon.ico
 						
 )

+ 2 - 2
components/wifi-manager/http_server_handlers.c

@@ -548,7 +548,7 @@ esp_err_t ap_get_handler(httpd_req_t *req){
     }
     /* if we can get the mutex, write the last version of the AP list */
 	esp_err_t err = set_content_type_from_req(req);
-	if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 10)){
+	if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){
 		char *buff = wifi_manager_alloc_get_ap_list_json();
 		wifi_manager_unlock_json_buffer();
 		if(buff!=NULL){
@@ -1168,7 +1168,7 @@ esp_err_t status_get_handler(httpd_req_t *req){
 		return err;
 	}
 
-	if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
+	if(wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) {
 		char *buff = wifi_manager_alloc_get_ip_info_json();
 		wifi_manager_unlock_json_buffer();
 		if(buff) {

+ 3 - 7
components/wifi-manager/index.development.html

@@ -20,21 +20,18 @@
 					<path d="m 16.074253,15.636738 v -1.05413 h 5.893274 c 1.16249,0 2.108261,-0.855111 2.108261,-1.906183 0,-1.051073 -0.945771,-1.906236 -2.108261,-1.906236 H 16.074253 V 9.7160604 c 0,-0.5812492 -0.472879,-1.0541321 -1.054131,-1.0541321 H 6.7847349 c -1.256731,0 -2.301908,0.9212057 -2.496867,2.1237027 h -0.451896 c -0.540407,0 -1.001317,0.349129 -1.173459,0.835611 H 0.47312787 c -0.23285,0 -0.42164599,0.188794 -0.42164599,0.421651 v 1.251779 c 0,0.232857 0.18879599,0.421652 0.42164599,0.421652 H 2.6550809 c 0.165919,0.497866 0.632365,0.857588 1.180831,0.857588 h 0.45312 c 0.19781,1.199177 1.241345,2.116956 2.495659,2.116956 h 8.2353861 c 0.581297,0 1.054176,-0.472883 1.054176,-1.05413 z m 5.060935,-4.023245 v 2.125811 h -0.844935 v -2.125811 z m 2.097293,1.062932 c 0,0.582933 -0.561524,1.057661 -1.253986,1.062668 v -2.125337 c 0.692462,0.0049 1.253986,0.47963 1.253986,1.062669 z m -3.785535,-1.062932 v 2.125811 h -3.372693 v -2.125811 z m -18.55215712,0.851 H 2.5901939 v 0.408475 H 0.89478888 Z m 2.94118302,1.266114 c -0.221897,0 -0.40247,-0.185737 -0.40247,-0.414062 v -1.273547 c 0,-0.228271 0.180573,-0.41401 0.40247,-0.41401 h 0.418855 v 2.101671 h -0.418855 z m 2.948763,2.116956 c -0.929997,0 -1.6866,-0.756601 -1.6866,-1.686608 v -0.0087 -2.944976 -0.01545 c 0,-0.930006 0.756603,-1.6866072 1.6866,-1.6866072 h 8.2353871 c 0.114313,0 0.210838,0.096554 0.210838,0.2108266 v 5.9206786 c 0,0.114268 -0.09656,0.210824 -0.210838,0.210824 z" />
 				</g>
 			</svg>
-			<svg xmlns="http://www.w3.org/2000/svg" id="output" width="24" height="24" viewBox="0 0 24 24">
+			<span data-toggle="tooltip" id="o_type" data-placement="top" title=""><svg xmlns="http://www.w3.org/2000/svg" id="output" width="24" height="24" viewBox="0 0 24 24">
 				<g id="o_i2s" display="none">
 					<path d="M2 7L2 8L2 9L2 10L2 11L2 12L2 13L2 14L2 15L2 16L2 17L3 17L3 16L3 15L3 14L3 13L3 12L3 11L3 10L3 9L3 8L2 7M6 7L6 8L6 9L7 9L7 8L8 8L9 8L10 8L10 9L11 9L11 10L11 11L10 11L10 12L9 12L9 13L8 13L8 14L7 14L7 15L6 15L6 16L6 17L7 17L8 17L9 17L10 17L11 17L12 17L12 16L11 16L10 16L9 16L8 16L8 15L9 15L9 14L10 14L10 13L11 13L11 12L12 12L12 11L12 10L12 9L12 8L11 8L11 7L10 7L9 7L8 7L6 7M16 7L16 8L15 8L15 9L15 10L15 11L16 11L16 12L17 12L18 12L18 13L19 13L20 13L21 13L21 14L21 15L20 15L20 16L19 16L18 16L17 16L16 16L16 15L15 15L15 16L15 17L16 17L17 17L18 17L19 17L20 17L21 17L21 16L22 16L22 15L22 14L22 13L21 13L21 12L20 12L20 11L19 11L18 11L17 11L16 11L16 10L16 9L17 9L17 8L18 8L19 8L20 8L21 8L21 9L22 9L22 8L22 7L21 7L20 7L19 7L18 7L16 7z"/>
 				</g>
-				<g id="o_bt" display="none">
-					<path d="M3 7L3 8L3 9L3 10L3 11L3 12L3 13L3 14L3 15L3 16L3 17L4 17L5 17L6 17L7 17L8 17L9 17L9 16L10 16L10 15L10 14L10 13L10 12L9 12L9 11L10 11L10 10L10 9L10 8L9 8L9 7L8 7L7 7L6 7L5 7L3 7M12 7L12 8L13 8L14 8L15 8L16 8L16 9L16 10L16 11L16 12L16 13L16 14L16 15L16 16L16 17L17 17L17 16L17 15L17 14L17 13L17 12L17 11L17 10L17 9L17 8L18 8L19 8L20 8L21 8L21 7L20 7L19 7L18 7L17 7L16 7L15 7L14 7L12 7z"/>
-					<path style="fill:#272B30;" d="M4 8L4 9L4 10L4 11L5 11L6 11L7 11L8 11L8 10L9 10L9 9L9 8L8 8L7 8L6 8L4 8M4 12L4 13L4 14L4 15L4 16L5 16L6 16L7 16L8 16L8 15L9 15L9 14L9 13L8 13L8 12L7 12L6 12L4 12z"/>
-				</g>
+				<g id="o_bt" stroke="currentColor" stroke-width="1" fill="none" fill-rule="evenodd" display="none"></g>
 				<g id="o_spdif" display="none">
 					<path d="M3 1L3 2L2 2L2 3L2 4L2 5L3 5L3 6L4 6L5 6L5 7L6 7L7 7L8 7L8 8L8 9L7 9L7 10L6 10L5 10L4 10L3 10L3 9L2 9L2 10L2 11L3 11L4 11L5 11L6 11L7 11L8 11L8 10L9 10L9 9L9 8L9 7L8 7L8 6L7 6L7 5L6 5L5 5L4 5L3 5L3 4L3 3L4 3L4 2L5 2L6 2L7 2L8 2L8 3L9 3L9 2L9 1L8 1L7 1L6 1L5 1L3 1M13 1L13 2L13 3L13 4L12 4L12 5L12 6L12 7L12 8L11 8L11 9L11 10L11 11L10 11L10 12L10 13L11 13L11 12L11 11L12 11L12 10L12 9L12 8L13 8L13 7L13 6L13 5L14 5L14 4L14 3L14 2L15 2L15 1L13 1M16 1L16 2L16 3L16 4L16 5L16 6L16 7L16 8L16 9L16 10L16 11L17 11L17 10L17 9L17 8L17 7L18 7L19 7L20 7L21 7L21 6L22 6L22 5L22 4L22 3L22 2L21 2L21 1L20 1L19 1L18 1L16 1z"/>
 					<path style="fill:#272B30;" d="M17 2L17 3L17 4L17 5L17 6L18 6L19 6L20 6L20 5L21 5L21 4L21 3L20 3L20 2L19 2L17 2z"/>
 					<path d="M2 13L2 14L2 15L2 16L2 17L2 18L2 19L2 20L2 21L2 22L2 23L3 23L4 23L5 23L6 23L7 23L8 23L8 22L9 22L9 21L10 21L10 20L10 19L10 18L10 17L10 16L10 15L9 15L9 14L8 14L7 14L7 13L6 13L5 13L4 13L2 13M13 13L13 14L13 15L13 16L13 17L13 18L13 19L13 20L13 21L13 22L13 23L14 23L14 22L14 21L14 20L14 19L14 18L14 17L14 16L14 15L14 14L13 13M17 13L17 14L17 15L17 16L17 17L17 18L17 19L17 20L17 21L17 22L17 23L18 23L18 22L18 21L18 20L18 19L18 18L19 18L20 18L21 18L22 18L22 17L21 17L20 17L19 17L18 17L18 16L18 15L18 14L19 14L20 14L21 14L22 14L22 13L21 13L20 13L19 13L17 13z"/>
 					<path style="fill:#272B30;" d="M3 14L3 15L3 16L3 17L3 18L3 19L3 20L3 21L3 22L4 22L5 22L6 22L7 22L7 21L8 21L8 20L9 20L9 19L9 18L9 17L9 16L8 16L8 15L7 15L7 14L6 14L5 14L3 14z"/>
 				</g>
-			</svg>
+			</svg></span>
 			<svg xmlns="http://www.w3.org/2000/svg" id="battery" width="24" height="24" viewBox="0 0 24 24">
 				<g id="bat0" display="none">
 					<path d="M19 8v8h-17v-8h17zm2-2h-21v12h21v-12zm1 9h.75c.69 0 1.25-.56 1.25-1.25v-3.5c0-.69-.56-1.25-1.25-1.25h-.75v6z"/>
@@ -322,7 +319,6 @@
 											</div>
 										</fieldset>
 										<div class="form-group"><label for="player">Player Name</label><input type="text" class="form-control " placeholder="Squeezelite" id="player" ></div>
-										<div class="form-group" style="display: none;"><label for="btsinkdiv">Bluetooth Speaker Name To Connect To</label><input type="text" class="form-control" id="btsinkdiv" ></div>
 										<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP address)</label><input type="text" class="form-control"  id="optional" ></div>
 										<div class="form-group"><div class="form-check">
 											<label class="form-check-label">

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
components/wifi-manager/index.html


+ 52 - 20
components/wifi-manager/res/code.js

@@ -41,6 +41,31 @@ var nvs_type_t = {
 	/*!< Type blob */
 	NVS_TYPE_ANY: 0xff /*!< Must be last */
 };
+var bt_icons = {
+	'bt_playing':'<path d="M15.98,10.28 L14.6,11.66 C14.4,11.86 14.4,12.17 14.6,12.37 L15.98,13.75 C16.26,14.03 16.73,13.9 16.83,13.52 C16.94,13.02 17,12.52 17,12 C17,11.49 16.94,10.99 16.82,10.52 C16.73,10.14 16.26,10 15.98,10.28 Z M20.1,7.78 C19.85,7.23 19.12,7.11 18.7,7.54 C18.44,7.8 18.39,8.18 18.53,8.52 C18.99,9.59 19.25,10.76 19.25,11.99 C19.25,13.23 18.99,14.41 18.52,15.48 C18.38,15.8 18.43,16.17 18.68,16.42 C19.09,16.83 19.78,16.71 20.03,16.19 C20.66,14.89 21.01,13.43 21.01,11.89 C21,10.44 20.68,9.04 20.1,7.78 Z M11.39,12 L14.98,8.42 C15.37,8.03 15.37,7.4 14.98,7 L10.69,2.71 C10.06,2.08 8.98,2.53 8.98,3.42 L8.98,9.6 L5.09,5.7 C4.7,5.31 4.07,5.31 3.68,5.7 C3.29,6.09 3.29,6.72 3.68,7.11 L8.57,12 L3.68,16.89 C3.29,17.28 3.29,17.91 3.68,18.3 C4.07,18.69 4.7,18.69 5.09,18.3 L8.98,14.41 L8.98,20.59 C8.98,21.48 10.06,21.93 10.69,21.3 L14.99,17 C15.38,16.61 15.38,15.98 14.99,15.58 L11.39,12 Z M10.98,5.83 L12.86,7.71 L10.98,9.59 L10.98,5.83 Z M10.98,18.17 L10.98,14.41 L12.86,16.29 L10.98,18.17 Z" id="🔹-Icon-Color" fill="#1D1D1D"></path>',
+	'bt_disconnected':'<path d="M13.41,12l3.8-3.79a1,1,0,0,0,0-1.42l-4.5-4.5a1,1,0,0,0-.33-.21,1,1,0,0,0-.76,0,1,1,0,0,0-.54.54A1,1,0,0,0,11,3V9.59L8.21,6.79A1,1,0,1,0,6.79,8.21L10.59,12l-3.8,3.79a1,1,0,1,0,1.42,1.42L11,14.41V21a1,1,0,0,0,.08.38,1,1,0,0,0,.54.54.94.94,0,0,0,.76,0,1,1,0,0,0,.33-.21l4.5-4.5a1,1,0,0,0,0-1.42ZM13,5.41,15.09,7.5,13,9.59Zm0,13.18V14.41l2.09,2.09Z"/>',
+	'bt_neutral':'<path d="M17.71 7.71L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88z"/>',
+	'bt_connected':'<path d="M7 12l-2-2-2 2 2 2 2-2zm10.71-4.29L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88zM19 10l-2 2 2 2 2-2-2-2z"/>',
+	'bt_disabled':'<path d="M13 5.83l1.88 1.88-1.6 1.6 1.41 1.41 3.02-3.02L12 2h-1v5.03l2 2v-3.2zM5.41 4L4 5.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l4.29-4.29 2.3 2.29L20 18.59 5.41 4zM13 18.17v-3.76l1.88 1.88L13 18.17z"/>',
+	'bt_searching':'<path d="M14.24 12.01l2.32 2.32c.28-.72.44-1.51.44-2.33 0-.82-.16-1.59-.43-2.31l-2.33 2.32zm5.29-5.3l-1.26 1.26c.63 1.21.98 2.57.98 4.02s-.36 2.82-.98 4.02l1.2 1.2c.97-1.54 1.54-3.36 1.54-5.31-.01-1.89-.55-3.67-1.48-5.19zm-3.82 1L10 2H9v7.59L4.41 5 3 6.41 8.59 12 3 17.59 4.41 19 9 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM11 5.83l1.88 1.88L11 9.59V5.83zm1.88 10.46L11 18.17v-3.76l1.88 1.88z"/>',
+	'play_circle_outline':'<path d="M10 16.5l6-4.5-6-4.5v9zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>',
+	'play_circle_filled':'<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/>',
+	'play_arrow':'<path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/>',
+	'pause':'<path d="M0 0h24v24H0z" fill="none"/><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>',
+	'stop':'<path d="M0 0h24v24H0z" fill="none"/><path d="M6 6h12v12H6z"/>',
+	'':''
+};
+
+var bt_state_icon = [
+	{"desc":"Idle", "sub":["bt_neutral"]},
+	{"desc":"Discovering","sub":["bt_searching"]},
+	{"desc":"Discovered","sub":["bt_searching"]},
+	{"desc":"Unconnected","sub":["bt_disabled"]},
+	{"desc":"Connecting","sub":["bt_disabled"]},
+	{"desc":"Connected","sub":["bt_connected", "play_circle_outline", "bt_playing", "pause", "stop"]},
+	{"desc":"Disconnecting","sub":["bt_neutral"]},
+];
+
 pillcolors = {
 	'MESSAGING_INFO' : 'badge-success',
 	'MESSAGING_WARNING' : 'badge-warning',
@@ -72,6 +97,24 @@ var escapeHTML = function(unsafe) {
 		}
 	});
 };
+
+function handlebtstate(data){
+	var icon = '';
+	var tt='';
+	if (data['bt_status']!=undefined && data['bt_sub_status']!=undefined) {
+		var iconsvg=bt_state_icon[data['bt_status']]?.sub[data['bt_sub_status']];
+		if(iconsvg){
+			icon =  bt_icons[iconsvg];
+			tt=bt_state_icon[data['bt_status']]?.desc;
+		}
+		else {
+			icon = bt_icons.bt_connected;
+			tt='Output status';
+		}
+	}
+	o_type.title=tt;
+	$('#o_bt').html(icon);
+}
 function setNavColor(stylename){
 	$('[name=secnav]').removeClass('bg-secondary bg-warning');
 	$("footer.footer").removeClass('bg-secondary bg-warning');
@@ -84,24 +127,18 @@ function setNavColor(stylename){
 }
 function handleTemplateTypeRadio(outtype){
 	if (outtype == 'bt') {
-		$("#btsinkdiv").parent().show(200);
-		$("#btsinkdiv").show();
 		$('#bt').prop('checked',true);
-		o_bt.setAttribute("display", "inline");		
+		o_bt.setAttribute("display", "inline");				
 		o_spdif.setAttribute("display", "none");	
 		o_i2s.setAttribute("display", "none");			
 		output = 'bt';
 	} else if (outtype == 'spdif') {
-		$("#btsinkdiv").parent().hide(200);
-		$("#btsinkdiv").show();
 		$('#spdif').prop('checked',true);
 		o_bt.setAttribute("display", "none");		
 		o_spdif.setAttribute("display", "inline");	
 		o_i2s.setAttribute("display", "none");			
 		output = 'spdif';
 	} else {
-		$("#btsinkdiv").parent().hide(200);
-		$("#btsinkdiv").show();
 		$('#i2s').prop('checked',true);
 		o_bt.setAttribute("display", "none");		
 		o_spdif.setAttribute("display", "none");	
@@ -326,13 +363,8 @@ function save_autoexec1(apply){
 	showCmdMessage('cfg-audio-tmpl','MESSAGING_INFO',"Saving.\n",false);
 	var commandLine = commandHeader + ' -n "' + $("#player").val() + '"';
 	if (output == 'bt') {
-		if($("#btsinkdiv").val()?.length!=0){
-			commandLine += ' -o "BT -n \'' + $("#btsinkdiv").val() + '\'" -Z 192000';
-		}
-		else {
-			showCmdMessage('cfg-audio-tmpl','MESSAGING_ERROR',"BT Sink Name required for output bluetooth.\n",true);
-			return;
-		}
+		commandLine += ' -o "BT" -R -Z 192000';
+		showCmdMessage('cfg-audio-tmpl','MESSAGING_INFO',"Remember to configure the Bluetooth audio device name.\n",true);
 	} else if (output == 'spdif') {
 		commandLine += ' -o SPDIF -Z 192000';
 	} else {
@@ -939,6 +971,8 @@ function handleRecoveryMode(data){
 			setNavColor('bg-warning');
 			$("#boot-button").html('Reboot');
 			$("#boot-form").attr('action', '/reboot_ota.json');
+			$("flashfilename").show();
+			$("fwUpload").show();
 		} else {
 			recovery = false;
 			$("#reboot_ota_nav").hide();
@@ -949,6 +983,8 @@ function handleRecoveryMode(data){
 			$("footer.footer").addClass('sl');
 			$("#boot-button").html('Recovery');
 			$("#boot-form").attr('action', '/recovery.json');
+			$("flashfilename").hide();
+			$("fwUpload").hide();
 		}
 	}
 }
@@ -1029,6 +1065,7 @@ function checkStatus() {
 	$.getJSON("/status.json", function(data) {
 		handleRecoveryMode(data);
 		handleWifiStatus(data);
+		handlebtstate(data);
 		if (data.hasOwnProperty('project_name') && data['project_name'] != '') {
 			pname = data['project_name'];
 		}
@@ -1066,7 +1103,7 @@ function checkStatus() {
 		}
 		if (data.hasOwnProperty('Jack')) {
 			var jack = data['Jack'];
-			if (jack == '1') {
+			if (jack) {
 				o_jack.setAttribute("display", "inline");
 			}
 		}
@@ -1253,11 +1290,6 @@ function getConfig() {
 							handleTemplateTypeRadio('spdif');
 						} else if (m[1].toUpperCase().startsWith('"BT')) {
 							handleTemplateTypeRadio('bt');
-							var re2=/["]BT\s*-n\s*'([^"]+)'/g;
-							var m2=re2.exec(m[1]);
-							if(m2.length>=2){
-								$("#btsinkdiv").val(m2[1]);
-							}
 						}
 					} else if (key == 'host_name') {
 						val = val.replaceAll('"', '');

BIN
components/wifi-manager/res/code.js.gz


+ 16 - 1
components/wifi-manager/status-messages.json

@@ -1 +1,16 @@
-{"project_name":"recovery","version":"custom.build","recovery":1,"Jack":"1","Voltage":0,"disconnect_count":0,"avg_conn_time":0,"is_i2c_locked":false,"urc":0,"ssid":"MyTestSSID","ip":"192.168.10.225","netmask":"255.255.255.0","gw":"192.168.10.1"}
+{
+    "project_name": "recovery",
+    "version": "custom.build",
+    "recovery": 1,
+    "Jack": "1",
+    "Voltage": 0,
+    "disconnect_count": 0,
+    "avg_conn_time": 0,
+    "is_i2c_locked": false,
+    "urc": 0,
+    "bt_status": 0,
+    "ssid": "MyTestSSID",
+    "ip": "192.168.10.225",
+    "netmask": "255.255.255.0",
+    "gw": "192.168.10.1"
+}

+ 1 - 0
components/wifi-manager/status.json

@@ -8,6 +8,7 @@
 	"avg_conn_time": 0,
 	"is_i2c_locked": false,
 	"urc": 0,
+	"bt_status": 0,
 	"ssid": "MyTestSSID",
 	"ip": "192.168.10.225",
 	"netmask": "255.255.255.0",

+ 42 - 1
components/wifi-manager/wifi_manager.c

@@ -63,6 +63,7 @@ Contains the freeRTOS task and all necessary support
 #include "trace.h"
 #include "cmd_system.h"
 #include "messaging.h"
+#include "bt_app_core.h"
 
 #include "http_server_handlers.h"
 #include "monitor.h"
@@ -188,6 +189,9 @@ char * get_disconnect_code_desc(uint8_t reason){
 	}
 	return "";
 }
+void wifi_manager_update_status(){
+	wifi_manager_send_message(ORDER_UPDATE_STATUS,NULL);
+}
 void set_host_name(){
 	esp_err_t err;
 	ESP_LOGD(TAG, "Retrieving host name from nvs");
@@ -458,6 +462,38 @@ cJSON * wifi_manager_get_new_array_json(cJSON **old){
 	ESP_LOGV(TAG,  "wifi_manager_get_new_array_json done");
 	return cJSON_CreateArray();
 }
+void wifi_manager_update_basic_info(){
+	if(wifi_manager_lock_json_buffer( portMAX_DELAY )){
+
+		monitor_gpio_t *mgpio= get_jack_insertion_gpio(); 
+		
+		cJSON * voltage = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Voltage");
+		if(voltage){
+			cJSON_SetNumberValue(voltage,	battery_value_svc());
+		}
+		cJSON * bt_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_status");
+		if(bt_status){
+			cJSON_SetNumberValue(bt_status,	bt_app_source_get_a2d_state());
+		}
+		cJSON * bt_sub_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_sub_status");
+		if(bt_sub_status){
+			cJSON_SetNumberValue(bt_sub_status,	bt_app_source_get_media_state());
+		}
+		cJSON * jack = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Jack");
+		if(jack){
+			jack->type=mgpio->gpio>=0 && jack_inserted_svc()?cJSON_True:cJSON_False;
+		}
+		cJSON * disconnect_count = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "disconnect_count");
+		if(disconnect_count){
+			cJSON_SetNumberValue(disconnect_count,	num_disconnect);
+		}
+		cJSON * avg_conn_time = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "avg_conn_time");
+		if(avg_conn_time){
+			cJSON_SetNumberValue(avg_conn_time,	num_disconnect>0?(total_connected_time/num_disconnect):0);
+		}	
+		wifi_manager_unlock_json_buffer();
+	}
+}
 cJSON * wifi_manager_get_basic_info(cJSON **old){
 	monitor_gpio_t *mgpio= get_jack_insertion_gpio(); 
 	const esp_app_desc_t* desc = esp_ota_get_app_description();
@@ -467,10 +503,12 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
 	cJSON_AddItemToObject(root, "version", cJSON_CreateString(desc->version));
 	if(release_url !=NULL) cJSON_AddItemToObject(root, "release_url", cJSON_CreateString(release_url));
 	cJSON_AddNumberToObject(root,"recovery",	is_recovery_running?1:0);
-	cJSON_AddItemToObject(root, "Jack", cJSON_CreateString(mgpio->gpio>=0 && jack_inserted_svc() ? "1" : "0"));
+	cJSON_AddBoolToObject(root, "Jack", mgpio->gpio>=0 && jack_inserted_svc() );
 	cJSON_AddNumberToObject(root,"Voltage",	battery_value_svc());
 	cJSON_AddNumberToObject(root,"disconnect_count", num_disconnect	);
 	cJSON_AddNumberToObject(root,"avg_conn_time", num_disconnect>0?(total_connected_time/num_disconnect):0	);
+	cJSON_AddNumberToObject(root,"bt_status", bt_app_source_get_a2d_state());
+	cJSON_AddNumberToObject(root,"bt_sub_status", bt_app_source_get_media_state());
 #if CONFIG_I2C_LOCKED
 	cJSON_AddTrueToObject(root, "is_i2c_locked");
 #else
@@ -1537,6 +1575,9 @@ void wifi_manager( void * pvParameters ){
 				ESP_LOGD(TAG,   "Calling simple_restart.");
 				simple_restart();
 				break;
+			case ORDER_UPDATE_STATUS:
+				wifi_manager_update_basic_info();
+				break;
 			default:
 				break;
 

+ 3 - 2
components/wifi-manager/wifi_manager.h

@@ -191,7 +191,8 @@ typedef enum message_code_t {
 	ORDER_RESTART_RECOVERY = 16,
 	ORDER_RESTART_OTA_URL = 17,
 	ORDER_RESTART = 18,
-	MESSAGE_CODE_COUNT = 19 /* important for the callback array */
+	ORDER_UPDATE_STATUS = 19,
+	MESSAGE_CODE_COUNT = 20 /* important for the callback array */
 
 }message_code_t;
 
@@ -202,7 +203,7 @@ typedef enum reboot_type_t{
 } reboot_type_t;
 void wifi_manager_reboot(reboot_type_t rtype);
 void wifi_manager_reboot_ota(char * url);
-
+void wifi_manager_update_status();
 
 
 /**

+ 9 - 7
main/esp_app_main.c

@@ -437,14 +437,16 @@ void app_main()
 		bypass_wifi_manager=(strcmp(bypass_wm,"1")==0 ||strcasecmp(bypass_wm,"y")==0);
 	}
 
-	ESP_LOGD(TAG,"Getting audio control mapping ");
-	char *actrls_config = config_alloc_get_default(NVS_TYPE_STR, "actrls_config", NULL, 0);
-	if (actrls_init(actrls_config) == ESP_OK) {
-		ESP_LOGD(TAG,"Initializing audio control buttons type %s", actrls_config);	
-	} else {
-		ESP_LOGD(TAG,"No audio control buttons");
+	if(!is_recovery_running){
+		ESP_LOGD(TAG,"Getting audio control mapping ");
+		char *actrls_config = config_alloc_get_default(NVS_TYPE_STR, "actrls_config", NULL, 0);
+		if (actrls_init(actrls_config) == ESP_OK) {
+			ESP_LOGD(TAG,"Initializing audio control buttons type %s", actrls_config);	
+		} else {
+			ESP_LOGD(TAG,"No audio control buttons");
+		}
+		if (actrls_config) free(actrls_config);
 	}
-	if (actrls_config) free(actrls_config);
 
 	/* start the wifi manager */
 	ESP_LOGD(TAG,"Blinking led");

+ 1 - 1
sdkconfig.defaults

@@ -609,7 +609,7 @@ CONFIG_LWIP_MAX_SOCKETS=16
 
 CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
-CONFIG_LWIP_IP_REASSEMBLY=y
+#CONFIG_LWIP_IP_REASSEMBLY is not set
 
 
 

+ 3 - 3
sdkconfig_minimal

@@ -321,7 +321,7 @@ CONFIG_BT_A2DP_ENABLE=y
 # CONFIG_BT_HFP_ENABLE is not set
 CONFIG_BT_SSP_ENABLED=y
 # CONFIG_BT_BLE_ENABLED is not set
-CONFIG_BT_STACK_NO_LOG=y
+CONFIG_BT_STACK_NO_LOG=n
 CONFIG_BT_ACL_CONNECTIONS=4
 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
@@ -773,8 +773,8 @@ CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 CONFIG_FREERTOS_USE_TRACE_FACILITY=y
 CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
 CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
-CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
-CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
+#CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
+#CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
 # CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set
 CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
 # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott