mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 20:47:08 +03:00
BT ring buffering
This commit is contained in:
@@ -97,13 +97,18 @@ static void bt_app_task_handler(void *arg)
|
|||||||
free(msg.param);
|
free(msg.param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_DEBUG("No messaged received from queue.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_app_task_start_up(void)
|
void bt_app_task_start_up(void)
|
||||||
{
|
{
|
||||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||||
xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
|
assert(s_bt_app_task_queue!=NULL);
|
||||||
|
assert(xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle)==pdPASS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ 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);
|
LOG_DEBUG("include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs);
|
||||||
|
|
||||||
mutex_create(decode.mutex);
|
mutex_create(decode.mutex);
|
||||||
|
PTHREAD_SET_NAME("decode");
|
||||||
#if LINUX || OSX || FREEBSD || POSIX
|
#if LINUX || OSX || FREEBSD || POSIX
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#if defined(ESP_PLATFORM)
|
#if defined(ESP_PLATFORM)
|
||||||
#include "sdkconfig.h"
|
#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); }
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
284
main/esp32.c
284
main/esp32.c
@@ -27,19 +27,63 @@
|
|||||||
#include "esp_avrc_api.h"
|
#include "esp_avrc_api.h"
|
||||||
#include "esp_pthread.h"
|
#include "esp_pthread.h"
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
|
|
||||||
|
const char * art_a2dp_connected[]={"\n\n",
|
||||||
|
" ___ _____ _____ _____ _ _ _ \n",
|
||||||
|
" /\\ |__ \\| __ \\| __ \\ / ____| | | | | |\n",
|
||||||
|
" / \\ ) | | | | |__) | | | ___ _ __ _ __ ___ ___| |_ ___ __| | |\n",
|
||||||
|
" / /\\ \\ / /| | | | ___/ | | / _ \\| '_ \\| '_ \\ / _ \\/ __| __/ _ \\/ _` | |\n",
|
||||||
|
" / ____ \\ / /_| |__| | | | |___| (_) | | | | | | | __/ (__| || __/ (_| |_|\n",
|
||||||
|
" /_/ \\_\\____|_____/|_| \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__\\___|\\__,_(_)\n\n",
|
||||||
|
"\0"};
|
||||||
|
const char * art_a2dp_connecting[]= {"\n\n",
|
||||||
|
" ___ _____ _____ _____ _ _ \n",
|
||||||
|
" /\\ |__ \\| __ \\| __ \\ / ____| | | (_) \n",
|
||||||
|
" / \\ ) | | | | |__) | | | ___ _ __ _ __ ___ ___| |_ _ _ __ __ _ \n",
|
||||||
|
" / /\\ \\ / /| | | | ___/ | | / _ \\| '_ \\| '_ \\ / _ \\/ __| __| | '_ \\ / _` | \n",
|
||||||
|
" / ____ \\ / /_| |__| | | | |___| (_) | | | | | | | __/ (__| |_| | | | | (_| |_ _ _ \n",
|
||||||
|
" /_/ \\_\\____|_____/|_| \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__|_|_| |_|\\__, (_|_|_)\n",
|
||||||
|
" __/ | \n",
|
||||||
|
" |___/ \n\n",
|
||||||
|
"\0"};
|
||||||
|
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
#define BT_AV_TAG "BT_AV"
|
#define BT_AV_TAG "BT_AV"
|
||||||
extern log_level loglevel;
|
extern log_level loglevel;
|
||||||
extern struct outputstate output;
|
extern struct outputstate output;
|
||||||
extern struct buffer *outputbuf;
|
extern struct buffer *outputbuf;
|
||||||
extern struct buffer *streambuf;
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
#define LOCK_BT mutex_lock(btbuf->mutex)
|
||||||
|
#define UNLOCK_BT mutex_unlock(btbuf->mutex)
|
||||||
extern struct buffer *btbuf;
|
extern struct buffer *btbuf;
|
||||||
|
#else
|
||||||
|
extern uint8_t * btout;
|
||||||
|
#endif
|
||||||
time_t disconnect_time=0;
|
time_t disconnect_time=0;
|
||||||
#define LOCK mutex_lock(outputbuf->mutex)
|
#define LOCK mutex_lock(outputbuf->mutex)
|
||||||
#define UNLOCK mutex_unlock(outputbuf->mutex)
|
#define UNLOCK mutex_unlock(outputbuf->mutex)
|
||||||
#define LOCK_BT mutex_lock(btbuf->mutex)
|
|
||||||
#define UNLOCK_BT mutex_unlock(btbuf->mutex)
|
|
||||||
int64_t connecting_timeout = 0;
|
int64_t connecting_timeout = 0;
|
||||||
|
|
||||||
#ifndef CONFIG_A2DP_SINK_NAME
|
#ifndef CONFIG_A2DP_SINK_NAME
|
||||||
#define CONFIG_A2DP_SINK_NAME "btspeaker" // fix some compile errors when BT is not chosen
|
#define CONFIG_A2DP_SINK_NAME "btspeaker" // fix some compile errors when BT is not chosen
|
||||||
#endif
|
#endif
|
||||||
@@ -52,19 +96,24 @@ int64_t connecting_timeout = 0;
|
|||||||
#ifndef CONFIG_A2DP_CONTROL_DELAY_MS
|
#ifndef CONFIG_A2DP_CONTROL_DELAY_MS
|
||||||
#define CONFIG_A2DP_CONTROL_DELAY_MS 1000
|
#define CONFIG_A2DP_CONTROL_DELAY_MS 1000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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 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 IS_A2DP_TIMER_OVER esp_timer_get_time() >= connecting_timeout
|
||||||
|
|
||||||
#define FRAME_TO_BYTES(f) f*BYTES_PER_FRAME
|
#define FRAME_TO_BYTES(f) f*BYTES_PER_FRAME
|
||||||
#define BYTES_TO_FRAME(b) b/BYTES_PER_FRAME
|
#define BYTES_TO_FRAME(b) b/BYTES_PER_FRAME
|
||||||
#define FRAMES_TO_MS(f) 1000*f/output.current_sample_rate
|
|
||||||
#define BYTES_TO_MS(b) FRAMES_TO_MS(BYTES_TO_FRAME(b))
|
|
||||||
|
|
||||||
//#define SET_MIN_MAX(val,var) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var
|
|
||||||
//#define RESET_MIN_MAX(var,mv) min_##var=mv##_MAX; max_##var=mv##_MIN
|
#define RESET_ALL_MIN_MAX RESET_MIN_MAX(req); RESET_MIN_MAX(rec); RESET_MIN_MAX(bt);RESET_MIN_MAX_DURATION(lock_bt_time);RESET_MIN_MAX(under); RESET_MIN_MAX_DURATION(lock_out_time)
|
||||||
//#define DECLARE_MIN_MAX(var,t,mv) static t min_##var = mv##_MAX, max_##var = mv##_MIN; t var=0
|
|
||||||
#define DECLARE_ALL_MIN_MAX DECLARE_MIN_MAX(req, long,LONG); DECLARE_MIN_MAX(rec, long,LONG); DECLARE_MIN_MAX(bt, long,LONG);DECLARE_MIN_MAX(lock_bt_time, long,LONG);DECLARE_MIN_MAX(under, long,LONG);DECLARE_MIN_MAX(o, long,LONG);
|
DECLARE_MIN_MAX(req);
|
||||||
#define RESET_ALL_MIN_MAX RESET_MIN_MAX(req,LONG); RESET_MIN_MAX(rec,LONG); RESET_MIN_MAX(bt,LONG);RESET_MIN_MAX(lock_bt_time,LONG);RESET_MIN_MAX(under,LONG);RESET_MIN_MAX(o,LONG);
|
DECLARE_MIN_MAX(rec);
|
||||||
|
DECLARE_MIN_MAX(bt);
|
||||||
|
DECLARE_MIN_MAX_DURATION(lock_bt_time);
|
||||||
|
DECLARE_MIN_MAX(under);
|
||||||
|
DECLARE_MIN_MAX_DURATION(lock_out_time);
|
||||||
|
|
||||||
static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param);
|
static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param);
|
||||||
|
|
||||||
@@ -186,7 +235,6 @@ static esp_bd_addr_t s_peer_bda = {0};
|
|||||||
static uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
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_a2d_state = APP_AV_STATE_IDLE;
|
||||||
static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||||
static int s_intv_cnt = 0;
|
|
||||||
static uint32_t s_pkt_cnt = 0;
|
static uint32_t s_pkt_cnt = 0;
|
||||||
|
|
||||||
static TimerHandle_t s_tmr;
|
static TimerHandle_t s_tmr;
|
||||||
@@ -198,6 +246,7 @@ void hal_bluetooth_init(log_level level)
|
|||||||
* Bluetooth audio source init Start
|
* Bluetooth audio source init Start
|
||||||
*/
|
*/
|
||||||
loglevel = level;
|
loglevel = level;
|
||||||
|
bt_set_log_level(level);
|
||||||
//running_test = false;
|
//running_test = false;
|
||||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
||||||
|
|
||||||
@@ -244,27 +293,23 @@ void hal_bluetooth_init(log_level level)
|
|||||||
esp_bt_gap_set_pin(pin_type, 0, pin_code);
|
esp_bt_gap_set_pin(pin_type, 0, pin_code);
|
||||||
|
|
||||||
}
|
}
|
||||||
DECLARE_ALL_MIN_MAX ;
|
|
||||||
|
|
||||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||||
{
|
{
|
||||||
static int count = 0;
|
#ifdef USE_BT_RING_BUFFER
|
||||||
unsigned avail_data=0,wanted_len=0;
|
int32_t avail_data=0,wanted_len=0, start_timer=0;
|
||||||
|
|
||||||
if (len < 0 || data == NULL ) {
|
if (len < 0 || data == NULL ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// This is how the BTC layer calculates the number of bytes to
|
// 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
|
// for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes
|
||||||
|
|
||||||
wanted_len=len;
|
wanted_len=len;
|
||||||
|
TIME_MEASUREMENT_START(start_timer);
|
||||||
SET_MIN_MAX(len/BYTES_PER_FRAME,req);
|
SET_MIN_MAX(len,req);
|
||||||
LOCK_BT;
|
LOCK_BT;
|
||||||
SET_MIN_MAX(_buf_used(btbuf)/BYTES_PER_FRAME,bt);
|
SET_MIN_MAX_SIZED(_buf_used(btbuf),bt,btbuf->size);
|
||||||
do {
|
do {
|
||||||
|
|
||||||
avail_data=min(_buf_cont_read(btbuf),wanted_len);
|
avail_data=min(_buf_cont_read(btbuf),wanted_len);
|
||||||
@@ -275,54 +320,57 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
|||||||
data+=avail_data;
|
data+=avail_data;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// SET_MIN_MAX(wanted_len, under);
|
assert(wanted_len>0);
|
||||||
//LOG_WARN("BT Buffering underrun! %7d bytes Requested, %7d bytes missing.", len,wanted_len);
|
assert(avail_data==0);
|
||||||
// LOG_INFO( "count:%d, current sample rate: %d",count,output.current_sample_rate);
|
SET_MIN_MAX(wanted_len, under);
|
||||||
// LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
// LOG_INFO( " max | min | current| | max | min | current |");
|
|
||||||
// LOG_INFO( " (ms) | (ms) | (ms)| | (bytes) | (bytes) | (bytes) |");
|
|
||||||
// LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
// 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("available",bt));
|
|
||||||
// LOG_INFO(" ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
// LOG_INFO("");
|
|
||||||
// LOG_INFO(" max (us) | min (us) |current(us)| ");
|
|
||||||
// LOG_INFO(" ----------+----------+-----------+ ");
|
|
||||||
// LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
|
|
||||||
// LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("i2s tfr(us)",i2s_time));
|
|
||||||
// LOG_INFO(" ----------+----------+-----------+ ");
|
|
||||||
|
|
||||||
RESET_ALL_MIN_MAX;
|
|
||||||
}
|
}
|
||||||
} while (wanted_len > 0 && avail_data != 0);
|
} while (wanted_len > 0 && avail_data != 0);
|
||||||
|
|
||||||
UNLOCK_BT;
|
UNLOCK_BT;
|
||||||
SET_MIN_MAX((len-wanted_len)/BYTES_PER_FRAME, rec);
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_bt_time);
|
||||||
SET_MIN_MAX(wanted_len/BYTES_PER_FRAME, under);
|
SET_MIN_MAX((len-wanted_len), rec);
|
||||||
SET_MIN_MAX(_buf_used(outputbuf)/BYTES_PER_FRAME,o);
|
TIME_MEASUREMENT_START(start_timer);
|
||||||
|
output_bt_check_buffer();
|
||||||
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
|
||||||
|
return len-wanted_len;
|
||||||
|
|
||||||
|
#else
|
||||||
|
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;
|
LOCK;
|
||||||
output.device_frames = 0;
|
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);
|
||||||
|
}
|
||||||
|
output.device_frames = 0; // todo: check if this is the right way do to this.
|
||||||
output.updated = gettime_ms();
|
output.updated = gettime_ms();
|
||||||
output.frames_played_dmp = output.frames_played;
|
output.frames_played_dmp = output.frames_played;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
//count++;
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
|
||||||
// TIMED_SECTION_START(5000);
|
SET_MIN_MAX((len-wanted_len), rec);
|
||||||
// //LOG_INFO( "count:%d, current sample rate: %d, bytes per frame: %d",count,output.current_sample_rate);
|
TIME_MEASUREMENT_START(start_timer);
|
||||||
// LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
output_bt_check_buffer();
|
||||||
// LOG_INFO( " max | min | current| | max | min | current |");
|
|
||||||
// LOG_INFO( " (ms) | (ms) | (ms)| | (bytes) | (bytes) | (bytes) |");
|
|
||||||
// LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
// LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
|
|
||||||
// LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("available",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(" ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
// RESET_ALL_MIN_MAX;
|
|
||||||
// TIMED_SECTION_END;
|
|
||||||
return len-wanted_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return len-wanted_len;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
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);
|
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
||||||
@@ -423,10 +471,10 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param)
|
|||||||
//LOG_DEBUG("%s state %s, evt 0x%x, output state: %d", __func__, APP_AV_STATE_DESC[s_a2d_state], event, output.state);
|
//LOG_DEBUG("%s state %s, evt 0x%x, output state: %d", __func__, APP_AV_STATE_DESC[s_a2d_state], event, output.state);
|
||||||
switch (s_a2d_state) {
|
switch (s_a2d_state) {
|
||||||
case APP_AV_STATE_DISCOVERING:
|
case APP_AV_STATE_DISCOVERING:
|
||||||
LOG_SDEBUG("state %s, evt 0x%x, output state: %d", APP_AV_STATE_DESC[s_a2d_state], event, output.state);
|
LOG_SDEBUG("state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
|
||||||
break;
|
break;
|
||||||
case APP_AV_STATE_DISCOVERED:
|
case APP_AV_STATE_DISCOVERED:
|
||||||
LOG_SDEBUG("state %s, evt 0x%x, output state: %d", APP_AV_STATE_DESC[s_a2d_state], event, output.state);
|
LOG_SDEBUG("state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
|
||||||
break;
|
break;
|
||||||
case APP_AV_STATE_UNCONNECTED:
|
case APP_AV_STATE_UNCONNECTED:
|
||||||
bt_app_av_state_unconnected(event, param);
|
bt_app_av_state_unconnected(event, param);
|
||||||
@@ -633,16 +681,22 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
|||||||
esp_a2d_cb_param_t *a2d = NULL;
|
esp_a2d_cb_param_t *a2d = NULL;
|
||||||
LOCK;
|
LOCK;
|
||||||
output_state out_state=output.state;
|
output_state out_state=output.state;
|
||||||
|
unsigned start_frames = output.start_frames;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
LOCK_BT;
|
||||||
unsigned bt_buffer_used=_buf_used(btbuf);
|
unsigned bt_buffer_used=_buf_used(btbuf);
|
||||||
|
UNLOCK_BT;
|
||||||
|
#endif
|
||||||
switch (s_media_state) {
|
switch (s_media_state) {
|
||||||
case APP_AV_MEDIA_STATE_IDLE: {
|
case APP_AV_MEDIA_STATE_IDLE: {
|
||||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||||
if(out_state > OUTPUT_STOPPED)
|
if(out_state > OUTPUT_OFF)
|
||||||
{
|
{
|
||||||
LOG_INFO("buffering output, a2dp media ready and connected. Starting checking if ready...");
|
LOG_INFO("Output state is %s, a2dp media ready and connected. Checking if A2DP is ready.", get_output_state_desc(out_state));
|
||||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
|
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
|
} else if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
|
||||||
a2d = (esp_a2d_cb_param_t *)(param);
|
a2d = (esp_a2d_cb_param_t *)(param);
|
||||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY &&
|
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY &&
|
||||||
@@ -656,21 +710,39 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
|||||||
}
|
}
|
||||||
case APP_AV_MEDIA_STATE_BUFFERING: {
|
case APP_AV_MEDIA_STATE_BUFFERING: {
|
||||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||||
if(out_state > OUTPUT_BUFFER ){
|
switch (out_state) {
|
||||||
|
case OUTPUT_RUNNING :
|
||||||
|
case OUTPUT_PAUSE_FRAMES :
|
||||||
|
case OUTPUT_SKIP_FRAMES:
|
||||||
|
case OUTPUT_START_AT:
|
||||||
|
#ifndef USE_BT_RING_BUFFER
|
||||||
|
case OUTPUT_BUFFER:
|
||||||
|
#endif
|
||||||
// Buffer is ready, local buffer has some data, start playback!
|
// Buffer is ready, local buffer has some data, start playback!
|
||||||
|
LOG_INFO("Buffering complete, out state is %s, a2dp media ready and connected. Starting playback! ", get_output_state_desc(out_state));
|
||||||
// ensure that we can get a lock on the buffer.
|
|
||||||
// when we release start, the data call back
|
|
||||||
// will be begging for data
|
|
||||||
LOG_INFO("Buffering complete, a2dp media ready and connected. Starting playback! ");
|
|
||||||
s_media_state = APP_AV_MEDIA_STATE_STARTING;
|
s_media_state = APP_AV_MEDIA_STATE_STARTING;
|
||||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
|
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
|
||||||
LOG_INFO("Signaling of ESP_A2D_MEDIA_CTRL_START complete. ");
|
#ifdef USE_BT_RING_BUFFER
|
||||||
}
|
break;
|
||||||
else{
|
|
||||||
LOG_INFO("Buffering... BT Buffer: %d bytes ",bt_buffer_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case OUTPUT_BUFFER:
|
||||||
|
|
||||||
|
LOG_DEBUG("Buffering... BT Buffer: %d bytes. Start threshold: %u, ",bt_buffer_used, start_frames*BYTES_PER_FRAME);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case OUTPUT_STOPPED:
|
||||||
|
case OUTPUT_OFF:
|
||||||
|
LOG_DEBUG("Output state is %s. Changing app status to ",get_output_state_desc(out_state));
|
||||||
|
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||||
|
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
output_bt_check_buffer();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unknown output status while waiting for buffering to complete %d",out_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
LOG_WARN("Received unknown event while in state APP_AV_MEDIA_STATE_BUFFERING");
|
LOG_WARN("Received unknown event while in state APP_AV_MEDIA_STATE_BUFFERING");
|
||||||
@@ -686,7 +758,6 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
|||||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
|
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
|
||||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
||||||
LOG_INFO("a2dp media started successfully.");
|
LOG_INFO("a2dp media started successfully.");
|
||||||
s_intv_cnt = 0;
|
|
||||||
s_media_state = APP_AV_MEDIA_STATE_STARTED;
|
s_media_state = APP_AV_MEDIA_STATE_STARTED;
|
||||||
} else {
|
} else {
|
||||||
// not started succesfully, transfer to idle state
|
// not started succesfully, transfer to idle state
|
||||||
@@ -702,25 +773,32 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
|||||||
LOG_INFO("Output state is stopped. Stopping a2dp media ...");
|
LOG_INFO("Output state is stopped. Stopping a2dp media ...");
|
||||||
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
||||||
s_intv_cnt = 0;
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
output_bt_check_buffer();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static time_t lastTime=0;
|
static time_t lastTime=0;
|
||||||
if (lastTime <= gettime_ms() )
|
if (lastTime <= gettime_ms() )
|
||||||
{
|
{
|
||||||
lastTime = gettime_ms() + 5000;
|
lastTime = gettime_ms() + 15000;
|
||||||
//LOG_INFO( "count:%d, current sample rate: %d, bytes per frame: %d",count,output.current_sample_rate);
|
LOG_DEBUG( " +==========+==========+================+=====+================+");
|
||||||
LOG_INFO( " **********+**********+***********+***********+ +**********+**********+****************+****************+****************+");
|
LOG_DEBUG( " | max | min | average | avg | count |");
|
||||||
LOG_INFO( " max | min | avg | current| | max | min | average | count | current |");
|
LOG_DEBUG( " | (bytes) | (bytes) | (bytes) | pct | |");
|
||||||
LOG_INFO( " (ms) | (ms) | (ms)| (ms) | | (bytes) | (bytes) | (bytes) | | (bytes) |");
|
LOG_DEBUG( " +==========+==========+================+=====+================+");
|
||||||
LOG_INFO( " **********+**********+***********+***********+ +**********+**********+****************+****************+****************+");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("available",bt));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("available",bt));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
LOG_DEBUG( " +==========+==========+================+=====+================+");
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under));
|
LOG_DEBUG("\n");
|
||||||
LOG_INFO(" **********+**********+***********+***********+ +**********+**********+****************+****************+****************+");
|
LOG_DEBUG(" ==========+==========+===========+===========+ ");
|
||||||
|
LOG_DEBUG(" max (us) | min (us) | avg(us) | count | ");
|
||||||
|
LOG_DEBUG(" ==========+==========+===========+===========+ ");
|
||||||
|
LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("BT Buf Lock",lock_bt_time));
|
||||||
|
LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time));
|
||||||
|
LOG_DEBUG(" ==========+==========+===========+===========+");
|
||||||
RESET_ALL_MIN_MAX;
|
RESET_ALL_MIN_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,9 +849,18 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case ESP_A2D_CONNECTION_STATE_EVT:
|
case ESP_A2D_CONNECTION_STATE_EVT:
|
||||||
LOG_DEBUG_EVENT(ESP_A2D_CONNECTION_STATE_EVT);
|
LOG_DEBUG_EVENT(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);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ESP_A2D_AUDIO_STATE_EVT:
|
case ESP_A2D_AUDIO_STATE_EVT:
|
||||||
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_STATE_EVT);
|
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_STATE_EVT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ESP_A2D_AUDIO_CFG_EVT:
|
case ESP_A2D_AUDIO_CFG_EVT:
|
||||||
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_CFG_EVT);
|
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_CFG_EVT);
|
||||||
@@ -799,11 +886,12 @@ static void bt_app_av_state_unconnected(uint16_t event, void *param)
|
|||||||
}
|
}
|
||||||
// if(out_state > OUTPUT_STOPPED){
|
// if(out_state > OUTPUT_STOPPED){
|
||||||
// only attempt a connect when playback isn't stopped
|
// only attempt a connect when playback isn't stopped
|
||||||
if(esp_a2d_source_connect(s_peer_bda)!=ESP_ERR_INVALID_STATE) {
|
if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {
|
||||||
s_a2d_state = APP_AV_STATE_CONNECTING;
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
//esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){
|
||||||
//LOG_INFO("squeezelite playback resumed. connecting to A2DP peer: %s", s_peer_bdname);
|
LOG_INFO_NO_LF("%s",art_a2dp_connecting[l]);
|
||||||
LOG_INFO("connecting to A2DP peer: %s", s_peer_bdname);
|
}
|
||||||
|
LOG_INFO("********** A2DP CONNECTING TO %s", s_peer_bdname);
|
||||||
A2DP_TIMER_INIT;
|
A2DP_TIMER_INIT;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -830,8 +918,12 @@ static void bt_app_av_state_connecting(uint16_t event, void *param)
|
|||||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
|
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
|
||||||
s_a2d_state = APP_AV_STATE_CONNECTED;
|
s_a2d_state = APP_AV_STATE_CONNECTED;
|
||||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||||
LOG_INFO("a2dp connected! Setting BT mode to non_connectable and non_discoverable. ");
|
for(uint8_t l=0;art_a2dp_connected[l][0]!='\0';l++){
|
||||||
|
LOG_INFO_NO_LF("%s",art_a2dp_connected[l]);
|
||||||
|
}
|
||||||
|
LOG_DEBUG("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_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
||||||
|
LOG_DEBUG("Done setting scan mode. App state is now CONNECTED and media state IDLE.");
|
||||||
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||||
}
|
}
|
||||||
@@ -888,7 +980,7 @@ static void bt_app_av_state_connected(uint16_t event, void *param)
|
|||||||
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_CFG_EVT);
|
LOG_DEBUG_EVENT(ESP_A2D_AUDIO_CFG_EVT);
|
||||||
break;
|
break;
|
||||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:{
|
case ESP_A2D_MEDIA_CTRL_ACK_EVT:{
|
||||||
LOG_DEBUG_EVENT(ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
LOG_SDEBUG_EVENT(ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
||||||
bt_app_av_media_proc(event, param);
|
bt_app_av_media_proc(event, param);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,47 @@
|
|||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "sys/socket.h"
|
#include "sys/socket.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
thread_cond_type wifi_connect_suspend_cond;
|
||||||
|
mutex_type wifi_connect_suspend_mutex;
|
||||||
|
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",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
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",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
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",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
/*Set the SSID and Password via "make menuconfig"*/
|
/*Set the SSID and Password via "make menuconfig"*/
|
||||||
#define DEFAULT_SSID CONFIG_WIFI_SSID
|
#define DEFAULT_SSID CONFIG_WIFI_SSID
|
||||||
@@ -80,7 +121,13 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
esp_wifi_connect();
|
esp_wifi_connect();
|
||||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
} 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;
|
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_LOGI(TAG, "got ip: %s.", ip4addr_ntoa(&event->ip_info.ip));
|
||||||
|
logprint("Signaling wifi connected. Locking.\n");
|
||||||
|
mutex_lock(wifi_connect_suspend_mutex);
|
||||||
|
logprint("Signaling wifi connected. Broadcasting.\n");
|
||||||
|
mutex_broadcast_cond(wifi_connect_suspend_cond);
|
||||||
|
logprint("Signaling wifi connected. Unlocking.\n");
|
||||||
|
mutex_unlock(wifi_connect_suspend_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +135,12 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
/* Initialize Wi-Fi as sta and set scan method */
|
/* Initialize Wi-Fi as sta and set scan method */
|
||||||
static void wifi_scan(void)
|
static void wifi_scan(void)
|
||||||
{
|
{
|
||||||
|
for(uint8_t l=0;art_wifi[l][0]!='\0';l++){
|
||||||
|
logprint("%s",art_wifi[l]);
|
||||||
|
}
|
||||||
|
for(uint8_t l=0;art_wifi_connecting[l][0]!='\0';l++){
|
||||||
|
logprint("%s",art_wifi_connecting[l]);
|
||||||
|
}
|
||||||
tcpip_adapter_init();
|
tcpip_adapter_init();
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
@@ -143,18 +196,13 @@ void app_main()
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// can't do strtok on FLASH strings
|
// can't do strtok on FLASH strings
|
||||||
argv = malloc(sizeof(_argv));
|
argv = malloc(sizeof(_argv));
|
||||||
for (i = 0; i < sizeof(_argv)/sizeof(char*); i++) {
|
for (i = 0; i < sizeof(_argv)/sizeof(char*); i++) {
|
||||||
argv[i] = strdup(_argv[i]);
|
argv[i] = strdup(_argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint("%s %s:%d Calling main with parameters: " , logtime(), __FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(_argv)/sizeof(char*); i++) {
|
|
||||||
logprint("%s " , _argv[i]);
|
|
||||||
}
|
|
||||||
logprint("\n");
|
|
||||||
|
|
||||||
// Initialize NVS
|
// Initialize NVS
|
||||||
esp_err_t ret = nvs_flash_init();
|
esp_err_t ret = nvs_flash_init();
|
||||||
@@ -164,7 +212,29 @@ void app_main()
|
|||||||
}
|
}
|
||||||
ESP_ERROR_CHECK( ret );
|
ESP_ERROR_CHECK( ret );
|
||||||
|
|
||||||
|
mutex_create_p(wifi_connect_suspend_mutex);
|
||||||
|
mutex_cond_init(wifi_connect_suspend_cond);
|
||||||
|
|
||||||
|
logprint("Starting WiFi.\n");
|
||||||
wifi_scan();
|
wifi_scan();
|
||||||
|
logprint("Waiting for WiFi to connect. Locking Mutex.\n");
|
||||||
|
mutex_lock(wifi_connect_suspend_mutex);
|
||||||
|
logprint("Waiting for WiFi to connect. cond_wait.\n");
|
||||||
|
pthread_cond_wait(&wifi_connect_suspend_cond,&wifi_connect_suspend_mutex);
|
||||||
|
logprint("Waiting for WiFi to connect. Unlocking Mutex.\n");
|
||||||
|
mutex_unlock(wifi_connect_suspend_mutex);
|
||||||
|
for(uint8_t l=0;art_wifi[l][0]!='\0';l++){
|
||||||
|
logprint("%s",art_wifi[l]);
|
||||||
|
}
|
||||||
|
for(uint8_t l=0;art_wifi_connected[l][0]!='\0';l++){
|
||||||
|
logprint("%s",art_wifi_connected[l]);
|
||||||
|
}
|
||||||
|
logprint("%s %s:%d Calling main with parameters: " , logtime(), __FUNCTION__, __LINE__);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(_argv)/sizeof(char*); i++) {
|
||||||
|
logprint("%s " , _argv[i]);
|
||||||
|
}
|
||||||
|
logprint("\n");
|
||||||
|
|
||||||
main(sizeof(_argv)/sizeof(char*), argv);
|
main(sizeof(_argv)/sizeof(char*), argv);
|
||||||
}
|
}
|
||||||
|
|||||||
327
main/output_bt.c
327
main/output_bt.c
@@ -8,50 +8,57 @@ static bool running = true;
|
|||||||
extern struct outputstate output;
|
extern struct outputstate output;
|
||||||
extern struct buffer *outputbuf;
|
extern struct buffer *outputbuf;
|
||||||
extern struct buffer *streambuf;
|
extern struct buffer *streambuf;
|
||||||
size_t bt_buffer_size=0;
|
|
||||||
|
|
||||||
static struct buffer bt_buf_structure;
|
|
||||||
struct buffer *btbuf=&bt_buf_structure;
|
|
||||||
|
|
||||||
|
|
||||||
#define LOCK mutex_lock(outputbuf->mutex)
|
#define LOCK mutex_lock(outputbuf->mutex)
|
||||||
#define UNLOCK mutex_unlock(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 LOCK_BT mutex_lock(btbuf->mutex)
|
||||||
#define UNLOCK_BT mutex_unlock(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 FRAME_BLOCK MAX_SILENCE_FRAMES
|
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
||||||
#define BUFFERING_FRAME_BLOCK FRAME_BLOCK*2
|
|
||||||
|
|
||||||
extern u8_t *silencebuf;
|
extern u8_t *silencebuf;
|
||||||
|
|
||||||
void hal_bluetooth_init(log_level);
|
void hal_bluetooth_init(log_level);
|
||||||
static void *output_thread_bt();
|
|
||||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
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);
|
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||||
extern void wait_for_frames(size_t frames, uint8_t pct);
|
|
||||||
|
|
||||||
#define DECLARE_ALL_MIN_MAX \
|
#define DECLARE_ALL_MIN_MAX \
|
||||||
DECLARE_MIN_MAX(req, long,LONG); \
|
DECLARE_MIN_MAX(req);\
|
||||||
DECLARE_MIN_MAX(rec, long,LONG); \
|
DECLARE_MIN_MAX(rec);\
|
||||||
DECLARE_MIN_MAX(o, long,LONG); \
|
DECLARE_MIN_MAX(o);\
|
||||||
DECLARE_MIN_MAX(s, long,LONG); \
|
DECLARE_MIN_MAX(s);\
|
||||||
DECLARE_MIN_MAX(d, long,LONG); \
|
DECLARE_MIN_MAX(locbtbuff);\
|
||||||
DECLARE_MIN_MAX(locbtbuff, long,LONG); \
|
DECLARE_MIN_MAX(under);\
|
||||||
DECLARE_MIN_MAX(mutex1, long,LONG); \
|
DECLARE_MIN_MAX_DURATION(mutex1);\
|
||||||
DECLARE_MIN_MAX(mutex2, long,LONG); \
|
DECLARE_MIN_MAX_DURATION(mutex2);\
|
||||||
DECLARE_MIN_MAX(total, long,LONG); \
|
DECLARE_MIN_MAX_DURATION(buffering);\
|
||||||
DECLARE_MIN_MAX(buffering, long,LONG);
|
DECLARE_MIN_MAX_DURATION(sleep_time);
|
||||||
#define RESET_ALL_MIN_MAX \
|
#define RESET_ALL_MIN_MAX \
|
||||||
RESET_MIN_MAX(d,LONG); \
|
RESET_MIN_MAX(o); \
|
||||||
RESET_MIN_MAX(o,LONG); \
|
RESET_MIN_MAX(s); \
|
||||||
RESET_MIN_MAX(s,LONG); \
|
RESET_MIN_MAX(locbtbuff); \
|
||||||
RESET_MIN_MAX(locbtbuff, LONG); \
|
RESET_MIN_MAX(req); \
|
||||||
RESET_MIN_MAX(req,LONG); \
|
RESET_MIN_MAX(rec); \
|
||||||
RESET_MIN_MAX(rec,LONG); \
|
RESET_MIN_MAX(under); \
|
||||||
RESET_MIN_MAX(mutex1,LONG); \
|
RESET_MIN_MAX_DURATION(mutex1); \
|
||||||
RESET_MIN_MAX(mutex2,LONG); \
|
RESET_MIN_MAX_DURATION(mutex2); \
|
||||||
RESET_MIN_MAX(total,LONG); \
|
RESET_MIN_MAX_DURATION(sleep_time); \
|
||||||
RESET_MIN_MAX(buffering,LONG);
|
RESET_MIN_MAX_DURATION(buffering);
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_BTAUDIO
|
#if CONFIG_BTAUDIO
|
||||||
@@ -64,7 +71,58 @@ void set_volume_bt(unsigned left, unsigned right) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static thread_type thread_bt;
|
|
||||||
|
|
||||||
|
void output_bt_check_buffer()
|
||||||
|
{
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
LOCK_BT;
|
||||||
|
uint8_t tot_buf_used_pct=100*_buf_used(btbuf)/btbuf->size;
|
||||||
|
UNLOCK_BT;
|
||||||
|
if(tot_buf_used_pct<bt_buf_used_threshold)
|
||||||
|
{
|
||||||
|
// tell the thread to resume
|
||||||
|
LOG_SDEBUG("Below threshold. Locking suspend mutex.");
|
||||||
|
mutex_lock(output_bt_suspend_mutex);
|
||||||
|
LOG_SDEBUG("Broadcasting suspend condition.");
|
||||||
|
mutex_broadcast_cond(output_bt_suspend_cond);
|
||||||
|
LOG_SDEBUG("Unlocking suspend mutex.");
|
||||||
|
mutex_unlock(output_bt_suspend_mutex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void output_bt_suspend()
|
||||||
|
{
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
struct timespec ts;
|
||||||
|
struct timeval tp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
|
||||||
|
// if suspended, suspend until resumed
|
||||||
|
LOG_SDEBUG("Locking suspend mutex.");
|
||||||
|
mutex_lock(output_bt_suspend_mutex);
|
||||||
|
LOG_SDEBUG("Waiting on condition to be signaled.");
|
||||||
|
|
||||||
|
// suspend for up to a predetermined wait time.
|
||||||
|
// this will allow flushing the BT buffer when the
|
||||||
|
// playback stops.
|
||||||
|
gettimeofday(&tp, NULL);
|
||||||
|
/* Convert from timeval to timespec */
|
||||||
|
ts.tv_sec = tp.tv_sec;
|
||||||
|
ts.tv_nsec = tp.tv_usec * 1000;
|
||||||
|
ts.tv_nsec += output_bt_thread_heartbeat_ms*1000000; // micro seconds to nanosecs
|
||||||
|
|
||||||
|
rc = pthread_cond_timedwait(&output_bt_suspend_cond,&output_bt_suspend_mutex,&ts);
|
||||||
|
if(rc==ETIMEDOUT)
|
||||||
|
{
|
||||||
|
LOG_SDEBUG("Wait timed out. Resuming output.");
|
||||||
|
}
|
||||||
|
LOG_SDEBUG("Unlocking suspend mutex.");
|
||||||
|
mutex_unlock(output_bt_suspend_mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
|
void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
|
||||||
loglevel = level;
|
loglevel = level;
|
||||||
|
|
||||||
@@ -72,10 +130,6 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
|||||||
|
|
||||||
memset(&output, 0, sizeof(output));
|
memset(&output, 0, sizeof(output));
|
||||||
|
|
||||||
output.start_frames = FRAME_BLOCK; //CONFIG_ //FRAME_BLOCK * 2;
|
|
||||||
output.write_cb = &_write_frames;
|
|
||||||
output.rate_delay = rate_delay;
|
|
||||||
|
|
||||||
// ensure output rate is specified to avoid test open
|
// ensure output rate is specified to avoid test open
|
||||||
if (!rates[0]) {
|
if (!rates[0]) {
|
||||||
rates[0] = 44100;
|
rates[0] = 44100;
|
||||||
@@ -86,15 +140,16 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
|||||||
*/
|
*/
|
||||||
device = CONFIG_OUTPUT_NAME;
|
device = CONFIG_OUTPUT_NAME;
|
||||||
output_init_common(level, device, output_buf_size, rates, idle);
|
output_init_common(level, device, output_buf_size, rates, idle);
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
bt_buffer_size = 3*FRAME_BLOCK*get_bytes_per_frame(output.format);
|
|
||||||
LOG_DEBUG("Allocating local BT transfer buffer of %u bytes.",bt_buffer_size);
|
LOG_DEBUG("Allocating local BT transfer buffer of %u bytes.",bt_buffer_size);
|
||||||
buf_init(btbuf, bt_buffer_size );
|
buf_init(btbuf, bt_buffer_size );
|
||||||
if (!btbuf->buf) {
|
if (!btbuf->buf) {
|
||||||
LOG_ERROR("unable to malloc BT buffer");
|
LOG_ERROR("unable to malloc BT buffer");
|
||||||
exit(0);
|
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
|
#if LINUX || OSX || FREEBSD || POSIX
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
@@ -102,11 +157,18 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
|||||||
#ifdef PTHREAD_STACK_MIN
|
#ifdef PTHREAD_STACK_MIN
|
||||||
pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
|
pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_create(&thread_bt, &attr, output_thread_bt, NULL);
|
pthread_create(&thread_bt, &attr, output_thread_bt, NULL);
|
||||||
pthread_attr_destroy(&attr);
|
|
||||||
#endif
|
#endif
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
|
||||||
#if WIN
|
#if WIN
|
||||||
thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread_bt, NULL, 0, NULL);
|
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
|
#endif
|
||||||
LOG_INFO("Init completed.");
|
LOG_INFO("Init completed.");
|
||||||
|
|
||||||
@@ -115,111 +177,135 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Main output thread
|
* Main output thread
|
||||||
*/
|
*/
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
static void *output_thread_bt() {
|
static void *output_thread_bt() {
|
||||||
|
|
||||||
frames_t frames=0;
|
frames_t frames=0;
|
||||||
frames_t available_frames_space=0;
|
frames_t requested_frames=0;
|
||||||
uint32_t timer_start=0, mutex_start=0, total_start=0;
|
uint32_t timer_start=0, mutex_start=0;
|
||||||
static int count = 0;
|
unsigned btbuf_used=0;
|
||||||
|
output_state state;
|
||||||
DECLARE_ALL_MIN_MAX;
|
DECLARE_ALL_MIN_MAX;
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
frames=0;
|
frames=0;
|
||||||
available_frames_space=0;
|
requested_frames=0;
|
||||||
|
|
||||||
TIME_MEASUREMENT_START(timer_start);
|
TIME_MEASUREMENT_START(timer_start);
|
||||||
TIME_MEASUREMENT_START(total_start);
|
|
||||||
|
// Get output state
|
||||||
TIME_MEASUREMENT_START(mutex_start);
|
TIME_MEASUREMENT_START(mutex_start);
|
||||||
LOCK;
|
LOCK;
|
||||||
|
state=output.state;
|
||||||
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1);
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1);
|
||||||
if (output.state == OUTPUT_OFF) {
|
|
||||||
|
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;
|
UNLOCK;
|
||||||
LOG_SDEBUG("Output state is off.");
|
LOG_SDEBUG("Output state is off.");
|
||||||
usleep(500000);
|
usleep(200000);
|
||||||
continue;
|
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);
|
TIME_MEASUREMENT_START(mutex_start);
|
||||||
LOCK_BT;
|
LOCK_BT;
|
||||||
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex2);
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex2);
|
||||||
available_frames_space = min(_buf_space(btbuf), _buf_cont_write(btbuf))/BYTES_PER_FRAME;
|
btbuf_used=_buf_used(btbuf);
|
||||||
SET_MIN_MAX( available_frames_space,req);
|
SET_MIN_MAX_SIZED(btbuf_used,locbtbuff,btbuf->size);
|
||||||
SET_MIN_MAX(_buf_used(outputbuf)/BYTES_PER_FRAME,o);
|
|
||||||
SET_MIN_MAX(_buf_used(streambuf)/BYTES_PER_FRAME,s);
|
|
||||||
if(available_frames_space==0)
|
// 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)
|
||||||
{
|
{
|
||||||
UNLOCK;
|
frames = _output_frames( requested_frames ); // Keep the transfer buffer full
|
||||||
UNLOCK_BT;
|
SET_MIN_MAX(frames*BYTES_PER_FRAME,rec);
|
||||||
usleep(10000);
|
if(requested_frames>frames){
|
||||||
continue;
|
SET_MIN_MAX((requested_frames-frames)*BYTES_PER_FRAME,under);
|
||||||
}
|
}
|
||||||
frames = _output_frames( available_frames_space ); // Keep the transfer buffer full
|
}
|
||||||
SET_MIN_MAX(_buf_used(btbuf),locbtbuff);
|
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
UNLOCK_BT;
|
UNLOCK_BT;
|
||||||
//LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(btbuf),_buf_cont_read(btbuf));
|
|
||||||
SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering);
|
SET_MIN_MAX( TIME_MEASUREMENT_GET(timer_start),buffering);
|
||||||
SET_MIN_MAX( available_frames_space,req);
|
SET_MIN_MAX( requested_frames,req);
|
||||||
SET_MIN_MAX(frames,rec);
|
|
||||||
// if(frames>0 ){
|
// When playback has started, we want to
|
||||||
// // let's hold processing a bit, while frames are being processed
|
// hold the BT out thread
|
||||||
// // we're waiting long enough to avoid hogging the CPU too much
|
// so the BT data callback isn't constantly interrupted.
|
||||||
// // while we're ramping up this transfer buffer
|
TIME_MEASUREMENT_START(timer_start);
|
||||||
// wait_for_frames(frames,95);
|
if(state>OUTPUT_BUFFER){
|
||||||
// }
|
output_bt_suspend();
|
||||||
wait_for_frames(FRAME_BLOCK,100);
|
}
|
||||||
|
SET_MIN_MAX(TIME_MEASUREMENT_GET(timer_start),sleep_time);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Statistics reporting
|
* Statistics reporting
|
||||||
*/
|
*/
|
||||||
#define STATS_PERIOD_MS 10000
|
static time_t lastTime=0;
|
||||||
count++;
|
if (lastTime <= gettime_ms() )
|
||||||
TIMED_SECTION_START_MS(STATS_PERIOD_MS);
|
{
|
||||||
if(count>1){
|
#define STATS_PERIOD_MS 15000
|
||||||
LOG_INFO( "count:%d, current sample rate: %d, avg cycle duration (ms): %d",count,output.current_sample_rate, STATS_PERIOD_MS/count);
|
lastTime = gettime_ms() + STATS_PERIOD_MS;
|
||||||
LOG_INFO( " ----------+----------+-----------+-----------+ +----------+----------+----------------+----------------+----------------+");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD1);
|
||||||
LOG_INFO( " max | min | avg | current| | max | min | average | count | current |");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD2);
|
||||||
LOG_INFO( " (ms) | (ms) | (ms)| (ms) | | (bytes) | (bytes) | (bytes) | | (bytes) |");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD3);
|
||||||
LOG_INFO( " ----------+----------+-----------+-----------+ +----------+----------+----------------+----------------+----------------+");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_HEAD4);
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local bt buf",locbtbuff));
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER );
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local bt buf",locbtbuff));
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
||||||
LOG_INFO(" ----------+----------+-----------+-----------+ +----------+----------+----------------+----------------+");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
||||||
LOG_INFO("");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("Underrun",under));
|
||||||
LOG_INFO(" ----------+----------+-----------+-----------+-----------+ ");
|
LOG_DEBUG(LINE_MIN_MAX_FORMAT_FOOTER );
|
||||||
LOG_INFO(" max (us) | min (us) | avg(us) | count |current(us)| ");
|
LOG_DEBUG("");
|
||||||
LOG_INFO(" ----------+----------+-----------+-----------+-----------+ ");
|
LOG_DEBUG(" ----------+----------+-----------+-----------+ ");
|
||||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
|
LOG_DEBUG(" max (us) | min (us) | avg(us) | count | ");
|
||||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Output mux(us)",mutex1));
|
LOG_DEBUG(" ----------+----------+-----------+-----------+ ");
|
||||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("BT mux(us)",mutex2));
|
LOG_DEBUG(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
|
||||||
LOG_INFO(" ----------+----------+-----------+-----------+-----------+");
|
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;
|
RESET_ALL_MIN_MAX;
|
||||||
count=0;
|
|
||||||
}
|
}
|
||||||
TIMED_SECTION_END;
|
|
||||||
/*
|
/*
|
||||||
* End Statistics reporting
|
* End Statistics reporting
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void output_close_bt(void) {
|
void output_close_bt(void) {
|
||||||
LOG_INFO("close output");
|
LOG_INFO("close output");
|
||||||
LOCK;
|
LOCK;
|
||||||
running = false;
|
running = false;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
|
LOCK_BT;
|
||||||
|
buf_destroy(btbuf);
|
||||||
|
UNLOCK_BT;
|
||||||
|
#endif
|
||||||
output_close_common();
|
output_close_common();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
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) {
|
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
|
||||||
|
#ifdef USE_BT_RING_BUFFER
|
||||||
if (!silence ) {
|
if (!silence ) {
|
||||||
DEBUG_LOG_TIMED(200,"Not silence, Writing audio out.");
|
DEBUG_LOG_TIMED(200,"Not silence, Writing audio out.");
|
||||||
// TODO need 16 bit fix
|
// TODO need 16 bit fix
|
||||||
@@ -235,6 +321,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
|||||||
#if BYTES_PER_FRAME == 4
|
#if BYTES_PER_FRAME == 4
|
||||||
|
|
||||||
memcpy(btbuf->writep, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
memcpy(btbuf->writep, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||||
|
_buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
@@ -248,12 +335,46 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else if(output.state >OUTPUT_BUFFER){
|
||||||
DEBUG_LOG_TIMED(200,"Silence flag true. Writing silence to audio out.");
|
// Don't fill our local buffer with silence frames.
|
||||||
|
|
||||||
u8_t *buf = silencebuf;
|
u8_t *buf = silencebuf;
|
||||||
memcpy(btbuf->writep, buf, out_frames * BYTES_PER_FRAME);
|
memcpy(btbuf->writep, buf, out_frames * BYTES_PER_FRAME);
|
||||||
}
|
|
||||||
_buf_inc_writep(btbuf,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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
|
||||||
|
_apply_gain(outputbuf, out_frames, gainL, gainR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
memcpy(btout, outputbuf->readp, 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 {
|
||||||
|
|
||||||
|
u8_t *buf = silencebuf;
|
||||||
|
memcpy(btout, buf, out_frames * BYTES_PER_FRAME);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return (int)out_frames;
|
return (int)out_frames;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,27 +6,25 @@
|
|||||||
|
|
||||||
|
|
||||||
#define DECLARE_ALL_MIN_MAX \
|
#define DECLARE_ALL_MIN_MAX \
|
||||||
DECLARE_MIN_MAX(req, long,LONG); \
|
DECLARE_MIN_MAX(req); \
|
||||||
DECLARE_MIN_MAX(rec, long,LONG); \
|
DECLARE_MIN_MAX(rec); \
|
||||||
DECLARE_MIN_MAX(over, long,LONG); \
|
DECLARE_MIN_MAX(over); \
|
||||||
DECLARE_MIN_MAX(o, long,LONG); \
|
DECLARE_MIN_MAX(o); \
|
||||||
DECLARE_MIN_MAX(s, long,LONG); \
|
DECLARE_MIN_MAX(s); \
|
||||||
DECLARE_MIN_MAX(d, long,LONG); \
|
DECLARE_MIN_MAX(loci2sbuf); \
|
||||||
DECLARE_MIN_MAX(loci2sbuf, long,LONG); \
|
DECLARE_MIN_MAX(buffering); \
|
||||||
DECLARE_MIN_MAX(buffering, long,LONG);\
|
DECLARE_MIN_MAX(i2s_time); \
|
||||||
DECLARE_MIN_MAX(i2s_time, long,LONG); \
|
DECLARE_MIN_MAX(i2savailable);
|
||||||
DECLARE_MIN_MAX(i2savailable, long,LONG);
|
|
||||||
#define RESET_ALL_MIN_MAX \
|
#define RESET_ALL_MIN_MAX \
|
||||||
RESET_MIN_MAX(d,LONG); \
|
RESET_MIN_MAX(o); \
|
||||||
RESET_MIN_MAX(o,LONG); \
|
RESET_MIN_MAX(s); \
|
||||||
RESET_MIN_MAX(s,LONG); \
|
RESET_MIN_MAX(loci2sbuf); \
|
||||||
RESET_MIN_MAX(loci2sbuf, LONG); \
|
RESET_MIN_MAX(req); \
|
||||||
RESET_MIN_MAX(req,LONG); \
|
RESET_MIN_MAX(rec); \
|
||||||
RESET_MIN_MAX(rec,LONG); \
|
RESET_MIN_MAX(over); \
|
||||||
RESET_MIN_MAX(over,LONG); \
|
RESET_MIN_MAX(over); \
|
||||||
RESET_MIN_MAX(over,LONG); \
|
RESET_MIN_MAX(i2savailable);\
|
||||||
RESET_MIN_MAX(i2savailable,LONG);\
|
RESET_MIN_MAX(i2s_time);
|
||||||
RESET_MIN_MAX(i2s_time,LONG);
|
|
||||||
|
|
||||||
// Prevent compile errors if dac output is
|
// Prevent compile errors if dac output is
|
||||||
// included in the build and not actually activated in menuconfig
|
// included in the build and not actually activated in menuconfig
|
||||||
@@ -74,7 +72,7 @@ static thread_type thread;
|
|||||||
|
|
||||||
static int _dac_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
static int _dac_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);
|
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||||
static void *output_thread();
|
static void *output_thread_dac();
|
||||||
extern void wait_for_frames(size_t frames, uint8_t pct);
|
extern void wait_for_frames(size_t frames, uint8_t pct);
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
@@ -160,8 +158,8 @@ void output_init_dac(log_level level, char *device, unsigned output_buf_size, ch
|
|||||||
LOG_ERROR("unable to malloc i2s buffer");
|
LOG_ERROR("unable to malloc i2s buffer");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
LOG_SDEBUG("Current buffer free: %d",_buf_space(dacbuffer));
|
|
||||||
|
|
||||||
|
PTHREAD_SET_NAME("output_dac");
|
||||||
|
|
||||||
#if LINUX || OSX || FREEBSD || POSIX
|
#if LINUX || OSX || FREEBSD || POSIX
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
@@ -278,7 +276,7 @@ static void *output_thread() {
|
|||||||
isI2SStarted=false;
|
isI2SStarted=false;
|
||||||
i2s_stop(CONFIG_I2S_NUM);
|
i2s_stop(CONFIG_I2S_NUM);
|
||||||
}
|
}
|
||||||
usleep(500000);
|
usleep(200000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(dacbuffer),_buf_cont_read(dacbuffer));
|
LOG_SDEBUG("Current buffer free: %10d, cont read: %10d",_buf_space(dacbuffer),_buf_cont_read(dacbuffer));
|
||||||
@@ -343,35 +341,7 @@ static void *output_thread() {
|
|||||||
/*
|
/*
|
||||||
* Statistics reporting
|
* Statistics reporting
|
||||||
*/
|
*/
|
||||||
#define STATS_PERIOD_MS 5000
|
|
||||||
count++;
|
|
||||||
TIMED_SECTION_START_MS(STATS_PERIOD_MS);
|
|
||||||
|
|
||||||
LOG_INFO( "count:%d, current sample rate: %d, bytes per frame: %d, avg cycle duration (ms): %d",count,output.current_sample_rate, out_bytes_per_frame,STATS_PERIOD_MS/count);
|
|
||||||
LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
LOG_INFO( " max | min | current| | max | min | current |");
|
|
||||||
LOG_INFO( " (ms) | (ms) | (ms)| | (bytes) | (bytes) | (bytes) |");
|
|
||||||
LOG_INFO( " ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT_STREAM, LINE_MIN_MAX_STREAM("stream",s));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output",o));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("i2swrite",i2savailable));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local free",loci2sbuf));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("overflow",over));
|
|
||||||
LOG_INFO(" ----------+----------+-----------+ +----------+----------+----------------+");
|
|
||||||
LOG_INFO("");
|
|
||||||
LOG_INFO(" max (us) | min (us) |current(us)| ");
|
|
||||||
LOG_INFO(" ----------+----------+-----------+ ");
|
|
||||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Buffering(us)",buffering));
|
|
||||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("i2s tfr(us)",i2s_time));
|
|
||||||
LOG_INFO(" ----------+----------+-----------+ ");
|
|
||||||
RESET_ALL_MIN_MAX;
|
|
||||||
count=0;
|
|
||||||
TIMED_SECTION_END;
|
|
||||||
/*
|
|
||||||
* End Statistics reporting
|
|
||||||
*/
|
|
||||||
//wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written));
|
//wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -406,9 +376,7 @@ static void *output_thread() {
|
|||||||
/*
|
/*
|
||||||
* End Statistics reporting
|
* End Statistics reporting
|
||||||
*/
|
*/
|
||||||
wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written),75);
|
// wait_for_frames(BYTES_TO_FRAME(i2s_bytes_written),75);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ extern struct buffer *streambuf;
|
|||||||
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
||||||
|
|
||||||
extern u8_t *silencebuf;
|
extern u8_t *silencebuf;
|
||||||
extern u8_t *buf;
|
|
||||||
|
|
||||||
#define I2S_NUM (0)
|
#define I2S_NUM (0)
|
||||||
#define WAVE_FREQ_HZ (100)
|
#define WAVE_FREQ_HZ (100)
|
||||||
|
|||||||
@@ -1,24 +1,48 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#define FRAMES_TO_MS(f) output.current_sample_rate>0?1000*f/output.current_sample_rate:LONG_MIN
|
#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
|
||||||
|
#define FRAMES_TO_MS(f) (uint32_t)f*(uint32_t)1000/(uint32_t)(CURR_SAMPLE_RATE)
|
||||||
#ifdef BYTES_TO_FRAME
|
#ifdef BYTES_TO_FRAME
|
||||||
#define BYTES_TO_MS(b) FRAMES_TO_MS(BYTES_TO_FRAME(b))
|
#define BYTES_TO_MS(b) FRAMES_TO_MS(BYTES_TO_FRAME(b))
|
||||||
#else
|
#else
|
||||||
#define BYTES_TO_MS(b) FRAMES_TO_MS(b/BYTES_PER_FRAME)
|
#define BYTES_TO_MS(b) FRAMES_TO_MS(b/BYTES_PER_FRAME)
|
||||||
#endif
|
#endif
|
||||||
#define LINE_MIN_MAX_FORMAT "%14s%10d|%10d|%11d|%11d|" " |%10d|%10d|%16d|%16d|%16d|"
|
|
||||||
#define LINE_MIN_MAX_DURATION_FORMAT "%14s%10d|%10d|%11d|%11d|%11d|"
|
|
||||||
#define LINE_MIN_MAX_FORMAT_STREAM "%14s%10s|%10s|%11s|%11s|" " |%10d|%10d|%16d|%16d|%16d|"
|
|
||||||
#define SET_MIN_MAX(val,var) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var; count_##var++; avgtot_##var+= var
|
#define SET_MIN_MAX(val,var) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var; count_##var++; avgtot_##var+= var
|
||||||
#define RESET_MIN_MAX(var,mv) min_##var=mv##_MAX; max_##var=mv##_MIN; avgtot_##var=0;count_##var=0
|
#define SET_MIN_MAX_SIZED(val,var,siz) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var; count_##var++; avgtot_##var+= var;size_##var=siz
|
||||||
#define DECLARE_MIN_MAX(var,t,mv) static t min_##var = mv##_MAX, max_##var = mv##_MIN; uint32_t avgtot_##var = 0, count_##var=0; t var=0
|
#define RESET_MIN_MAX(var) min_##var=PERF_MAX; max_##var=0; avgtot_##var=0;count_##var=0;var=0;size_##var=0
|
||||||
#define LINE_MIN_MAX_AVG(var) count_##var>0?avgtot_##var/count_##var:-1
|
#define RESET_MIN_MAX_DURATION(var) min_##var=PERF_MAX; max_##var=0; avgtot_##var=0;count_##var=0;var=0
|
||||||
#define LINE_MIN_MAX(name,var) name,BYTES_TO_MS(max_##var), BYTES_TO_MS(min_##var),BYTES_TO_MS( var),BYTES_TO_MS( LINE_MIN_MAX_AVG(var)),max_##var,min_##var,LINE_MIN_MAX_AVG(var),count_##var,var
|
#define DECLARE_MIN_MAX(var) static uint32_t min_##var = PERF_MAX, max_##var = 0, size_##var = 0,avgtot_##var = 0, count_##var=0; uint32_t var=0
|
||||||
#define LINE_MIN_MAX_STREAM(name,var) name,"n/a","n/a","n/a","n/a",max_##var,min_##var,LINE_MIN_MAX_AVG(var),count_##var,var
|
#define DECLARE_MIN_MAX_DURATION(var) static uint32_t min_##var = PERF_MAX, max_##var = 0, avgtot_##var = 0, count_##var=0; uint32_t var=0
|
||||||
#define LINE_MIN_MAX_DURATION(name,var) name,max_##var, min_##var, LINE_MIN_MAX_AVG(var), count_##var,var
|
#define LINE_MIN_MAX_AVG(var) (count_##var>0?avgtot_##var/count_##var:0)
|
||||||
|
|
||||||
|
#define LINE_MIN_MAX_FORMAT_HEAD1 " +----------+----------+----------------+-----+----------------+"
|
||||||
|
#define LINE_MIN_MAX_FORMAT_HEAD2 " | max | min | average | | count |"
|
||||||
|
#define LINE_MIN_MAX_FORMAT_HEAD3 " | (bytes) | (bytes) | (bytes) | | |"
|
||||||
|
#define LINE_MIN_MAX_FORMAT_HEAD4 " +----------+----------+----------------+-----+----------------+"
|
||||||
|
#define LINE_MIN_MAX_FORMAT_FOOTER " +----------+----------+----------------+-----+----------------+"
|
||||||
|
#define LINE_MIN_MAX_FORMAT "%14s|%10u|%10u|%16u|%5u|%16u|"
|
||||||
|
#define LINE_MIN_MAX(name,var) name,\
|
||||||
|
MIN_MAX_VAL(max_##var),\
|
||||||
|
MIN_MAX_VAL(min_##var),\
|
||||||
|
LINE_MIN_MAX_AVG(var),\
|
||||||
|
size_##var!=0?100*LINE_MIN_MAX_AVG(var)/size_##var:0,\
|
||||||
|
count_##var
|
||||||
|
|
||||||
|
#define LINE_MIN_MAX_FORMAT_STREAM "%14s|%10u|%10u|%16u|%5u|%16u|"
|
||||||
|
#define LINE_MIN_MAX_STREAM(name,var) name,\
|
||||||
|
MIN_MAX_VAL(max_##var),\
|
||||||
|
MIN_MAX_VAL(min_##var),\
|
||||||
|
LINE_MIN_MAX_AVG(var),\
|
||||||
|
size_##var!=0?100*LINE_MIN_MAX_AVG(var)/size_##var:0,\
|
||||||
|
count_##var
|
||||||
|
#define LINE_MIN_MAX_DURATION_FORMAT "%14s%10u|%10u|%11u|%11u|"
|
||||||
|
#define LINE_MIN_MAX_DURATION(name,var) name,MIN_MAX_VAL(max_##var),MIN_MAX_VAL(min_##var), LINE_MIN_MAX_AVG(var), count_##var
|
||||||
|
|
||||||
|
|
||||||
#define TIME_MEASUREMENT_START(x) x=esp_timer_get_time()
|
#define TIME_MEASUREMENT_START(x) x=esp_timer_get_time()
|
||||||
#define TIME_MEASUREMENT_GET(x) (esp_timer_get_time()-x)/1000
|
#define TIME_MEASUREMENT_GET(x) (esp_timer_get_time()-x)
|
||||||
|
|
||||||
#define TIMED_SECTION_START_MS_FORCE(x,force) if(hasTimeElapsed(x,force)) {
|
#define TIMED_SECTION_START_MS_FORCE(x,force) if(hasTimeElapsed(x,force)) {
|
||||||
#define TIMED_SECTION_START_MS(x) if(hasTimeElapsed(x,false)){
|
#define TIMED_SECTION_START_MS(x) if(hasTimeElapsed(x,false)){
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
#define POSIX 1
|
#define POSIX 1
|
||||||
#include "embedded.h"
|
#include "embedded.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef PTHREAD_SET_NAME
|
||||||
|
#define PTHREAD_SET_NAME(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
// build detection
|
// build detection
|
||||||
#if defined(linux)
|
#if defined(linux)
|
||||||
@@ -334,6 +337,10 @@ typedef int64_t s64_t;
|
|||||||
#define mutex_lock(m) pthread_mutex_lock(&m)
|
#define mutex_lock(m) pthread_mutex_lock(&m)
|
||||||
#define mutex_unlock(m) pthread_mutex_unlock(&m)
|
#define mutex_unlock(m) pthread_mutex_unlock(&m)
|
||||||
#define mutex_destroy(m) pthread_mutex_destroy(&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
|
#define thread_type pthread_t
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -765,6 +772,7 @@ 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_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);
|
void output_close_bt(void);
|
||||||
void hal_bluetooth_init(log_level loglevel);
|
void hal_bluetooth_init(log_level loglevel);
|
||||||
|
void output_bt_check_buffer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ void stream_init(log_level level, unsigned stream_buf_size) {
|
|||||||
#if LINUX || FREEBSD
|
#if LINUX || FREEBSD
|
||||||
touch_memory(streambuf->buf, streambuf->size);
|
touch_memory(streambuf->buf, streambuf->size);
|
||||||
#endif
|
#endif
|
||||||
|
PTHREAD_SET_NAME("stream");
|
||||||
#if LINUX || OSX || FREEBSD || POSIX
|
#if LINUX || OSX || FREEBSD || POSIX
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
|
|||||||
Reference in New Issue
Block a user