123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- #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;
- #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 FRAME_BLOCK MAX_SILENCE_FRAMES
- extern u8_t *silencebuf;
- void hal_bluetooth_init(log_level);
- 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(under);\
- DECLARE_MIN_MAX_DURATION(mutex1);\
- DECLARE_MIN_MAX_DURATION(mutex2);\
- DECLARE_MIN_MAX_DURATION(buffering);\
- DECLARE_MIN_MAX_DURATION(sleep_time);
- #define RESET_ALL_MIN_MAX \
- RESET_MIN_MAX(o); \
- RESET_MIN_MAX(s); \
- RESET_MIN_MAX(locbtbuff); \
- RESET_MIN_MAX(req); \
- RESET_MIN_MAX(rec); \
- RESET_MIN_MAX(under); \
- RESET_MIN_MAX_DURATION(mutex1); \
- RESET_MIN_MAX_DURATION(mutex2); \
- RESET_MIN_MAX_DURATION(sleep_time); \
- RESET_MIN_MAX_DURATION(buffering);
- #if CONFIG_BTAUDIO
- void set_volume_bt(unsigned left, unsigned right) {
- LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
- LOCK;
- output.gainL = left;
- output.gainR = right;
- UNLOCK;
- }
- #endif
- void output_bt_check_buffer()
- {
- #ifdef USE_BT_RING_BUFFER
- LOCK_BT;
- uint8_t tot_buf_used_pct=100*_buf_used(btbuf)/btbuf->size;
- UNLOCK_BT;
- if(tot_buf_used_pct<bt_buf_used_threshold)
- {
-
- 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;
-
- LOG_SDEBUG("Locking suspend mutex.");
- mutex_lock(output_bt_suspend_mutex);
- LOG_SDEBUG("Waiting on condition to be signaled.");
-
-
-
- gettimeofday(&tp, NULL);
-
- ts.tv_sec = tp.tv_sec;
- ts.tv_nsec = tp.tv_usec * 1000;
- ts.tv_nsec += output_bt_thread_heartbeat_ms*1000000;
- 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) {
- loglevel = level;
- LOG_INFO("init output BT");
- memset(&output, 0, sizeof(output));
-
- if (!rates[0]) {
- rates[0] = 44100;
- }
- hal_bluetooth_init(loglevel);
- device = CONFIG_OUTPUT_NAME;
- output_init_common(level, device, output_buf_size, rates, idle);
- #ifdef USE_BT_RING_BUFFER
- LOG_DEBUG("Allocating local BT transfer buffer of %u bytes.",bt_buffer_size);
- buf_init(btbuf, bt_buffer_size );
- if (!btbuf->buf) {
- LOG_ERROR("unable to malloc BT buffer");
- exit(0);
- }
- mutex_create_p(output_bt_suspend_mutex);
- mutex_cond_init(output_bt_suspend_cond);
- PTHREAD_SET_NAME("output_bt");
- #if LINUX || OSX || FREEBSD || POSIX
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- #ifdef PTHREAD_STACK_MIN
- pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
- #endif
- pthread_create(&thread_bt, &attr, output_thread_bt, NULL);
- #endif
- pthread_attr_destroy(&attr);
- #if WIN
- thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread_bt, NULL, 0, NULL);
- #endif
- #else
- output.start_frames = FRAME_BLOCK;
- output.write_cb = &_write_frames;
- output.rate_delay = rate_delay;
- #endif
- LOG_INFO("Init completed.");
- }
- #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);
-
- TIME_MEASUREMENT_START(mutex_start);
- LOCK;
- state=output.state;
- SET_MIN_MAX(TIME_MEASUREMENT_GET(mutex_start),mutex1);
- if(state < OUTPUT_STOPPED ){
-
-
- 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;
- 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);
-
-
- 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 );
- 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);
-
-
-
- TIME_MEASUREMENT_START(timer_start);
- if(state>OUTPUT_BUFFER){
- output_bt_suspend();
- }
- SET_MIN_MAX(TIME_MEASUREMENT_GET(timer_start),sleep_time);
-
- 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;
- }
-
- }
- return NULL;
- }
- #endif
- void output_close_bt(void) {
- LOG_INFO("close output");
- LOCK;
- running = false;
- UNLOCK;
- #ifdef USE_BT_RING_BUFFER
- LOCK_BT;
- buf_destroy(btbuf);
- UNLOCK_BT;
- #endif
- output_close_common();
- }
- static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
- s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
- #ifdef USE_BT_RING_BUFFER
- if (!silence ) {
- DEBUG_LOG_TIMED(200,"Not silence, Writing audio out.");
-
- 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){
-
- 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.");
-
- 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;
- }
|