diff --git a/.gitignore b/.gitignore index 39637f48..1a5a79aa 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ libs/ /cdump.cmd /_codecs +sdkconfig diff --git a/components/platform_esp32/platform_esp32.c b/components/platform_esp32/bt_app_handler.c similarity index 77% rename from components/platform_esp32/platform_esp32.c rename to components/platform_esp32/bt_app_handler.c index 399e2658..eaf5673d 100644 --- a/components/platform_esp32/platform_esp32.c +++ b/components/platform_esp32/bt_app_handler.c @@ -1,54 +1,32 @@ #include #include #include -#include "esp_log.h" -#include "esp_system.h" -#include #include -#include -#include + +#include "esp_log.h" #include "esp_bt.h" #include "esp_bt_device.h" #include "esp_bt_main.h" #include "esp_gap_bt_api.h" #include "esp_a2dp_api.h" -#include "esp_avrc_api.h" #include "esp_console.h" #include "esp_pthread.h" #include "esp_system.h" #include "esp_wifi.h" -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "freertos/task.h" #include "freertos/timers.h" -#include "nvs.h" -#include "nvs_flash.h" -#include "nvs_utilities.h" -#include "pthread.h" -#include "string.h" -//#include "esp_event.h" -#include "sys/socket.h" -#include - -#include -#include "platform_esp32.h" -#include "../../main/squeezelite.h" #include "argtable3/argtable3.h" -#define STATS_REPORT_DELAY_MS 15000 +#include "bt_app_core.h" + +#include "platform_esp32.h" + static const char * TAG = "platform"; -extern char * get_output_state_desc(output_state state); -extern struct outputstate output; -extern struct buffer *outputbuf; -extern struct buffer *streambuf; -extern uint8_t * btout; -time_t disconnect_time=0; -#define LOCK_S pthread_mutex_lock(&(streambuf->mutex)) -#define UNLOCK_S pthread_mutex_unlock(&(streambuf->mutex)) +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); -#define LOCK pthread_mutex_lock(&(outputbuf->mutex)) -#define UNLOCK pthread_mutex_unlock(&(outputbuf->mutex)) int64_t connecting_timeout = 0; static const char * art_a2dp_connected[]={"\n", @@ -76,34 +54,8 @@ static void bt_app_av_state_connecting(uint16_t event, void *param); #define A2DP_TIMER_INIT connecting_timeout = esp_timer_get_time() +(CONFIG_A2DP_CONNECT_TIMEOUT_MS * 1000) #define IS_A2DP_TIMER_OVER esp_timer_get_time() >= connecting_timeout -#define FRAME_TO_BYTES(f) f*BYTES_PER_FRAME -#define BYTES_TO_FRAME(b) b/BYTES_PER_FRAME - - -#define RESET_ALL_MIN_MAX RESET_MIN_MAX(req); RESET_MIN_MAX(rec); RESET_MIN_MAX(bt);RESET_MIN_MAX(under); RESET_MIN_MAX_DURATION(stream_buf); RESET_MIN_MAX_DURATION(lock_out_time) - -DECLARE_MIN_MAX(stream_buf); -DECLARE_MIN_MAX(req); -DECLARE_MIN_MAX(rec); -DECLARE_MIN_MAX(bt); -DECLARE_MIN_MAX(under); -DECLARE_MIN_MAX_DURATION(lock_out_time); - static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param); -void get_mac(u8_t mac[]) { - esp_read_mac(mac, ESP_MAC_WIFI_STA); -} - -_sig_func_ptr signal(int sig, _sig_func_ptr func) { - return NULL; -} - -void *audio_calloc(size_t nmemb, size_t size) { - return calloc(nmemb, size); -} - - /* event for handler "bt_av_hdl_stack_up */ enum { BT_APP_EVT_STACK_UP = 0, @@ -181,16 +133,12 @@ static struct { void hal_bluetooth_init(const char * options) { ESP_LOGD(TAG,"Initializing Bluetooth HAL"); - //CONFIG_A2DP_SINK_NAME - //CONFIG_A2DP_CONTROL_DELAY_MS - //CONFIG_A2DP_CONNECT_TIMEOUT_MS squeezelite_args.sink_name = arg_str1("n", "name", "", "the name of the bluetooth to connect to"); squeezelite_args.control_delay = arg_int0("d", "delay", "", "the delay between each pass at the A2DP control loop"); squeezelite_args.connect_timeout_delay = arg_int0("t","timeout", "", "the timeout duration for connecting to the A2DP sink"); squeezelite_args.end = arg_end(2); - ESP_LOGD(TAG,"Copying parameters"); char * opts = strdup(options); char **argv = malloc(sizeof(char**)*15); @@ -280,42 +228,7 @@ void hal_bluetooth_init(const char * options) esp_bt_gap_set_pin(pin_type, 0, pin_code); } -static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len) -{ - int32_t avail_data=0,wanted_len=0, start_timer=0; - if (len < 0 || data == NULL ) { - return 0; - } - btout=data; - - // This is how the BTC layer calculates the number of bytes to - // for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes - wanted_len=len; - SET_MIN_MAX(len,req); - TIME_MEASUREMENT_START(start_timer); - LOCK; - output.device_frames = 0; // todo: check if this is the right way do to this. - output.updated = gettime_ms(); - output.frames_played_dmp = output.frames_played; - SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size); - do { - avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full - wanted_len-=avail_data; - } while (wanted_len > 0 && avail_data != 0); - if(wanted_len>0) - { - SET_MIN_MAX(wanted_len, under); - } - - UNLOCK; - SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time); - SET_MIN_MAX((len-wanted_len), rec); - TIME_MEASUREMENT_START(start_timer); - output_bt_check_buffer(); - - return len-wanted_len; -} static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL); @@ -415,10 +328,10 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param) { switch (s_a2d_state) { case APP_AV_STATE_DISCOVERING: - ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state)); + ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, output_state_str()); break; case APP_AV_STATE_DISCOVERED: - ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state)); + ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, output_state_str()); break; case APP_AV_STATE_UNCONNECTED: bt_app_av_state_unconnected(event, param); @@ -562,7 +475,6 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param) } } - static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) { @@ -579,7 +491,7 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) /* initialize A2DP source */ esp_a2d_register_callback(&bt_app_a2d_cb); - esp_a2d_source_register_data_callback(bt_app_a2d_data_cb); + esp_a2d_source_register_data_callback(&output_bt_data); esp_a2d_source_init(); /* set discoverable and connectable mode */ @@ -605,39 +517,15 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) } } -#ifdef BTAUDIO -bool test_open(const char *device, unsigned rates[], bool userdef_rates) { - -// running_test = true; -// while(running_test) -// { -// // wait until BT playback has started -// // this will allow querying the sample rate -// usleep(100000); -// } - - memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned)); - if (!strcmp(device, "BT")) { - rates[0] = 44100; - } else { - unsigned _rates[] = { 96000, 88200, 48000, 44100, 32000, 0 }; - memcpy(rates, _rates, sizeof(_rates)); - } - return true; -} -#endif static void bt_app_av_media_proc(uint16_t event, void *param) { esp_a2d_cb_param_t *a2d = NULL; - LOCK; - output_state out_state=output.state; - UNLOCK; switch (s_media_state) { case APP_AV_MEDIA_STATE_IDLE: { if (event == BT_APP_HEART_BEAT_EVT) { - if(out_state > OUTPUT_STOPPED) + if(!output_stopped()) { - ESP_LOGI(TAG,"Output state is %s, Checking if A2DP is ready.", get_output_state_desc(out_state)); + ESP_LOGI(TAG,"Output state is %s, Checking if A2DP is ready.", output_state_str()); esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY); } @@ -671,40 +559,12 @@ static void bt_app_av_media_proc(uint16_t event, void *param) } case APP_AV_MEDIA_STATE_STARTED: { if (event == BT_APP_HEART_BEAT_EVT) { - if(out_state <= OUTPUT_STOPPED) { - ESP_LOGI(TAG,"Output state is %s. Stopping a2dp media ...", get_output_state_desc(out_state)); + if(output_stopped()) { + ESP_LOGI(TAG,"Output state is %s. Stopping a2dp media ...", output_state_str()); s_media_state = APP_AV_MEDIA_STATE_STOPPING; esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP); - } - else - { - LOCK_S; - SET_MIN_MAX_SIZED(_buf_used(streambuf),stream_buf,streambuf->size); - UNLOCK_S; - static time_t lastTime=0; - if (lastTime <= gettime_ms() ) - { - lastTime = gettime_ms() + 15000; - ESP_LOGD(TAG, "Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000); - ESP_LOGD(TAG, " +==========+==========+================+=====+================+"); - ESP_LOGD(TAG, " | max | min | average | avg | count |"); - ESP_LOGD(TAG, " | (bytes) | (bytes) | (bytes) | pct | |"); - ESP_LOGD(TAG, " +==========+==========+================+=====+================+"); - ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf)); - ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt)); - ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req)); - ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec)); - ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under)); - ESP_LOGD(TAG, " +==========+==========+================+=====+================+"); - ESP_LOGD(TAG,"\n"); - ESP_LOGD(TAG," ==========+==========+===========+===========+ "); - ESP_LOGD(TAG," max (us) | min (us) | avg(us) | count | "); - ESP_LOGD(TAG," ==========+==========+===========+===========+ "); - ESP_LOGD(TAG,LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time)); - ESP_LOGD(TAG," ==========+==========+===========+===========+"); - RESET_ALL_MIN_MAX; - } - + } else { + output_bt_tick(); } } break; @@ -716,16 +576,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param) if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP && a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) { ESP_LOGI(TAG,"a2dp media stopped successfully..."); - //s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT; - // if(CONFIG_A2DP_DISCONNECT_MS==0){ - // we're not going to disconnect. - s_media_state = APP_AV_MEDIA_STATE_IDLE; -// } -// else -// { -// disconnect_time = gettime_ms()+CONFIG_A2DP_DISCONNECT_MS; -// s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT; -// } + s_media_state = APP_AV_MEDIA_STATE_IDLE; } else { ESP_LOGI(TAG,"a2dp media stopping..."); esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP); @@ -735,20 +586,15 @@ static void bt_app_av_media_proc(uint16_t event, void *param) } case APP_AV_MEDIA_STATE_WAIT_DISCONNECT:{ - if(gettime_ms()>disconnect_time){ - // we've reached timeout - esp_a2d_source_disconnect(s_peer_bda); - s_a2d_state = APP_AV_STATE_DISCONNECTING; - } + esp_a2d_source_disconnect(s_peer_bda); + s_a2d_state = APP_AV_STATE_DISCONNECTING; + ESP_LOGI(TAG,"a2dp disconnecting..."); } } } static void bt_app_av_state_unconnected(uint16_t event, void *param) { -// LOCK; -// output_state out_state= output.state; -// UNLOCK; switch (event) { case ESP_A2D_CONNECTION_STATE_EVT: ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_CONNECTION_STATE_EVT)); @@ -772,8 +618,6 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param) ESP_LOG_DEBUG_EVENT(TAG,QUOTE(ESP_A2D_MEDIA_CTRL_ACK_EVT)); break; case BT_APP_HEART_BEAT_EVT: { - // uint8_t *p = s_peer_bda; - // ESP_LOGI(TAG,"BT_APP_HEART_BEAT_EVT a2dp connecting to peer: %02x:%02x:%02x:%02x:%02x:%02x",p[0], p[1], p[2], p[3], p[4], p[5]); switch (esp_bluedroid_get_status()) { case ESP_BLUEDROID_STATUS_UNINITIALIZED: ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_UNINITIALIZED."); @@ -787,21 +631,18 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param) default: break; } -// if(out_state > OUTPUT_STOPPED){ - // only attempt a connect when playback isn't stopped - for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){ - ESP_LOGI(TAG,"%s",art_a2dp_connecting[l]); - } - ESP_LOGI(TAG,"Device: %s", s_peer_bdname); - if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) { - A2DP_TIMER_INIT; - s_a2d_state = APP_AV_STATE_CONNECTING; - } - else { - // there was an issue connecting... continue to discover - ESP_LOGE(TAG,"Attempt at connecting failed, restart at discover..."); - esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); - // } + for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){ + ESP_LOGI(TAG,"%s",art_a2dp_connecting[l]); + } + ESP_LOGI(TAG,"Device: %s", s_peer_bdname); + if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) { + A2DP_TIMER_INIT; + s_a2d_state = APP_AV_STATE_CONNECTING; + } + else { + // there was an issue connecting... continue to discover + ESP_LOGE(TAG,"Attempt at connecting failed, restart at discover..."); + esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); } break; } @@ -928,18 +769,4 @@ static void bt_app_av_state_disconnecting(uint16_t event, void *param) ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event); break; } -} -const char *loc_logtime(void) { - static char buf[100]; -#if WIN - SYSTEMTIME lt; - GetLocalTime(<); - sprintf(buf, "[%02d:%02d:%02d.%03d]", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - strftime(buf, sizeof(buf), "[%T.", localtime(&tv.tv_sec)); - sprintf(buf+strlen(buf), "%06ld]", (long)tv.tv_usec); -#endif - return buf; -} +} \ No newline at end of file diff --git a/components/platform_esp32/cmd_squeezelite.c b/components/platform_esp32/cmd_squeezelite.c index 63874979..de02fe58 100644 --- a/components/platform_esp32/cmd_squeezelite.c +++ b/components/platform_esp32/cmd_squeezelite.c @@ -7,6 +7,7 @@ #include "esp_log.h" #include "esp_console.h" +#include "esp_pthread.h" #include "argtable3/argtable3.h" #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" diff --git a/components/platform_esp32/component.mk b/components/platform_esp32/component.mk index fc8a2aa9..77265992 100644 --- a/components/platform_esp32/component.mk +++ b/components/platform_esp32/component.mk @@ -6,5 +6,4 @@ # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, # please read the SDK documents if you need to do this. # -CFLAGS += -Os -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG diff --git a/components/platform_esp32/esp_app_main.c b/components/platform_esp32/esp_app_main.c index a121f354..8e05230e 100644 --- a/components/platform_esp32/esp_app_main.c +++ b/components/platform_esp32/esp_app_main.c @@ -1,147 +1,27 @@ -/* Scan Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -/* - This example shows how to use the All Channel Scan or Fast Scan to connect - to a Wi-Fi network. - - In the Fast Scan mode, the scan will stop as soon as the first network matching - the SSID is found. In this mode, an application can set threshold for the - authentication mode and the Signal strength. Networks that do not meet the - threshold requirements will be ignored. - - In the All Channel Scan mode, the scan will end only after all the channels - are scanned, and connection will start with the best network. The networks - can be sorted based on Authentication Mode or Signal Strength. The priority - for the Authentication mode is: WPA2 > WPA > WEP > Open -*/ +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #include "platform_esp32.h" -#include -#include -#include -#include -#include "esp_bt.h" -#include "esp_bt_device.h" -#include "esp_bt_main.h" -#include "esp_gap_bt_api.h" -#include "esp_a2dp_api.h" -#include "esp_avrc_api.h" -#include "esp_log.h" -#include "esp_pthread.h" -#include "esp_system.h" -#include "esp_wifi.h" -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "freertos/task.h" -#include "freertos/timers.h" -#include "nvs.h" -#include "nvs_flash.h" -#include "nvs_utilities.h" -#include "pthread.h" -#include "string.h" -#include "sys/socket.h" -#include -#include "esp_system.h" -#include - -/*Set the SSID and Password via "make menuconfig"*/ -#define DEFAULT_SSID CONFIG_WIFI_SSID -#define DEFAULT_PWD CONFIG_WIFI_PASSWORD - -#if CONFIG_WIFI_ALL_CHANNEL_SCAN -#define DEFAULT_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN -#elif CONFIG_WIFI_FAST_SCAN -#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN -#else -#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN -#endif /*CONFIG_SCAN_METHOD*/ - -#if CONFIG_WIFI_CONNECT_AP_BY_SIGNAL -#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL -#elif CONFIG_WIFI_CONNECT_AP_BY_SECURITY -#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY -#else -#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL -#endif /*CONFIG_SORT_METHOD*/ - -#if CONFIG_FAST_SCAN_THRESHOLD -#define DEFAULT_RSSI CONFIG_FAST_SCAN_MINIMUM_SIGNAL -#if CONFIG_EXAMPLE_OPEN -#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN -#elif CONFIG_EXAMPLE_WEP -#define DEFAULT_AUTHMODE WIFI_AUTH_WEP -#elif CONFIG_EXAMPLE_WPA -#define DEFAULT_AUTHMODE WIFI_AUTH_WPA_PSK -#elif CONFIG_EXAMPLE_WPA2 -#define DEFAULT_AUTHMODE WIFI_AUTH_WPA2_PSK -#else -#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN -#endif -#else -#define DEFAULT_RSSI -127 -#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN -#endif /*CONFIG_FAST_SCAN_THRESHOLD*/ -extern char current_namespace[]; -static const char * TAG = "platform_esp32"; - - - -//static void event_handler(void* arg, esp_event_base_t event_base, -// int32_t event_id, void* event_data) -//{ -// if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { -// esp_wifi_connect(); -// } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { -// esp_wifi_connect(); -// } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { -// ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; -// ESP_LOGI(TAG, "got ip: %s.", ip4addr_ntoa(&event->ip_info.ip)); -// ESP_LOGD(TAG,"Signaling wifi connected. Locking.\n"); -// pthread_mutex_lock(&wifi_connect_suspend_mutex); -// ESP_LOGD(TAG,"Signaling wifi connected. Broadcasting.\n"); -// pthread_cond_broadcast(&wifi_connect_suspend_cond); -// ESP_LOGD(TAG,"Signaling wifi connected. Unlocking.\n"); -// pthread_mutex_unlock(&wifi_connect_suspend_mutex); -// } -//} -// -///* Initialize Wi-Fi as sta and set scan method */ -//static void wifi_scan(void) -//{ -// -// tcpip_adapter_init(); -// ESP_ERROR_CHECK(esp_event_loop_create_default()); -// -// wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); -// ESP_ERROR_CHECK(esp_wifi_init(&cfg)); -// -// ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); -// ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); -// -// wifi_config_t wifi_config = { -// .sta = { -// .ssid = DEFAULT_SSID, -// .password = DEFAULT_PWD, -// .scan_method = DEFAULT_SCAN_METHOD, -// .sort_method = DEFAULT_SORT_METHOD, -// .threshold.rssi = DEFAULT_RSSI, -// .threshold.authmode = DEFAULT_AUTHMODE, -// }, -// }; -// ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); -// ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); -// ESP_ERROR_CHECK(esp_wifi_start()); -//} - void app_main() { - console_start(); } diff --git a/components/platform_esp32/perf_trace.h b/components/platform_esp32/perf_trace.h index 5ded9c9d..1cd93859 100644 --- a/components/platform_esp32/perf_trace.h +++ b/components/platform_esp32/perf_trace.h @@ -1,8 +1,28 @@ - +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #pragma once -#include "time.h" + #include "sys/time.h" -#include "esp_system.h" + #define PERF_MAX LONG_MAX #define MIN_MAX_VAL(x) x==PERF_MAX?0:x #define CURR_SAMPLE_RATE output.current_sample_rate>0?output.current_sample_rate:1 diff --git a/components/platform_esp32/platform_esp32.h b/components/platform_esp32/platform_esp32.h index 148dd24f..b01e4754 100644 --- a/components/platform_esp32/platform_esp32.h +++ b/components/platform_esp32/platform_esp32.h @@ -1,93 +1,44 @@ +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #pragma once + #ifdef __cplusplus extern "C" { #endif -#include "bt_app_core.h" -#include "perf_trace.h" + #include "esp_pthread.h" + #ifndef QUOTE #define QUOTE(name) #name -#define STR(macro) QUOTE(macro) #endif + +#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e) + extern void run_command(char * line); extern bool wait_for_wifi(); - -//typedef struct { -// char opt_slimproto_logging[11]; -// char opt_stream_logging[11]; -// char opt_decode_logging[11]; -// char opt_output_logging[11]; -// char opt_player_name[11]; -// char opt_output_rates[21]; -// char opt_buffer[11]; -//} str_squeezelite_options ; extern void console_start(); extern pthread_cond_t wifi_connect_suspend_cond; extern pthread_t wifi_connect_suspend_mutex; -//static const char * art_wifi[]={ -// "\n", -// "o `O ooOoOOo OOooOoO ooOoOOo\n", -// "O o O o O \n", -// "o O o O o \n", -// "O O O oOooO O \n", -// "o o o o O o \n", -// "O O O O o O \n", -// "`o O o O' O o O \n", -// " `OoO' `OoO' ooOOoOo O' ooOOoOo\n", -// "\n", -// "" -//}; -//static const char * art_wifi_connecting[]={ -// " .oOOOo.", -// ".O o o \n", -// "o O \n", -// "o oOo \n", -// "o .oOo. 'OoOo. 'OoOo. .oOo. .oOo o O 'OoOo. .oOoO \n", -// "O O o o O o O OooO' O O o o O o O \n", -// "`o .o o O O o O o O o o O O o O o \n", -// " `OoooO' `OoO' o O o O `OoO' `OoO' `oO o' o O `OoOo \n", -// " O \n", -// " OoO' \n", -// "\n", -// "" -//}; -//static const char * art_wifi_connected[]={ -// " .oOOOo. o oO\n", -// ".O o O OO\n", -// "o O o oO\n", -// "o oOo o Oo\n", -// "o .oOo. 'OoOo. 'OoOo. .oOo. .oOo o .oOo. .oOoO oO\n", -// "O O o o O o O OooO' O O OooO' o O \n", -// "`o .o o O O o O o O o o O O o Oo\n", -// " `OoooO' `OoO' o O o O `OoO' `OoO' `oO `OoO' `OoO'o oO\n", -// "\n", -// "" -//}; -#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e) -const char *loc_logtime(void); -//#define MY_ESP_LOG -#ifdef MY_ESP_LOG -#ifdef ESP_LOGI -#undef ESP_LOGI -#define ESP_LOGI(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, tag, "%s %d " format,loc_logtime(), __LINE__, ##__VA_ARGS__) -#endif -#ifdef ESP_LOGE -#undef ESP_LOGE -#define ESP_LOGE(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, tag, "%s %d " format,loc_logtime(), __LINE__, ##__VA_ARGS__) -#endif -#ifdef ESP_LOGW -#undef ESP_LOGW -#define ESP_LOGW(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, tag, "%s %d " format,loc_logtime(), __LINE__, ##__VA_ARGS__) -#endif -#ifdef ESP_LOGD -#undef ESP_LOGD -#define ESP_LOGD(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, tag, "%s %d " format,loc_logtime(), __LINE__, ##__VA_ARGS__) -#endif -#ifdef ESP_LOGV -#undef ESP_LOGV -#define ESP_LOGV(tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, "%s %d " format,loc_logtime(), __LINE__, ##__VA_ARGS__) -#endif -#endif + #ifdef __cplusplus } #endif diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 0321d426..e691c5ff 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -134,7 +134,7 @@ menu "Squeezelite-ESP32" config OUTPUT_RATES string "Output rates" - default "48000,44100" + default "44100" help [:] Sample rates supported, allows output to be off when squeezelite is started; rates = |-|,,; delay = optional delay switching rates in ms menu "DAC I2S settings" @@ -196,13 +196,6 @@ menu "Squeezelite-ESP32" default 1000 help Increasing this value will give more chance for less stable connections to be established. - config A2DP_DISCONNECT_MS - int "Time in ms before disconnecting from A2DP audio sink. Set to 0 for no disconnect." - default 10000 - help - Controls how long to wait before disconnecting from the A2DP audio sink after playback is stopped - Longer delay will ensure better responsiveness at the expense of locking the audio sink for a longer period. - A shorter period may cause the player to disconnect between tracks change. endmenu endmenu diff --git a/main/component.mk b/main/component.mk index 54594f7b..ec21c2eb 100644 --- a/main/component.mk +++ b/main/component.mk @@ -2,7 +2,7 @@ # "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -CFLAGS += -O3 -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 \ +CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 \ -I$(COMPONENT_PATH)/../components/codecs/inc \ -I$(COMPONENT_PATH)/../components/codecs/inc/mad \ -I$(COMPONENT_PATH)/../components/codecs/inc/alac \ @@ -10,7 +10,7 @@ CFLAGS += -O3 -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DT -I$(COMPONENT_PATH)/../components/codecs/inc/vorbis \ -I$(COMPONENT_PATH)/../components/codecs/inc/soxr \ -I$(COMPONENT_PATH)/../components/codecs/inc/resample16 \ - -I$(COMPONENT_PATH)/../components/platform_esp32 + -I$(COMPONENT_PATH)/../components/platform_esp32 LDFLAGS += -s diff --git a/main/decode.c b/main/decode.c index 84cc4a45..c9c4eaec 100644 --- a/main/decode.c +++ b/main/decode.c @@ -199,8 +199,8 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud LOG_DEBUG("include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs); mutex_create(decode.mutex); - PTHREAD_SET_NAME("decode"); -#if LINUX || OSX || FREEBSD || POSIX + +#if LINUX || OSX || FREEBSD || EMBEDDED pthread_attr_t attr; pthread_attr_init(&attr); #ifdef PTHREAD_STACK_MIN @@ -208,6 +208,9 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud #endif pthread_create(&thread, &attr, decode_thread, NULL); pthread_attr_destroy(&attr); +#if HAS_PTHREAD_SETNAME_NP + pthread_setname_np(thread, "decode"); +#endif #endif #if WIN thread = CreateThread(NULL, DECODE_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&decode_thread, NULL, 0, NULL); diff --git a/main/embedded.c b/main/embedded.c new file mode 100644 index 00000000..cfaf76f8 --- /dev/null +++ b/main/embedded.c @@ -0,0 +1,44 @@ +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "squeezelite.h" +#include "esp_pthread.h" +#include "esp_system.h" + +void get_mac(u8_t mac[]) { + esp_read_mac(mac, ESP_MAC_WIFI_STA); +} + +_sig_func_ptr signal(int sig, _sig_func_ptr func) { + return NULL; +} + +void *audio_calloc(size_t nmemb, size_t size) { + return calloc(nmemb, size); +} + +int pthread_setname_np(pthread_t thread, const char *name) { + esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); + cfg.thread_name= name; + cfg.inherit_cfg = true; + return esp_pthread_set_cfg(&cfg); +} + + diff --git a/main/embedded.h b/main/embedded.h index 84e060ac..4b0b238d 100644 --- a/main/embedded.h +++ b/main/embedded.h @@ -1,6 +1,22 @@ -#pragma once -#if defined(ESP_PLATFORM) -#include "sdkconfig.h" -#include "esp_pthread.h" -#define PTHREAD_SET_NAME(n) { esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); cfg.thread_name= n; cfg.inherit_cfg = true; esp_pthread_set_cfg(&cfg); } +#ifndef EMBEDDED_H +#define EMBEDDED_H + +#include + +#define HAS_MUTEX_CREATE_P 0 +#define HAS_PTHREAD_SETNAME_NP 1 + +#ifndef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 256 #endif + +typedef int16_t s16_t; +typedef int32_t s32_t; +typedef int64_t s64_t; +typedef unsigned long long u64_t; + +#define exit(code) { int ret = code; pthread_exit(&ret); } + +int pthread_setname_np(pthread_t thread, const char *name); + +#endif // EMBEDDED_H diff --git a/main/main.c b/main/main.c index e1e4cf5e..164daf9c 100644 --- a/main/main.c +++ b/main/main.c @@ -169,6 +169,9 @@ static void usage(const char *argv0) { "18" #endif #endif +#if EMBEDDED + " EMBEDDED" +#endif #if EVENTFD " EVENTFD" #endif @@ -381,7 +384,7 @@ int main(int argc, char **argv) { } else { fprintf(stderr, "\nOption error: -%s\n\n", opt); usage(argv[0]); - local_exit(1); + exit(1); } switch (opt[0]) { @@ -432,7 +435,7 @@ int main(int argc, char **argv) { } else { fprintf(stderr, "\nDebug settings error: -d %s\n\n", optarg); usage(argv[0]); - local_exit(1); + exit(1); } } break; @@ -532,7 +535,7 @@ int main(int argc, char **argv) { pidfile = optarg; break; #endif -#if !CONFIG_DACAUDIO && !CONFIG_BTAUDIO +#ifndef EMBEDDED case 'l': list_devices(); exit(0); @@ -675,12 +678,11 @@ int main(int argc, char **argv) { #endif case 't': license(); - local_exit(0); - break; // mute compiler warning + exit(0); case '?': usage(argv[0]); - local_exit(0); - break; // mute compiler warning + exit(0); + break; default: fprintf(stderr, "Arg error: %s\n", argv[optind]); break; @@ -691,7 +693,7 @@ int main(int argc, char **argv) { if (optind < argc) { fprintf(stderr, "\nError: command line argument error\n\n"); usage(argv[0]); - local_exit(1); + exit(1); } signal(SIGINT, sighandler); @@ -757,13 +759,9 @@ int main(int argc, char **argv) { #endif stream_init(log_stream, stream_buf_size); -#ifdef EMBEDDED -if(strstr(output_device,"BT")!=NULL || strstr(output_device,"bt")!=NULL) { - output_init_bt(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle); -} -else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){ - output_init_dac(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle); -} + +#if EMBEDDED + output_init_embedded(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle); #else if (!strcmp(output_device, "-")) { output_init_stdout(log_output, output_buf_size, output_params, rates, rate_delay); @@ -804,7 +802,7 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){ if (name && namefile) { fprintf(stderr, "-n and -N option should not be used at same time\n"); - local_exit(1); + exit(1); } slimproto(log_slimproto, server, mac, name, namefile, modelname, maxSampleRate); @@ -812,10 +810,8 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){ decode_close(); stream_close(); -#if CONFIG_DACAUDIO - output_close_dac(); -#elif CONFIG_BTAUDIO - output_close_bt(); +#if EMBEDDED + output_close_embedded(); #else if (!strcmp(output_device, "-")) { output_close_stdout(); @@ -848,5 +844,5 @@ else if(strstr(output_device,"DAC")!=NULL || strstr(output_device,"dac")!=NULL){ free_ssl_symbols(); #endif - local_exit(0); + exit(0); } diff --git a/main/output.c b/main/output.c index de0748e9..a63cea9e 100644 --- a/main/output.c +++ b/main/output.c @@ -352,13 +352,13 @@ void output_init_common(log_level level, const char *device, unsigned output_buf buf_init(outputbuf, output_buf_size); if (!outputbuf->buf) { LOG_ERROR("unable to malloc output buffer"); - local_exit(0); + exit(0); } silencebuf = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME); if (!silencebuf) { LOG_ERROR("unable to malloc silence buffer"); - local_exit(0); + exit(0); } memset(silencebuf, 0, MAX_SILENCE_FRAMES * BYTES_PER_FRAME); @@ -389,7 +389,7 @@ void output_init_common(log_level level, const char *device, unsigned output_buf else { if (!test_open(output.device, output.supported_rates, user_rates)) { LOG_ERROR("unable to open output device: %s", output.device); - local_exit(0); + exit(0); } } diff --git a/main/output_bt.c b/main/output_bt.c index bc101c10..fa9f7624 100644 --- a/main/output_bt.c +++ b/main/output_bt.c @@ -1,352 +1,59 @@ #include "squeezelite.h" #include "perf_trace.h" -static log_level loglevel; - -static bool running = true; - extern struct outputstate output; extern struct buffer *outputbuf; extern struct buffer *streambuf; - +extern u8_t *silencebuf; #define LOCK mutex_lock(outputbuf->mutex) #define UNLOCK mutex_unlock(outputbuf->mutex) - -#ifdef USE_BT_RING_BUFFER -size_t bt_buffer_size=0; -uint8_t bt_buf_used_threshold = 25; -uint16_t output_bt_thread_heartbeat_ms=1000; -thread_type thread_bt; -#define LOCK_BT mutex_lock(btbuf->mutex) -#define UNLOCK_BT mutex_unlock(btbuf->mutex) -thread_cond_type output_bt_suspend_cond; -mutex_type output_bt_suspend_mutex; -static struct buffer bt_buf_structure; -struct buffer *btbuf=&bt_buf_structure; -static void *output_thread_bt(); -extern void wait_for_frames(size_t frames, uint8_t pct); -#else -uint8_t * btout; -#endif +#define LOCK_S mutex_lock(streambuf->mutex) +#define UNLOCK_S mutex_unlock(streambuf->mutex) #define FRAME_BLOCK MAX_SILENCE_FRAMES -extern u8_t *silencebuf; + +#define STATS_REPORT_DELAY_MS 15000 extern void hal_bluetooth_init(const char * options); +static log_level loglevel; +uint8_t * btout; + static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr); + #define DECLARE_ALL_MIN_MAX \ DECLARE_MIN_MAX(req);\ DECLARE_MIN_MAX(rec);\ - DECLARE_MIN_MAX(o);\ - DECLARE_MIN_MAX(s);\ - DECLARE_MIN_MAX(locbtbuff);\ + DECLARE_MIN_MAX(bt);\ DECLARE_MIN_MAX(under);\ - DECLARE_MIN_MAX_DURATION(mutex1);\ - DECLARE_MIN_MAX_DURATION(mutex2);\ - DECLARE_MIN_MAX_DURATION(buffering);\ - DECLARE_MIN_MAX_DURATION(sleep_time); + DECLARE_MIN_MAX(stream_buf);\ + DECLARE_MIN_MAX_DURATION(lock_out_time) + #define RESET_ALL_MIN_MAX \ - RESET_MIN_MAX(o); \ - RESET_MIN_MAX(s); \ - RESET_MIN_MAX(locbtbuff); \ + RESET_MIN_MAX(bt); \ RESET_MIN_MAX(req); \ RESET_MIN_MAX(rec); \ RESET_MIN_MAX(under); \ - RESET_MIN_MAX_DURATION(mutex1); \ - RESET_MIN_MAX_DURATION(mutex2); \ - RESET_MIN_MAX_DURATION(sleep_time); \ - RESET_MIN_MAX_DURATION(buffering); - - -#if CONFIG_BTAUDIO -void set_volume_bt(unsigned left, unsigned right) { - LOG_DEBUG("setting internal gain left: %u right: %u", left, right); - LOCK; - output.gainL = left; - output.gainR = right; - UNLOCK; -} -#endif - - - -void output_bt_check_buffer() -{ -#ifdef USE_BT_RING_BUFFER - LOCK_BT; - uint8_t tot_buf_used_pct=100*_buf_used(btbuf)/btbuf->size; - UNLOCK_BT; - if(tot_buf_used_pctbuf) { - LOG_ERROR("unable to malloc BT buffer"); - exit(0); - } - mutex_create_p(output_bt_suspend_mutex); - mutex_cond_init(output_bt_suspend_cond); - PTHREAD_SET_NAME("output_bt"); - -#if LINUX || OSX || FREEBSD || POSIX - pthread_attr_t attr; - pthread_attr_init(&attr); -#ifdef PTHREAD_STACK_MIN - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE); -#endif - - pthread_create(&thread_bt, &attr, output_thread_bt, NULL); -#endif - pthread_attr_destroy(&attr); - -#if WIN - thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread_bt, NULL, 0, NULL); -#endif -#else - output.start_frames = FRAME_BLOCK; output.write_cb = &_write_frames; - output.rate_delay = rate_delay; -#endif - LOG_INFO("Init completed."); - -} - -/**************************************************************************************** - * Main output thread - */ -#ifdef USE_BT_RING_BUFFER -static void *output_thread_bt() { - - frames_t frames=0; - frames_t requested_frames=0; - uint32_t timer_start=0, mutex_start=0; - unsigned btbuf_used=0; - output_state state; - DECLARE_ALL_MIN_MAX; - while (running) { - frames=0; - requested_frames=0; - TIME_MEASUREMENT_START(timer_start); - - // Get output state - TIME_MEASUREMENT_START(mutex_start); - LOCK; - state=output.state; - SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1); - - if(state < OUTPUT_STOPPED ){ - // Flushing the buffer will automatically - // lock the mutex - LOG_SDEBUG("Flushing BT buffer"); - buf_flush(btbuf); - } - if (state == OUTPUT_OFF) { - UNLOCK; - LOG_SDEBUG("Output state is off."); - usleep(200000); - continue; - } - output.device_frames = 0; // todo: check if this is the right way do to this. - output.updated = gettime_ms(); - output.frames_played_dmp = output.frames_played; - - TIME_MEASUREMENT_START(mutex_start); - LOCK_BT; - SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex2); - btbuf_used=_buf_used(btbuf); - SET_MIN_MAX_SIZED(btbuf_used,locbtbuff,btbuf->size); - - - // only output more frames if we need them - // so we can release the mutex as quickly as possible - requested_frames = min(_buf_space(btbuf), _buf_cont_write(btbuf))/BYTES_PER_FRAME; - SET_MIN_MAX( requested_frames*BYTES_PER_FRAME,req); - SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size); - SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size); - if(requested_frames>0) - { - frames = _output_frames( requested_frames ); // Keep the transfer buffer full - SET_MIN_MAX(frames*BYTES_PER_FRAME,rec); - if(requested_frames>frames){ - SET_MIN_MAX((requested_frames-frames)*BYTES_PER_FRAME,under); - } - } - - UNLOCK; - UNLOCK_BT; - SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering); - SET_MIN_MAX( requested_frames,req); - - // When playback has started, we want to - // hold the BT out thread - // so the BT data callback isn't constantly interrupted. - TIME_MEASUREMENT_START(timer_start); - if(state>OUTPUT_BUFFER){ - output_bt_suspend(); - } - SET_MIN_MAX(TIME_MEASUREMENT_GET(timer_start),sleep_time); - - /* - * Statistics reporting - */ - static time_t lastTime=0; - if (lastTime <= gettime_ms() ) - { -#define STATS_PERIOD_MS 15000 - lastTime = gettime_ms() + STATS_PERIOD_MS; - LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD1); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD2); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD3); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD4); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local bt buf",locbtbuff)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER ); - LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("Underrun",under)); - LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER ); - LOG_DEBUG(""); - LOG_DEBUG(" ----------+----------+-----------+-----------+ "); - LOG_DEBUG(" max (us) | min (us) | avg(us) | count | "); - LOG_DEBUG(" ----------+----------+-----------+-----------+ "); - LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering)); - LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Output mux(us)",mutex1)); - LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("BT mux(us)",mutex2)); - LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("sleep(us)",mutex2)); - LOG_DEBUG(" ----------+----------+-----------+-----------+"); - RESET_ALL_MIN_MAX; - } - /* - * End Statistics reporting - */ - - - - } - return NULL; -} -#endif -void output_close_bt(void) { - LOG_INFO("close output"); - LOCK; - running = false; - UNLOCK; -#ifdef USE_BT_RING_BUFFER - LOCK_BT; - buf_destroy(btbuf); - UNLOCK_BT; -#endif - output_close_common(); } static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) { -#ifdef USE_BT_RING_BUFFER + + assert(btout != NULL); + if (!silence ) { - DEBUG_LOG_TIMED(200,"Not silence, Writing audio out."); - // TODO need 16 bit fix - - if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) { - _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr); - } - - if (gainL != FIXED_ONE || gainR!= FIXED_ONE) { - _apply_gain(outputbuf, out_frames, gainL, gainR); - } - -#if BYTES_PER_FRAME == 4 - - memcpy(btbuf->writep, outputbuf->readp, out_frames * BYTES_PER_FRAME); - _buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME); - -#else - { - frames_t count = out_frames; - s32_t *_iptr = (s32_t*) outputbuf->readp; - s16_t *_optr = (s16_t*) bt_optr; - while (count--) { - *_optr++ = *_iptr++ >> 16; - *_optr++ = *_iptr++ >> 16; - } - } -#endif - - } else if(output.state >OUTPUT_BUFFER){ - // Don't fill our local buffer with silence frames. - u8_t *buf = silencebuf; - memcpy(btbuf->writep, buf, out_frames * BYTES_PER_FRAME); - _buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME); - } -#else - assert(btout!=NULL); - if (!silence ) { - DEBUG_LOG_TIMED(200,"Not silence, Writing audio out."); - // TODO need 16 bit fix - + if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) { _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr); } @@ -374,7 +81,74 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g u8_t *buf = silencebuf; memcpy(btout, buf, out_frames * BYTES_PER_FRAME); } -#endif return (int)out_frames; } + +int32_t output_bt_data(uint8_t *data, int32_t len) { + int32_t avail_data = 0, wanted_len = 0, start_timer = 0; + + if (len < 0 || data == NULL ) { + return 0; + } + + btout = data; + + // This is how the BTC layer calculates the number of bytes to + // for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes + wanted_len=len; + SET_MIN_MAX(len,req); + TIME_MEASUREMENT_START(start_timer); + LOCK; + output.device_frames = 0; // todo: check if this is the right way do to this. + output.updated = gettime_ms(); + output.frames_played_dmp = output.frames_played; + SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size); + do { + avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full + wanted_len-=avail_data; + } while (wanted_len > 0 && avail_data != 0); + + if (wanted_len > 0) { + SET_MIN_MAX(wanted_len, under); + } + + UNLOCK; + SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time); + SET_MIN_MAX((len-wanted_len), rec); + TIME_MEASUREMENT_START(start_timer); + + return len-wanted_len; +} + +void output_bt_tick(void) { + static time_t lastTime=0; + + LOCK_S; + SET_MIN_MAX_SIZED(_buf_used(streambuf), stream_buf, streambuf->size); + UNLOCK_S; + + if (lastTime <= gettime_ms() ) + { + lastTime = gettime_ms() + STATS_REPORT_DELAY_MS; + LOG_INFO("Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000); + LOG_INFO(" +==========+==========+================+=====+================+"); + LOG_INFO(" | max | min | average | avg | count |"); + LOG_INFO(" | (bytes) | (bytes) | (bytes) | pct | |"); + LOG_INFO(" +==========+==========+================+=====+================+"); + LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf)); + LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt)); + LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req)); + LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec)); + LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under)); + LOG_INFO( " +==========+==========+================+=====+================+"); + LOG_INFO("\n"); + LOG_INFO(" ==========+==========+===========+===========+ "); + LOG_INFO(" max (us) | min (us) | avg(us) | count | "); + LOG_INFO(" ==========+==========+===========+===========+ "); + LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time)); + LOG_INFO(" ==========+==========+===========+===========+"); + RESET_ALL_MIN_MAX; + } +} + diff --git a/main/output_dac.c.tes b/main/output_dac.c.tes deleted file mode 100644 index 2f2d8229..00000000 --- a/main/output_dac.c.tes +++ /dev/null @@ -1,162 +0,0 @@ -#include "squeezelite.h" -#include "driver/i2s.h" - -static log_level loglevel; - -static bool running = true; - -extern struct outputstate output; -extern struct buffer *outputbuf; -extern struct buffer *streambuf; - -#define LOCK mutex_lock(outputbuf->mutex) -#define UNLOCK mutex_unlock(outputbuf->mutex) - -#define FRAME_BLOCK MAX_SILENCE_FRAMES - -extern u8_t *silencebuf; - -#define I2S_NUM (0) -#define WAVE_FREQ_HZ (100) -#define PI (3.14159265) -#define I2S_BCK_IO (GPIO_NUM_26) -#define I2S_WS_IO (GPIO_NUM_25) -#define I2S_DO_IO (GPIO_NUM_22) -#define I2S_DI_IO (-1) -// buffer length is expressed in number of samples -#define I2S_BUF_LEN 60 - -static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, - s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, - ISAMPLE_T **cross_ptr); - -void set_volume(unsigned left, unsigned right) { - LOG_DEBUG("setting internal gain left: %u right: %u", left, right); - LOCK; - output.gainL = left; - output.gainR = right; - // TODO - output.gainL = FIXED_ONE; - output.gainR = FIXED_ONE; - UNLOCK; -} - -static void *output_thread(void *arg) { - bool start = true; - bool output_off = (output.state == OUTPUT_OFF); - bool probe_device = (arg != NULL); - int err; - - while (running) { - // todo: implement output off logic? - // todo: call i2s_set_clock here if rate is changed - LOCK; - - output.device_frames = 0; - output.updated = gettime_ms(); - output.frames_played_dmp = output.frames_played; - - _output_frames(I2S_BUF_LEN*2); // fill at least one DMA buffer with stereo signal - - UNLOCK; - } - - return 0; -} - -static pthread_t thread; - -void output_init_dac(log_level level, char *device, unsigned output_buf_size, - char *params, unsigned rates[], unsigned rate_delay, unsigned idle) { - loglevel = level; - - LOG_INFO("init output DAC"); - - memset(&output, 0, sizeof(output)); - - output.start_frames = 0; //CONFIG_ //FRAME_BLOCK * 2; - output.write_cb = &_write_frames; - output.rate_delay = rate_delay; - - // ensure output rate is specified to avoid test open - if (!rates[0]) { - rates[0] = 44100; - } - device = "DAC"; - output_init_common(level, device, output_buf_size, rates, idle); - - i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX - .sample_rate = output.current_sample_rate, - .bits_per_sample = BYTES_PER_FRAME * 8, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_I2S - | I2S_COMM_FORMAT_I2S_MSB, - .dma_buf_count = 6, //todo: tune this parameter. Expressed in numbrer of buffers - .dma_buf_len = I2S_BUF_LEN, // todo: tune this parameter. Expressed in number of samples. Byte size depends on bit depth - .use_apll = false, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 - }; - i2s_pin_config_t pin_config = { .bck_io_num = I2S_BCK_IO, .ws_io_num = - I2S_WS_IO, .data_out_num = I2S_DO_IO, .data_in_num = I2S_DI_IO //Not used - }; - i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); - i2s_set_pin(I2S_NUM, &pin_config); - i2s_set_clk(I2S_NUM, output.current_sample_rate, i2s_config.bits_per_sample, 2); - -#if LINUX || OSX || FREEBSD || POSIX - pthread_attr_t attr; - pthread_attr_init(&attr); -#ifdef PTHREAD_STACK_MIN - pthread_attr_setstacksize(&attr, - PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE); -#endif - pthread_create(&thread, &attr, output_thread, NULL); - pthread_attr_destroy(&attr); -#endif -#if WIN - thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread, NULL, 0, NULL); -#endif - -} - -void output_close_dac(void) { - LOG_INFO("close output"); - LOCK; - running = false; - UNLOCK; - - output_close_common(); -} - -static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, - s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, - ISAMPLE_T **cross_ptr) { - - u8_t *obuf; - size_t i2s_bytes_write = 0; - - if (!silence) { - - if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) { - _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr); - } - - obuf = outputbuf->readp; - - } else { - - obuf = silencebuf; - } - - //_scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format); - -// buffill += out_frames; - i2s_write(I2S_NUM, obuf, out_frames *BYTES_PER_FRAME, &i2s_bytes_write, 100); - - - - return (int)i2s_bytes_write * BYTES_PER_FRAME; - -} - diff --git a/main/output_embedded.c b/main/output_embedded.c new file mode 100644 index 00000000..89e06cbc --- /dev/null +++ b/main/output_embedded.c @@ -0,0 +1,119 @@ +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "squeezelite.h" + +extern struct outputstate output; +extern struct buffer *outputbuf; + +#define FRAME_BLOCK MAX_SILENCE_FRAMES + +#define LOCK mutex_lock(outputbuf->mutex) +#define UNLOCK mutex_unlock(outputbuf->mutex) + +extern void set_volume_i2s(unsigned left, unsigned right); +extern void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, + unsigned rates[], unsigned rate_delay, unsigned idle); +extern void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, + unsigned rates[], unsigned rate_delay, unsigned idle); + +static log_level loglevel; + +static void (*volume_cb)(unsigned left, unsigned right); +static void (*close_cb)(void); + +void output_init_embedded(log_level level, char *device, unsigned output_buf_size, char *params, + unsigned rates[], unsigned rate_delay, unsigned idle) { + loglevel = level; + LOG_INFO("init device: %s", device); + + memset(&output, 0, sizeof(output)); + output_init_common(level, device, output_buf_size, rates, idle); + output.start_frames = FRAME_BLOCK; + output.rate_delay = rate_delay; + + if (strstr(device, "BT ")) { + LOG_INFO("init Bluetooth"); + output_init_bt(level, device, output_buf_size, params, rates, rate_delay, idle); + } else { + LOG_INFO("init I2S"); + //volume_cb = set_volume_i2s; + //close_cb = output_close_i2s; + //output_init_i2s(level, device, output_buf_size, params, rates, rate_delay, idle); + } + + LOG_INFO("init completed."); +} + +void output_close_embedded(void) { + LOG_INFO("close output"); + output_close_common(); + if (close_cb) (*close_cb)(); +} + +void set_volume(unsigned left, unsigned right) { + LOG_DEBUG("setting internal gain left: %u right: %u", left, right); + if (!volume_cb) { + LOCK; + output.gainL = left; + output.gainR = right; + UNLOCK; + } else (*volume_cb)(left, right); +} + +bool test_open(const char *device, unsigned rates[], bool userdef_rates) { + memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned)); + if (!strcmp(device, "BT")) { + rates[0] = 44100; + } else { + unsigned _rates[] = { 96000, 88200, 48000, 44100, 32000, 0 }; + memcpy(rates, _rates, sizeof(_rates)); + } + return true; +} + +char* output_state_str(void){ + output_state state; + LOCK; + state = output.state; + UNLOCK; + switch (state) { + case OUTPUT_OFF: return STR(OUTPUT_OFF); + case OUTPUT_STOPPED: return STR(OUTPUT_STOPPED); + case OUTPUT_BUFFER: return STR(OUTPUT_BUFFER); + case OUTPUT_RUNNING: return STR(OUTPUT_RUNNING); + case OUTPUT_PAUSE_FRAMES: return STR(OUTPUT_PAUSE_FRAMES); + case OUTPUT_SKIP_FRAMES: return STR(OUTPUT_SKIP_FRAMES); + case OUTPUT_START_AT: return STR(OUTPUT_START_AT); + default: return "OUTPUT_UNKNOWN_STATE"; + } +} + +bool output_stopped(void) { + output_state state; + LOCK; + state = output.state; + UNLOCK; + return state <= OUTPUT_STOPPED; +} + + + + diff --git a/main/slimproto.c b/main/slimproto.c index e7b9cc4c..ec53d283 100644 --- a/main/slimproto.c +++ b/main/slimproto.c @@ -436,13 +436,8 @@ static void process_audg(u8_t *pkt, int len) { audg->gainR = unpackN(&audg->gainR); LOG_DEBUG("audg gainL: %u gainR: %u adjust: %u", audg->gainL, audg->gainR, audg->adjust); -#if CONFIG_BTAUDIO - set_volume_bt(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE); -#elif CONFIG_DACAUDIO - set_volume_dac(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE); -#else + set_volume(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE); -#endif } static void process_setd(u8_t *pkt, int len) { diff --git a/main/squeezelite.h b/main/squeezelite.h index 59ced6e4..89dec4b3 100644 --- a/main/squeezelite.h +++ b/main/squeezelite.h @@ -34,6 +34,7 @@ #define VERSION "v" MAJOR_VERSION "." MINOR_VERSION "-" MICRO_VERSION #endif + #if !defined(MODEL_NAME) #define MODEL_NAME SqueezeLite #endif @@ -42,16 +43,11 @@ #define STR(macro) QUOTE(macro) #define MODEL_NAME_STRING STR(MODEL_NAME) -#if defined(EMBEDDED) -#define POSIX 1 -#include "embedded.h" -#endif -#ifndef PTHREAD_SET_NAME -#define PTHREAD_SET_NAME(n) -#endif - -// build detection -#if defined(linux) +// build detection +#if defined (EMBEDDED) +#undef EMBEDDED +#define EMBEDDED 1 +#elif defined(linux) #define LINUX 1 #define OSX 0 #define WIN 0 @@ -78,27 +74,19 @@ #define PA18API 1 #define OSX 0 #define WIN 0 -#elif defined (POSIX) -#undef POSIX -#define POSIX 1 #else #error unknown target #endif - -#if defined(CONFIG_DACAUDIO) -#undef CONFIG_DACAUDIO -#define CONFIG_DACAUDIO 1 -#elif defined(CONFIG_BTAUDIO) -#undef CONFIG_BTAUDIO -#define CONFIG_BTAUDIO 1 -#elif LINUX && !defined(PORTAUDIO) +#if !EMBEDDED +#if LINUX && !defined(PORTAUDIO) #define ALSA 1 #define PORTAUDIO 0 #else #define ALSA 0 #define PORTAUDIO 1 #endif +#endif #if !defined(LOOPBACK) #if SUN @@ -278,18 +266,18 @@ #include #include -#if LINUX || OSX || FREEBSD || POSIX +#if EMBEDDED +#include "embedded.h" +#endif + +#if LINUX || OSX || FREEBSD || EMBEDDED #include #include #include #include #include #include -#if POSIX #include -#else -#include -#endif #if !LINKALL #include #endif @@ -299,14 +287,10 @@ #include #endif /* SUN */ -#ifndef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 256 -#endif - -#define STREAM_THREAD_STACK_SIZE 8 * 1024 -#define DECODE_THREAD_STACK_SIZE 20 * 1024 -#define OUTPUT_THREAD_STACK_SIZE 8 * 1024 -#define IR_THREAD_STACK_SIZE 8 * 1024 +#define STREAM_THREAD_STACK_SIZE 64 * 1024 +#define DECODE_THREAD_STACK_SIZE 128 * 1024 +#define OUTPUT_THREAD_STACK_SIZE 64 * 1024 +#define IR_THREAD_STACK_SIZE 64 * 1024 #if !OSX #define thread_t pthread_t; #endif @@ -314,13 +298,12 @@ #define last_error() errno #define ERROR_WOULDBLOCK EWOULDBLOCK +#if !EMBEDDED #ifdef SUN typedef uint8_t u8_t; typedef uint16_t u16_t; typedef uint32_t u32_t; typedef uint64_t u64_t; -#elif POSIX -typedef unsigned long long u64_t; #else typedef u_int8_t u8_t; typedef u_int16_t u16_t; @@ -330,29 +313,20 @@ typedef u_int64_t u64_t; typedef int16_t s16_t; typedef int32_t s32_t; typedef int64_t s64_t; +#endif #define mutex_type pthread_mutex_t #define mutex_create(m) pthread_mutex_init(&m, NULL) -#if POSIX -#define mutex_create_p(m) mutex_create(m) -#else +#if HAS_MUTEX_CREATE_P #define mutex_create_p(m) pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); pthread_mutex_init(&m, &attr); pthread_mutexattr_destroy(&attr) +#else +#define mutex_create_p(m) mutex_create(m) #endif #define mutex_lock(m) pthread_mutex_lock(&m) #define mutex_unlock(m) pthread_mutex_unlock(&m) #define mutex_destroy(m) pthread_mutex_destroy(&m) -#define mutex_broadcast_cond(m) pthread_cond_broadcast(&m) -#define mutex_cond_wait(c,m) pthread_cond_wait(&c, &m) -#define mutex_cond_init(c) pthread_cond_init(&c, NULL) -#define thread_cond_type pthread_cond_t #define thread_type pthread_t #endif -#ifdef EMBEDDED -#define local_exit(r) {static int ret=r; pthread_exit(&ret);} -#else -#define local_exit(r) exit(r) -#endif - #if WIN @@ -491,24 +465,7 @@ void logprint(const char *fmt, ...); #define LOG_INFO(fmt, ...) if (loglevel >= lINFO) logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__) #define LOG_DEBUG(fmt, ...) if (loglevel >= lDEBUG) logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__) #define LOG_SDEBUG(fmt, ...) if (loglevel >= lSDEBUG) logprint("%s %s:%d " fmt "\n", logtime(), __FUNCTION__, __LINE__, ##__VA_ARGS__) -static inline void DEBUG_LOG_TIMED(uint32_t delayms, char * strFmt, ...) -{ - static log_level loglevel; - va_list args; - va_start(args, strFmt); - static uint32_t nextDebugLog=0; - if(esp_timer_get_time()>nextDebugLog) - { - if (loglevel >= lDEBUG) - { - logprint("%s %s:%d ", logtime(), __FUNCTION__, __LINE__); - logprint(strFmt , args); - logprint("\n"); - } - nextDebugLog=esp_timer_get_time()+delayms*1000; - } -} // utils.c (non logging) typedef enum { EVENT_TIMEOUT = 0, EVENT_READ, EVENT_WAKE } event_type; #if WIN && USE_SSL @@ -670,8 +627,6 @@ typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE, U8, U16_LE, U16_BE, U32_LE, U32_ #else typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE, S24_BE, S24_3BE, S16_BE, S8_BE } output_format; #endif -extern uint8_t get_bytes_per_frame(output_format fmt); - typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state; typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir; @@ -763,26 +718,17 @@ void output_close_pa(void); void _pa_open(void); #endif -// output_dac.c - -void set_volume_dac(unsigned left, unsigned right); +// output_embedded.c +#if EMBEDDED +void set_volume(unsigned left, unsigned right); bool test_open(const char *device, unsigned rates[], bool userdef_rates); -void output_init_dac(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle); -void output_close_dac(void); -void hal_dac_init(const char * options); - -//output_bt.c -void set_volume_bt(unsigned left, unsigned right); -bool test_open(const char *device, unsigned rates[], bool userdef_rates); -void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle); -void output_close_bt(void); -extern void hal_bluetooth_init(const char * options); -void output_bt_check_buffer(); - - +void output_init_embedded(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle); +void output_close_embedded(void); +#else // output_stdout.c void output_init_stdout(log_level level, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay); void output_close_stdout(void); +#endif // output_pack.c void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format); diff --git a/main/stream.c b/main/stream.c index 288d9563..267a7581 100644 --- a/main/stream.c +++ b/main/stream.c @@ -373,7 +373,7 @@ void stream_init(log_level level, unsigned stream_buf_size) { buf_init(streambuf, stream_buf_size); if (streambuf->buf == NULL) { LOG_ERROR("unable to malloc buffer"); - local_exit(0); + exit(0); } #if USE_SSL @@ -405,8 +405,8 @@ void stream_init(log_level level, unsigned stream_buf_size) { #if LINUX || FREEBSD touch_memory(streambuf->buf, streambuf->size); #endif -PTHREAD_SET_NAME("stream"); -#if LINUX || OSX || FREEBSD || POSIX + +#if LINUX || OSX || FREEBSD || EMBEDDED pthread_attr_t attr; pthread_attr_init(&attr); #ifdef PTHREAD_STACK_MIN @@ -414,6 +414,9 @@ PTHREAD_SET_NAME("stream"); #endif pthread_create(&thread, &attr, stream_thread, NULL); pthread_attr_destroy(&attr); +#if HAS_PTHREAD_SETNAME_NP + pthread_setname_np(thread, "stream"); +#endif #endif #if WIN thread = CreateThread(NULL, STREAM_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&stream_thread, NULL, 0, NULL); diff --git a/main/utils.c b/main/utils.c index 764feb1b..a3a264cc 100644 --- a/main/utils.c +++ b/main/utils.c @@ -21,7 +21,7 @@ #include "squeezelite.h" -#if LINUX || OSX || FREEBSD || POSIX +#if LINUX || OSX || FREEBSD || EMBEDDED #include #include #include @@ -103,7 +103,7 @@ u32_t gettime_ms(void) { #if WIN return GetTickCount(); #else -#if LINUX || FREEBSD || POSIX +#if LINUX || FREEBSD || EMBEDDED struct timespec ts; #ifdef CLOCK_MONOTONIC if (!clock_gettime(CLOCK_MONOTONIC, &ts)) { @@ -561,77 +561,3 @@ char *strcasestr(const char *haystack, const char *needle) { return NULL; } #endif -uint8_t get_bytes_per_frame(output_format fmt) -{ - uint8_t bpf=0; - - switch (fmt) { - case S32_LE: - bpf=4*2; - break; - case S24_LE: - bpf=3*2; - break; - case S24_3LE: - bpf=3*2; - break; - case S16_LE: - bpf=2*2; - break; - case S24_BE: - bpf=3*2; - break; - case S24_3BE: - bpf=3*2; - break; - case S16_BE: - bpf=2*2; - break; - case S8_BE: - bpf=2*2; - break; -#if DSD - case U8: - bpf=1*2; - break; - case U16_LE: - bpf=2*2; - break; - case U16_BE: - bpf=2*2; - break; - case U32_LE: - bpf=4*2; - break; - case U32_BE: - bpf=4*2; - break; -#endif - default: - break; - } - assert(bpf>0); - return bpf; -} - -char * get_output_state_desc(output_state state){ - switch (state) { - case OUTPUT_OFF: - return STR(OUTPUT_OFF); - case OUTPUT_STOPPED: - return STR(OUTPUT_STOPPED); - case OUTPUT_BUFFER: - return STR(OUTPUT_BUFFER); - case OUTPUT_RUNNING: - return STR(OUTPUT_RUNNING); - case OUTPUT_PAUSE_FRAMES: - return STR(OUTPUT_PAUSE_FRAMES); - case OUTPUT_SKIP_FRAMES: - return STR(OUTPUT_SKIP_FRAMES); - case OUTPUT_START_AT: - return STR(OUTPUT_START_AT); - default: - return "OUTPUT_UNKNOWN_STATE"; - } - return ""; -}