diff --git a/spa/plugins/bluez5/a2dp-codec-aac.c b/spa/plugins/bluez5/a2dp-codec-aac.c index 0f677c2c1..82b43edfc 100644 --- a/spa/plugins/bluez5/a2dp-codec-aac.c +++ b/spa/plugins/bluez5/a2dp-codec-aac.c @@ -377,11 +377,6 @@ static void codec_deinit(void *data) free(this); } -static int codec_get_num_blocks(void *data) -{ - return 1; -} - static int codec_get_block_size(void *data) { struct impl *this = data; @@ -407,7 +402,7 @@ static int codec_start_encode (void *data, static int codec_encode(void *data, const void *src, size_t src_size, void *dst, size_t dst_size, - size_t *dst_out) + size_t *dst_out, int *need_flush) { struct impl *this = data; int res; @@ -445,6 +440,7 @@ static int codec_encode(void *data, return -EINVAL; *dst_out = out_args.numOutBytes; + *need_flush = 1; return out_args.numInSamples * this->samplesize; } @@ -498,7 +494,6 @@ const struct a2dp_codec a2dp_codec_aac = { .init = codec_init, .deinit = codec_deinit, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .start_encode = codec_start_encode, .encode = codec_encode, .abr_process = codec_abr_process, diff --git a/spa/plugins/bluez5/a2dp-codec-aptx.c b/spa/plugins/bluez5/a2dp-codec-aptx.c index b7de7588c..af51aadbb 100644 --- a/spa/plugins/bluez5/a2dp-codec-aptx.c +++ b/spa/plugins/bluez5/a2dp-codec-aptx.c @@ -43,6 +43,8 @@ struct impl { size_t mtu; int codesize; int frame_length; + int frame_count; + int max_frames; bool hd; }; @@ -202,19 +204,6 @@ static int codec_increase_bitpool(void *data) return -ENOTSUP; } -static int codec_get_num_blocks(void *data) -{ - struct impl *this = data; - size_t frame_count; - - if (this->hd) - frame_count = (this->mtu - sizeof(struct rtp_header)) / this->frame_length; - else - frame_count = this->mtu / this->frame_length; - - return frame_count; -} - static int codec_get_block_size(void *data) { struct impl *this = data; @@ -247,6 +236,11 @@ static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, this->frame_length = this->hd ? 6 : 4; this->codesize = 4 * 3 * 2; + if (this->hd) + this->max_frames = (this->mtu - sizeof(struct rtp_header)) / this->frame_length; + else + this->max_frames = this->mtu / this->frame_length; + return this; error_errno: @@ -277,6 +271,8 @@ static int codec_start_encode (void *data, { struct impl *this = data; + this->frame_count = 0; + if (!this->hd) return 0; @@ -287,21 +283,31 @@ static int codec_start_encode (void *data, this->header->pt = 1; this->header->sequence_number = htons(seqnum); this->header->timestamp = htonl(timestamp); - this->header->ssrc = htonl(1); return sizeof(struct rtp_header); } static int codec_encode(void *data, const void *src, size_t src_size, void *dst, size_t dst_size, - size_t *dst_out) + size_t *dst_out, int *need_flush) { struct impl *this = data; + size_t avail_dst_size; int res; - res = aptx_encode(this->aptx, src, src_size, - dst, dst_size, dst_out); + avail_dst_size = (this->max_frames - this->frame_count) * this->frame_length; + if (SPA_UNLIKELY(dst_size < avail_dst_size)) { + *need_flush = 1; + return 0; + } + res = aptx_encode(this->aptx, src, src_size, + dst, avail_dst_size, dst_out); + if(SPA_UNLIKELY(res < 0)) + return -EINVAL; + + this->frame_count += *dst_out / this->frame_length; + *need_flush = this->frame_count >= this->max_frames; return res; } @@ -352,7 +358,6 @@ const struct a2dp_codec a2dp_codec_aptx = { .init = codec_init, .deinit = codec_deinit, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process, .start_encode = codec_start_encode, .encode = codec_encode, @@ -376,7 +381,6 @@ const struct a2dp_codec a2dp_codec_aptx_hd = { .init = codec_init, .deinit = codec_deinit, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process, .start_encode = codec_start_encode, .encode = codec_encode, diff --git a/spa/plugins/bluez5/a2dp-codec-ldac.c b/spa/plugins/bluez5/a2dp-codec-ldac.c index cbbc4bd4a..14dbb8719 100644 --- a/spa/plugins/bluez5/a2dp-codec-ldac.c +++ b/spa/plugins/bluez5/a2dp-codec-ldac.c @@ -76,50 +76,6 @@ struct impl { int codesize; int frame_length; int frame_count; - int frame_count_factor; - - const struct props *props; -}; - -enum { - LDACBT_EQMID_BITRATE_990000 = 0, /* LDACBT_EQMID_HQ */ - LDACBT_EQMID_BITRATE_660000, /* LDACBT_EQMID_SQ */ - LDACBT_EQMID_BITRATE_330000, /* LDACBT_EQMID_MQ */ - - LDACBT_EQMID_BITRATE_492000, - LDACBT_EQMID_BITRATE_396000, - LDACBT_EQMID_BITRATE_282000, - LDACBT_EQMID_BITRATE_246000, - LDACBT_EQMID_BITRATE_216000, - LDACBT_EQMID_BITRATE_198000, - LDACBT_EQMID_BITRATE_180000, - LDACBT_EQMID_BITRATE_162000, - LDACBT_EQMID_BITRATE_150000, - LDACBT_EQMID_BITRATE_138000 -}; - -struct ldac_config -{ - int eqmid; - int frame_count; /* number of ldac frames in packet */ - int frame_length; /* ldac frame length */ - int frame_length_1ch; /* ldac frame length per channel */ -}; - -static const struct ldac_config ldac_config_table[] = { - { LDACBT_EQMID_BITRATE_990000, 2, 330, 165}, - { LDACBT_EQMID_BITRATE_660000, 3, 220, 110}, - { LDACBT_EQMID_BITRATE_492000, 4, 164, 82}, - { LDACBT_EQMID_BITRATE_396000, 5, 132, 66}, - { LDACBT_EQMID_BITRATE_330000, 6, 110, 55}, - { LDACBT_EQMID_BITRATE_282000, 7, 94, 47}, - { LDACBT_EQMID_BITRATE_246000, 8, 82, 41}, - { LDACBT_EQMID_BITRATE_216000, 9, 72, 36}, - { LDACBT_EQMID_BITRATE_198000, 10, 66, 33}, - { LDACBT_EQMID_BITRATE_180000, 11, 60, 30}, - { LDACBT_EQMID_BITRATE_162000, 12, 54, 27}, - { LDACBT_EQMID_BITRATE_150000, 13, 50, 25}, - { LDACBT_EQMID_BITRATE_138000, 14, 46, 23}, }; static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, uint8_t caps[A2DP_MAX_CAPS_SIZE]) @@ -265,23 +221,6 @@ static int codec_enum_config(const struct a2dp_codec *codec, return *param == NULL ? -EIO : 1; } -static int update_frame_info(struct impl *this) -{ - const struct ldac_config *config; - this->eqmid = ldacBT_get_eqmid(this->ldac); - for (size_t i = 0; i < SPA_N_ELEMENTS(ldac_config_table); ++i) { - config = &ldac_config_table[i]; - - if (config->eqmid != this->eqmid) - continue; - - this->frame_count = config->frame_count; - this->frame_length = config->frame_length; - return 0; - } - return -EINVAL; -} - static int codec_reduce_bitpool(void *data) { #ifdef ENABLE_LDAC_ABR @@ -292,7 +231,6 @@ static int codec_reduce_bitpool(void *data) if (this->eqmid == LDACBT_EQMID_BITRATE_330000 || !this->enable_abr) return this->eqmid; res = ldacBT_alter_eqmid_priority(this->ldac, LDACBT_EQMID_INC_CONNECTION); - update_frame_info(this); return res; #endif } @@ -307,17 +245,10 @@ static int codec_increase_bitpool(void *data) if (!this->enable_abr) return this->eqmid; res = ldacBT_alter_eqmid_priority(this->ldac, LDACBT_EQMID_INC_QUALITY); - update_frame_info(this); return res; #endif } -static int codec_get_num_blocks(void *data) -{ - struct impl *this = data; - return this->frame_count * this->frame_count_factor; -} - static int codec_get_block_size(void *data) { struct impl *this = data; @@ -450,7 +381,7 @@ static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, this->mtu = mtu; this->frequency = info->info.raw.rate; - this->codesize = info->info.raw.channels; + this->codesize = info->info.raw.channels * LDACBT_ENC_LSU; switch (info->info.raw.format) { case SPA_AUDIO_FORMAT_F32: @@ -474,23 +405,6 @@ static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, goto error; } - switch(conf->frequency) { - case LDACBT_SAMPLING_FREQ_044100: - case LDACBT_SAMPLING_FREQ_048000: - this->codesize *= 128; - this->frame_count_factor = 1; - break; - case LDACBT_SAMPLING_FREQ_088200: - case LDACBT_SAMPLING_FREQ_096000: - /* ldac ecoder has a constant encoding lsu: LDACBT_ENC_LSU=128 */ - this->codesize *= 128; - this->frame_count_factor = 2; - break; - default: - res = -EINVAL; - goto error; - } - res = ldacBT_init_handle_encode(this->ldac, this->mtu, this->eqmid, @@ -513,8 +427,6 @@ static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, goto error; #endif - update_frame_info(this); - return this; error_errno: @@ -562,8 +474,6 @@ static int codec_update_props(void *data, void *props) if ((res = ldacBT_set_eqmid(this->ldac, this->eqmid)) < 0) goto error; - if ((res = update_frame_info(this)) < 0) - goto error; return 0; error: return res; @@ -576,7 +486,6 @@ static int codec_abr_process(void *data, size_t unsent) int res; res = ldac_ABR_Proc(this->ldac, this->ldac_abr, unsent / LDAC_ABR_MAX_PACKET_NBYTES, this->enable_abr); - update_frame_info(this); return res; #else return -ENOTSUP; @@ -604,7 +513,7 @@ static int codec_start_encode (void *data, static int codec_encode(void *data, const void *src, size_t src_size, void *dst, size_t dst_size, - size_t *dst_out) + size_t *dst_out, int *need_flush) { struct impl *this = data; int res, src_used, dst_used, frame_num = 0; @@ -613,12 +522,13 @@ static int codec_encode(void *data, dst_used = dst_size; res = ldacBT_encode(this->ldac, (void*)src, &src_used, dst, &dst_used, &frame_num); - if (res < 0) + if (SPA_UNLIKELY(res < 0)) return -EINVAL; *dst_out = dst_used; this->payload->frame_count += frame_num; + *need_flush = this->payload->frame_count > 0; return src_used; } @@ -644,7 +554,6 @@ const struct a2dp_codec a2dp_codec_ldac = { .deinit = codec_deinit, .update_props = codec_update_props, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process, .start_encode = codec_start_encode, .encode = codec_encode, diff --git a/spa/plugins/bluez5/a2dp-codec-sbc.c b/spa/plugins/bluez5/a2dp-codec-sbc.c index 38bac75f9..b7f5e4567 100644 --- a/spa/plugins/bluez5/a2dp-codec-sbc.c +++ b/spa/plugins/bluez5/a2dp-codec-sbc.c @@ -45,7 +45,7 @@ struct impl { size_t mtu; int codesize; - int frame_length; + int max_frames; int min_bitpool; int max_bitpool; @@ -86,7 +86,7 @@ static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, static uint8_t default_bitpool(uint8_t freq, uint8_t mode, bool xq) { /* A2DP spec v1.2 states that all SNK implementation shall handle bitrates - * of up to 512 kbps (~ bitpool = 86 stereo, or 2x43 dual channel at 44.1KHz + * of up to 512 kbps (~ bitpool = 86 stereo, or 2x43 dual channel at 44.1KHz * or ~ bitpool = 78 stereo, or 2x39 dual channel at 48KHz). */ switch (freq) { case SBC_SAMPLING_FREQ_16000: @@ -325,9 +325,13 @@ static int codec_validate_config(const struct a2dp_codec *codec, uint32_t flags, static int codec_set_bitpool(struct impl *this, int bitpool) { + size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + this->sbc.bitpool = SPA_CLAMP(bitpool, this->min_bitpool, this->max_bitpool); this->codesize = sbc_get_codesize(&this->sbc); - this->frame_length = sbc_get_frame_length(&this->sbc); + this->max_frames = (this->mtu - rtp_size) / sbc_get_frame_length(&this->sbc); + if (this->max_frames > 15) + this->max_frames = 15; return this->sbc.bitpool; } @@ -422,18 +426,6 @@ static int codec_increase_bitpool(void *data) return codec_set_bitpool(this, this->sbc.bitpool + 1); } -static int codec_get_num_blocks(void *data) -{ - struct impl *this = data; - size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); - size_t frame_count = (this->mtu - rtp_size) / this->frame_length; - - /* frame_count is only 4 bit number */ - if (frame_count > 15) - frame_count = 15; - return frame_count; -} - static int codec_get_block_size(void *data) { struct impl *this = data; @@ -580,17 +572,19 @@ static int codec_start_encode (void *data, static int codec_encode(void *data, const void *src, size_t src_size, void *dst, size_t dst_size, - size_t *dst_out) + size_t *dst_out, int *need_flush) { struct impl *this = data; int res; res = sbc_encode(&this->sbc, src, src_size, dst, dst_size, (ssize_t*)dst_out); + if (SPA_UNLIKELY(res < 0)) + return -EINVAL; + spa_assert(res == this->codesize); - if (res >= this->codesize) - this->payload->frame_count += res / this->codesize; - + this->payload->frame_count += res / this->codesize; + *need_flush = this->payload->frame_count >= this->max_frames; return res; } @@ -636,7 +630,6 @@ const struct a2dp_codec a2dp_codec_sbc = { .init = codec_init, .deinit = codec_deinit, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process, .start_encode = codec_start_encode, .encode = codec_encode, @@ -659,7 +652,6 @@ const struct a2dp_codec a2dp_codec_sbc_xq = { .init = codec_init, .deinit = codec_deinit, .get_block_size = codec_get_block_size, - .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process, .start_encode = codec_start_encode, .encode = codec_encode, diff --git a/spa/plugins/bluez5/a2dp-codecs.h b/spa/plugins/bluez5/a2dp-codecs.h index 016e5cf2e..0a79835e5 100644 --- a/spa/plugins/bluez5/a2dp-codecs.h +++ b/spa/plugins/bluez5/a2dp-codecs.h @@ -371,7 +371,6 @@ struct a2dp_codec { int (*update_props) (void *data, void *props); int (*get_block_size) (void *data); - int (*get_num_blocks) (void *data); int (*abr_process) (void *data, size_t unsent); @@ -380,7 +379,7 @@ struct a2dp_codec { int (*encode) (void *data, const void *src, size_t src_size, void *dst, size_t dst_size, - size_t *dst_out); + size_t *dst_out, int *need_flush); int (*start_decode) (void *data, const void *src, size_t src_size, uint16_t *seqnum, uint32_t *timestamp); diff --git a/spa/plugins/bluez5/a2dp-sink.c b/spa/plugins/bluez5/a2dp-sink.c index 81a6a94fc..c80f2a5d3 100644 --- a/spa/plugins/bluez5/a2dp-sink.c +++ b/spa/plugins/bluez5/a2dp-sink.c @@ -133,10 +133,11 @@ struct impl { void *codec_data; struct spa_audio_info codec_format; + int need_flush; uint32_t block_size; - uint32_t num_blocks; uint8_t buffer[4096]; uint32_t buffer_used; + uint32_t header_size; uint32_t frame_count; uint16_t seqnum; uint32_t timestamp; @@ -376,11 +377,6 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, return 0; } -static void update_num_blocks(struct impl *this) -{ - this->num_blocks = this->codec->get_num_blocks(this->codec_data); -} - static int reset_buffer(struct impl *this) { if (this->codec_props_changed && this->codec_props @@ -388,10 +384,12 @@ static int reset_buffer(struct impl *this) this->codec->update_props(this->codec_data, this->codec_props); this->codec_props_changed = false; } + this->need_flush = 0; this->frame_count = 0; this->buffer_used = this->codec->start_encode(this->codec_data, this->buffer, sizeof(this->buffer), this->seqnum++, this->timestamp); + this->header_size = this->buffer_used; this->timestamp = this->sample_count; return 0; } @@ -415,7 +413,6 @@ static int send_buffer(struct impl *this) if (unsent >= 0) { unsent = this->fd_buffer_size - unsent; this->codec->abr_process(this->codec_data, unsent); - update_num_blocks(this); } spa_log_trace(this->log, NAME " %p: send %d %u %u %u %u", @@ -441,11 +438,6 @@ static bool want_flush(struct impl *this) return (this->frame_count * this->block_size / this->port.frame_size >= MIN_LATENCY); } -static bool need_flush(struct impl *this) -{ - return (this->frame_count >= this->num_blocks); -} - static int encode_buffer(struct impl *this, const void *data, uint32_t size) { int processed; @@ -458,7 +450,7 @@ static int encode_buffer(struct impl *this, const void *data, uint32_t size) this, size, this->buffer_used, port->frame_size, this->block_size, this->frame_count); - if (need_flush(this)) + if (this->need_flush) return 0; if (this->buffer_used >= sizeof(this->buffer)) @@ -479,7 +471,7 @@ static int encode_buffer(struct impl *this, const void *data, uint32_t size) from_data, from_size, this->buffer + this->buffer_used, sizeof(this->buffer) - this->buffer_used, - &out_encoded); + &out_encoded, &this->need_flush); if (processed < 0) return processed; @@ -499,10 +491,10 @@ static int encode_buffer(struct impl *this, const void *data, uint32_t size) static int flush_buffer(struct impl *this) { - spa_log_trace(this->log, NAME" %p: used:%d num_blocks:%d block_size:%d", this, - this->buffer_used, this->num_blocks, this->block_size); + spa_log_trace(this->log, NAME" %p: used:%d block_size:%d", this, + this->buffer_used, this->block_size); - if (want_flush(this) || need_flush(this)) + if (this->need_flush || want_flush(this)) return send_buffer(this); return 0; @@ -536,12 +528,11 @@ static void enable_flush(struct impl *this, bool enabled) static int flush_data(struct impl *this, uint64_t now_time) { int written; - uint32_t total_frames, iter_buffer_used; + uint32_t total_frames; struct port *port = &this->port; total_frames = 0; again: - iter_buffer_used = this->buffer_used; while (!spa_list_is_empty(&port->ready)) { uint8_t *src; uint32_t n_bytes, n_frames; @@ -599,8 +590,7 @@ again: spa_log_trace(this->log, NAME " %p: written %u frames", this, total_frames); } - iter_buffer_used = this->buffer_used - iter_buffer_used; - if (written > 0 && iter_buffer_used == 0) { + if (written > 0 && this->buffer_used == this->header_size) { enable_flush(this, false); return 0; } @@ -610,7 +600,6 @@ again: spa_log_trace(this->log, NAME" %p: delay flush", this); if (now_time - this->last_error > SPA_NSEC_PER_SEC / 2) { this->codec->reduce_bitpool(this->codec_data); - update_num_blocks(this); this->last_error = now_time; } enable_flush(this, true); @@ -623,7 +612,6 @@ again: else if (written > 0) { if (now_time - this->last_error > SPA_NSEC_PER_SEC) { this->codec->increase_bitpool(this->codec_data); - update_num_blocks(this); this->last_error = now_time; } if (!spa_list_is_empty(&port->ready)) @@ -746,15 +734,14 @@ static int do_start(struct impl *this) this->seqnum = 0; this->block_size = this->codec->get_block_size(this->codec_data); - update_num_blocks(this); if (this->block_size > sizeof(this->tmp_buffer)) { spa_log_error(this->log, "block-size %d > %zu", this->block_size, sizeof(this->tmp_buffer)); return -EIO; } - spa_log_debug(this->log, NAME " %p: block_size %d num_blocks:%d", this, - this->block_size, this->num_blocks); + spa_log_debug(this->log, NAME " %p: block_size %d", this, + this->block_size); val = this->codec->send_buf_size > 0 /* The kernel doubles the SO_SNDBUF option value set by setsockopt(). */