|
@@ -29,6 +29,7 @@ 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)
|
|
@@ -36,20 +37,19 @@ extern struct buffer *outputbuf;
|
|
|
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
|
|
|
|
|
extern u8_t *silencebuf;
|
|
|
+static u8_t *optr;
|
|
|
|
|
|
-// buffer to hold output data so we can block on writing outside of output lock, allocated on init
|
|
|
-static u8_t *buf;
|
|
|
-static unsigned buffill;
|
|
|
-static int bytes_per_frame;
|
|
|
-
|
|
|
-static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
|
|
- s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
|
|
|
+static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
|
|
+ s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
|
|
|
|
|
void set_volume(unsigned left, unsigned right) {
|
|
|
LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
|
|
|
LOCK;
|
|
|
output.gainL = left;
|
|
|
output.gainR = right;
|
|
|
+ // TODO
|
|
|
+ output.gainL = FIXED_ONE;
|
|
|
+ output.gainR = FIXED_ONE;
|
|
|
UNLOCK;
|
|
|
}
|
|
|
|
|
@@ -127,26 +127,12 @@ void output_init_dac(log_level level, unsigned output_buf_size, char *params, un
|
|
|
|
|
|
LOG_INFO("init output BT");
|
|
|
|
|
|
- buf = malloc(FRAME_BLOCK * BYTES_PER_FRAME);
|
|
|
- if (!buf) {
|
|
|
- LOG_ERROR("unable to malloc buf");
|
|
|
- return;
|
|
|
- }
|
|
|
- buffill = 0;
|
|
|
-
|
|
|
memset(&output, 0, sizeof(output));
|
|
|
|
|
|
- output.format = S32_LE;
|
|
|
output.start_frames = FRAME_BLOCK * 2;
|
|
|
- output.write_cb = &_bt_write_frames;
|
|
|
+ output.write_cb = &_write_frames;
|
|
|
output.rate_delay = rate_delay;
|
|
|
|
|
|
- if (params) {
|
|
|
- if (!strcmp(params, "32")) output.format = S32_LE;
|
|
|
- if (!strcmp(params, "24")) output.format = S24_3LE;
|
|
|
- if (!strcmp(params, "16")) output.format = S16_LE;
|
|
|
- }
|
|
|
-
|
|
|
// ensure output rate is specified to avoid test open
|
|
|
if (!rates[0]) {
|
|
|
rates[0] = 44100;
|
|
@@ -226,32 +212,46 @@ void output_close_dac(void) {
|
|
|
running = false;
|
|
|
UNLOCK;
|
|
|
|
|
|
- free(buf);
|
|
|
-
|
|
|
output_close_common();
|
|
|
}
|
|
|
|
|
|
-static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
|
|
- s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
|
|
|
-
|
|
|
- u8_t *obuf;
|
|
|
-
|
|
|
+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 (!silence) {
|
|
|
-
|
|
|
+
|
|
|
+ /* 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);
|
|
|
}
|
|
|
-
|
|
|
- obuf = outputbuf->readp;
|
|
|
+
|
|
|
+ if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
|
|
|
+ _apply_gain(outputbuf, out_frames, gainL, gainR);
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+#if BYTES_PER_FRAME == 4
|
|
|
+ memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
|
|
+#else
|
|
|
+ {
|
|
|
+ frames_t count = out_frames;
|
|
|
+ s32_t *_iptr = (s32_t*) outputbuf->readp;
|
|
|
+ s16_t *_optr = (s32_t*) optr;
|
|
|
+ while (count--) {
|
|
|
+ *_optr++ = *_iptr++ >> 16;
|
|
|
+ *_optr++ = *_iptr++ >> 16;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- obuf = silencebuf;
|
|
|
- }
|
|
|
+ u8_t *buf = silencebuf;
|
|
|
|
|
|
- _scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format);
|
|
|
-
|
|
|
- buffill += out_frames;
|
|
|
+ memcpy(optr, buf, out_frames * 4);
|
|
|
+ }
|
|
|
+
|
|
|
+ optr += out_frames * 4;
|
|
|
|
|
|
return (int)out_frames;
|
|
|
}
|
|
@@ -495,18 +495,16 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
|
|
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
|
|
{
|
|
|
frames_t frames;
|
|
|
- int i;
|
|
|
- s16_t *optr = (s16_t*) data;
|
|
|
- s32_t *iptr = (s32_t*) buf;
|
|
|
+ static int count = 0;
|
|
|
|
|
|
- if (len < 0 || data == NULL) {
|
|
|
+ if (len < 0 || data == NULL) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
LOCK;
|
|
|
|
|
|
/* TODO
|
|
|
- Normally, we would want BT to not call us back unless we have not in BUFFERING state.
|
|
|
+ Normally, we would want BT to not call us back unless we are not in BUFFERING state.
|
|
|
That requires BT to not start until we are > OUTPUT_BUFFER
|
|
|
// come back later, we are buffering (or stopped, need to handle that case ...) but we don't want silence
|
|
|
if (output.state <= OUTPUT_BUFFER) {
|
|
@@ -515,34 +513,21 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
- switch (output.format) {
|
|
|
- case S32_LE:
|
|
|
- bytes_per_frame = 4 * 2; break;
|
|
|
- case S24_3LE:
|
|
|
- bytes_per_frame = 3 * 2; break;
|
|
|
- case S16_LE:
|
|
|
- bytes_per_frame = 2 * 2; break;
|
|
|
- default:
|
|
|
- bytes_per_frame = 4 * 2; break;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // TODO update with proper bytes_per_frame handling
|
|
|
frames = len / 4;
|
|
|
output.device_frames = 0;
|
|
|
output.updated = gettime_ms();
|
|
|
output.frames_played_dmp = output.frames_played;
|
|
|
+ if (!output.threshold) output.threshold = 20;
|
|
|
+
|
|
|
+ optr = data;
|
|
|
frames = _output_frames(frames);
|
|
|
|
|
|
UNLOCK;
|
|
|
|
|
|
- for (i = 0; i < frames*2; i++) {
|
|
|
- *optr++ = *iptr++ >> 16;
|
|
|
- *optr++ = *iptr++ >> 16;
|
|
|
+ if (!(count++ & 0x1ff)) {
|
|
|
+ LOG_INFO("frames %d (count:%d) (out:%d, stream:%d)", frames, count, _buf_used(outputbuf), _buf_used(streambuf));
|
|
|
}
|
|
|
|
|
|
- buffill = 0;
|
|
|
-
|
|
|
return frames * 4;
|
|
|
}
|
|
|
|