mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-13 23:17:03 +03:00
BT ring buffering
This commit is contained in:
173
main/output_bt.c
173
main/output_bt.c
@@ -1,5 +1,5 @@
|
||||
#include "squeezelite.h"
|
||||
|
||||
#include "perf_trace.h"
|
||||
|
||||
static log_level loglevel;
|
||||
|
||||
@@ -8,22 +8,54 @@ static bool running = true;
|
||||
extern struct outputstate output;
|
||||
extern struct buffer *outputbuf;
|
||||
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 UNLOCK mutex_unlock(outputbuf->mutex)
|
||||
#define LOCK_BT mutex_lock(btbuf->mutex)
|
||||
#define UNLOCK_BT mutex_unlock(btbuf->mutex)
|
||||
|
||||
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
||||
#define BUFFERING_FRAME_BLOCK FRAME_BLOCK*2
|
||||
|
||||
extern u8_t *silencebuf;
|
||||
|
||||
extern u8_t *bt_optr;
|
||||
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,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
#if BTAUDIO
|
||||
void set_volume(unsigned left, unsigned right) {
|
||||
extern void wait_for_frames(size_t frames, uint8_t pct);
|
||||
|
||||
#define DECLARE_ALL_MIN_MAX \
|
||||
DECLARE_MIN_MAX(req, long,LONG); \
|
||||
DECLARE_MIN_MAX(rec, long,LONG); \
|
||||
DECLARE_MIN_MAX(o, long,LONG); \
|
||||
DECLARE_MIN_MAX(s, long,LONG); \
|
||||
DECLARE_MIN_MAX(d, long,LONG); \
|
||||
DECLARE_MIN_MAX(locbtbuff, long,LONG); \
|
||||
DECLARE_MIN_MAX(mutex1, long,LONG); \
|
||||
DECLARE_MIN_MAX(mutex2, long,LONG); \
|
||||
DECLARE_MIN_MAX(total, long,LONG); \
|
||||
DECLARE_MIN_MAX(buffering, long,LONG);
|
||||
#define RESET_ALL_MIN_MAX \
|
||||
RESET_MIN_MAX(d,LONG); \
|
||||
RESET_MIN_MAX(o,LONG); \
|
||||
RESET_MIN_MAX(s,LONG); \
|
||||
RESET_MIN_MAX(locbtbuff, LONG); \
|
||||
RESET_MIN_MAX(req,LONG); \
|
||||
RESET_MIN_MAX(rec,LONG); \
|
||||
RESET_MIN_MAX(mutex1,LONG); \
|
||||
RESET_MIN_MAX(mutex2,LONG); \
|
||||
RESET_MIN_MAX(total,LONG); \
|
||||
RESET_MIN_MAX(buffering,LONG);
|
||||
|
||||
|
||||
#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;
|
||||
@@ -32,7 +64,7 @@ void set_volume(unsigned left, unsigned right) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static thread_type thread_bt;
|
||||
void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
|
||||
loglevel = level;
|
||||
|
||||
@@ -55,9 +87,127 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
||||
device = CONFIG_OUTPUT_NAME;
|
||||
output_init_common(level, device, output_buf_size, rates, idle);
|
||||
|
||||
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);
|
||||
buf_init(btbuf, bt_buffer_size );
|
||||
if (!btbuf->buf) {
|
||||
LOG_ERROR("unable to malloc BT buffer");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
#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);
|
||||
pthread_attr_destroy(&attr);
|
||||
#endif
|
||||
#if WIN
|
||||
thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread_bt, NULL, 0, NULL);
|
||||
#endif
|
||||
LOG_INFO("Init completed.");
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Main output thread
|
||||
*/
|
||||
static void *output_thread_bt() {
|
||||
frames_t frames=0;
|
||||
frames_t available_frames_space=0;
|
||||
uint32_t timer_start=0, mutex_start=0, total_start=0;
|
||||
static int count = 0;
|
||||
|
||||
DECLARE_ALL_MIN_MAX;
|
||||
|
||||
while (running) {
|
||||
frames=0;
|
||||
available_frames_space=0;
|
||||
|
||||
TIME_MEASUREMENT_START(timer_start);
|
||||
TIME_MEASUREMENT_START(total_start);
|
||||
TIME_MEASUREMENT_START(mutex_start);
|
||||
LOCK;
|
||||
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1);
|
||||
if (output.state == OUTPUT_OFF) {
|
||||
UNLOCK;
|
||||
LOG_SDEBUG("Output state is off.");
|
||||
usleep(500000);
|
||||
continue;
|
||||
}
|
||||
TIME_MEASUREMENT_START(mutex_start);
|
||||
LOCK_BT;
|
||||
SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex2);
|
||||
available_frames_space = min(_buf_space(btbuf), _buf_cont_write(btbuf))/BYTES_PER_FRAME;
|
||||
SET_MIN_MAX( available_frames_space,req);
|
||||
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)
|
||||
{
|
||||
UNLOCK;
|
||||
UNLOCK_BT;
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
frames = _output_frames( available_frames_space ); // Keep the transfer buffer full
|
||||
SET_MIN_MAX(_buf_used(btbuf),locbtbuff);
|
||||
UNLOCK;
|
||||
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( available_frames_space,req);
|
||||
SET_MIN_MAX(frames,rec);
|
||||
// if(frames>0 ){
|
||||
// // let's hold processing a bit, while frames are being processed
|
||||
// // we're waiting long enough to avoid hogging the CPU too much
|
||||
// // while we're ramping up this transfer buffer
|
||||
// wait_for_frames(frames,95);
|
||||
// }
|
||||
wait_for_frames(FRAME_BLOCK,100);
|
||||
|
||||
/*
|
||||
* Statistics reporting
|
||||
*/
|
||||
#define STATS_PERIOD_MS 10000
|
||||
count++;
|
||||
TIMED_SECTION_START_MS(STATS_PERIOD_MS);
|
||||
if(count>1){
|
||||
LOG_INFO( "count:%d, current sample rate: %d, avg cycle duration (ms): %d",count,output.current_sample_rate, STATS_PERIOD_MS/count);
|
||||
LOG_INFO( " ----------+----------+-----------+-----------+ +----------+----------+----------------+----------------+----------------+");
|
||||
LOG_INFO( " max | min | avg | current| | max | min | average | count | current |");
|
||||
LOG_INFO( " (ms) | (ms) | (ms)| (ms) | | (bytes) | (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("requested",req));
|
||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
||||
LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("local bt buf",locbtbuff));
|
||||
LOG_INFO(" ----------+----------+-----------+-----------+ +----------+----------+----------------+----------------+");
|
||||
LOG_INFO("");
|
||||
LOG_INFO(" ----------+----------+-----------+-----------+-----------+ ");
|
||||
LOG_INFO(" max (us) | min (us) | avg(us) | count |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("Output mux(us)",mutex1));
|
||||
LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("BT mux(us)",mutex2));
|
||||
LOG_INFO(" ----------+----------+-----------+-----------+-----------+");
|
||||
RESET_ALL_MIN_MAX;
|
||||
count=0;
|
||||
}
|
||||
TIMED_SECTION_END;
|
||||
/*
|
||||
* End Statistics reporting
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
void output_close_bt(void) {
|
||||
LOG_INFO("close output");
|
||||
LOCK;
|
||||
@@ -83,7 +233,9 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
}
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
memcpy(bt_optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||
|
||||
memcpy(btbuf->writep, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||
|
||||
#else
|
||||
{
|
||||
frames_t count = out_frames;
|
||||
@@ -100,11 +252,8 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
DEBUG_LOG_TIMED(200,"Silence flag true. Writing silence to audio out.");
|
||||
|
||||
u8_t *buf = silencebuf;
|
||||
|
||||
memcpy(bt_optr, buf, out_frames * 4);
|
||||
memcpy(btbuf->writep, buf, out_frames * BYTES_PER_FRAME);
|
||||
}
|
||||
|
||||
bt_optr += out_frames * 4;
|
||||
|
||||
_buf_inc_writep(btbuf,out_frames * BYTES_PER_FRAME);
|
||||
return (int)out_frames;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user