output_bt.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Squeezelite for esp32
  3. *
  4. * (c) Sebastien 2019
  5. * Philippe G. 2019, philippe_44@outlook.com
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #include "driver/gpio.h"
  22. #include "squeezelite.h"
  23. #include "equalizer.h"
  24. #include "perf_trace.h"
  25. #include "config.h"
  26. extern struct outputstate output;
  27. extern struct buffer *outputbuf;
  28. extern struct buffer *streambuf;
  29. extern u8_t *silencebuf;
  30. #define LOCK mutex_lock(outputbuf->mutex)
  31. #define UNLOCK mutex_unlock(outputbuf->mutex)
  32. #define LOCK_S mutex_lock(streambuf->mutex)
  33. #define UNLOCK_S mutex_unlock(streambuf->mutex)
  34. #define FRAME_BLOCK MAX_SILENCE_FRAMES
  35. #define STATS_REPORT_DELAY_MS 15000
  36. extern void hal_bluetooth_init(const char * options);
  37. extern void hal_bluetooth_stop(void);
  38. extern u8_t config_spdif_gpio;
  39. static log_level loglevel;
  40. static bool running = false;
  41. static uint8_t *btout;
  42. static frames_t oframes;
  43. static bool stats;
  44. static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
  45. s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
  46. #define DECLARE_ALL_MIN_MAX \
  47. DECLARE_MIN_MAX(req);\
  48. DECLARE_MIN_MAX(rec);\
  49. DECLARE_MIN_MAX(bt);\
  50. DECLARE_MIN_MAX(under);\
  51. DECLARE_MIN_MAX(stream_buf);\
  52. DECLARE_MIN_MAX_DURATION(lock_out_time)
  53. #define RESET_ALL_MIN_MAX \
  54. RESET_MIN_MAX(bt); \
  55. RESET_MIN_MAX(req); \
  56. RESET_MIN_MAX(rec); \
  57. RESET_MIN_MAX(under); \
  58. RESET_MIN_MAX(stream_buf); \
  59. RESET_MIN_MAX_DURATION(lock_out_time)
  60. DECLARE_ALL_MIN_MAX;
  61. void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
  62. loglevel = level;
  63. running = true;
  64. output.write_cb = &_write_frames;
  65. hal_bluetooth_init(device);
  66. char *p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
  67. stats = p && (*p == '1' || *p == 'Y' || *p == 'y');
  68. free(p);
  69. }
  70. void output_close_bt(void) {
  71. LOCK;
  72. running = false;
  73. UNLOCK;
  74. hal_bluetooth_stop();
  75. equalizer_close();
  76. }
  77. static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
  78. s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
  79. assert(btout != NULL);
  80. if (!silence ) {
  81. if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
  82. _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
  83. }
  84. if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
  85. _apply_gain(outputbuf, out_frames, gainL, gainR);
  86. }
  87. #if BYTES_PER_FRAME == 4
  88. memcpy(btout + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);
  89. #else
  90. {
  91. frames_t count = out_frames;
  92. s32_t *_iptr = (s32_t*) outputbuf->readp;
  93. s16_t *_optr = (s16_t*) (btout + oframes * BYTES_PER_FRAME);
  94. while (count--) {
  95. *_optr++ = *_iptr++ >> 16;
  96. *_optr++ = *_iptr++ >> 16;
  97. }
  98. }
  99. #endif
  100. } else {
  101. u8_t *buf = silencebuf;
  102. memcpy(btout + oframes * BYTES_PER_FRAME, buf, out_frames * BYTES_PER_FRAME);
  103. }
  104. output_visu_export((s16_t*) (btout + oframes * BYTES_PER_FRAME), out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2);
  105. return (int)out_frames;
  106. }
  107. int32_t output_bt_data(uint8_t *data, int32_t len) {
  108. int32_t avail_data = 0, wanted_len = 0, start_timer = 0;
  109. if (len < 0 || data == NULL || !running) {
  110. return 0;
  111. }
  112. btout = data;
  113. oframes = 0;
  114. // This is how the BTC layer calculates the number of bytes to
  115. // for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes
  116. wanted_len=len;
  117. SET_MIN_MAX(len,req);
  118. TIME_MEASUREMENT_START(start_timer);
  119. LOCK;
  120. output.device_frames = 0; // todo: check if this is the right way do to this.
  121. output.updated = gettime_ms();
  122. output.frames_played_dmp = output.frames_played;
  123. SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size);
  124. do {
  125. avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full
  126. wanted_len-=avail_data;
  127. } while (wanted_len > 0 && avail_data != 0);
  128. if (wanted_len > 0) {
  129. SET_MIN_MAX(wanted_len, under);
  130. }
  131. output.frames_in_process = len-wanted_len;
  132. equalizer_process(data, (len - wanted_len) * BYTES_PER_FRAME, output.current_sample_rate);
  133. UNLOCK;
  134. SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
  135. SET_MIN_MAX((len-wanted_len), rec);
  136. TIME_MEASUREMENT_START(start_timer);
  137. return len-wanted_len;
  138. }
  139. void output_bt_tick(void) {
  140. static time_t lastTime=0;
  141. if (!running) return;
  142. LOCK_S;
  143. SET_MIN_MAX_SIZED(_buf_used(streambuf), stream_buf, streambuf->size);
  144. UNLOCK_S;
  145. if (stats && lastTime <= gettime_ms() )
  146. {
  147. lastTime = gettime_ms() + STATS_REPORT_DELAY_MS;
  148. LOG_INFO("Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000);
  149. LOG_INFO(" +==========+==========+================+=====+================+");
  150. LOG_INFO(" | max | min | average | avg | count |");
  151. LOG_INFO(" | (bytes) | (bytes) | (bytes) | pct | |");
  152. LOG_INFO(" +==========+==========+================+=====+================+");
  153. LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf));
  154. LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt));
  155. LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
  156. LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
  157. LOG_INFO(LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under));
  158. LOG_INFO( " +==========+==========+================+=====+================+");
  159. LOG_INFO("\n");
  160. LOG_INFO(" ==========+==========+===========+===========+ ");
  161. LOG_INFO(" max (us) | min (us) | avg(us) | count | ");
  162. LOG_INFO(" ==========+==========+===========+===========+ ");
  163. LOG_INFO(LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time));
  164. LOG_INFO(" ==========+==========+===========+===========+");
  165. RESET_ALL_MIN_MAX;
  166. }
  167. }