Previous implementation assumes these values are equal, but this doesn't
necessarily have to be so.
- size_t link_mtu;
- size_t block_size;
+ size_t read_link_mtu;
+ size_t read_block_size;
+
+ size_t write_link_mtu;
+ size_t write_block_size;
struct a2dp_info a2dp;
struct hsp_info hsp;
struct a2dp_info a2dp;
struct hsp_info hsp;
pa_log_debug("Bitpool has changed to %u", a2dp->sbc.bitpool);
pa_log_debug("Bitpool has changed to %u", a2dp->sbc.bitpool);
- u->block_size =
- (u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ u->read_block_size =
+ (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ / a2dp->frame_length * a2dp->codesize;
+
+ u->write_block_size =
+ (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
/ a2dp->frame_length * a2dp->codesize;
/ a2dp->frame_length * a2dp->codesize;
- pa_sink_set_max_request_within_thread(u->sink, u->block_size);
+ pa_sink_set_max_request_within_thread(u->sink, u->write_block_size);
pa_sink_set_fixed_latency_within_thread(u->sink,
pa_sink_set_fixed_latency_within_thread(u->sink,
- FIXED_LATENCY_PLAYBACK_A2DP + pa_bytes_to_usec(u->block_size, &u->sample_spec));
+ FIXED_LATENCY_PLAYBACK_A2DP + pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
}
/* from IO thread, except in SCO over PCM */
}
/* from IO thread, except in SCO over PCM */
- /* FIXME: Handle in/out MTU properly when unix socket is not longer supported */
- u->stream_fd = pa_bluetooth_transport_acquire(t, accesstype, NULL, &u->link_mtu);
+ u->stream_fd = pa_bluetooth_transport_acquire(t, accesstype, &u->read_link_mtu, &u->write_link_mtu);
if (u->stream_fd < 0)
return -1;
if (u->stream_fd < 0)
return -1;
pa_usec_t wi, ri;
ri = pa_smoother_get(u->read_smoother, pa_rtclock_now());
pa_usec_t wi, ri;
ri = pa_smoother_get(u->read_smoother, pa_rtclock_now());
- wi = pa_bytes_to_usec(u->write_index + u->block_size, &u->sample_spec);
+ wi = pa_bytes_to_usec(u->write_index + u->write_block_size, &u->sample_spec);
*((pa_usec_t*) data) = wi > ri ? wi - ri : 0;
} else {
*((pa_usec_t*) data) = wi > ri ? wi - ri : 0;
} else {
/* First, render some data */
if (!u->write_memchunk.memblock)
/* First, render some data */
if (!u->write_memchunk.memblock)
- pa_sink_render_full(u->sink, u->block_size, &u->write_memchunk);
+ pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
- pa_assert(u->write_memchunk.length == u->block_size);
+ pa_assert(u->write_memchunk.length == u->write_block_size);
pa_assert(u->source);
pa_assert(u->read_smoother);
pa_assert(u->source);
pa_assert(u->read_smoother);
- memchunk.memblock = pa_memblock_new(u->core->mempool, u->block_size);
+ memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
memchunk.index = memchunk.length = 0;
for (;;) {
memchunk.index = memchunk.length = 0;
for (;;) {
pa_source_post(u->source, &memchunk);
pa_source_post(u->source, &memchunk);
/* Run from IO thread */
static void a2dp_prepare_buffer(struct userdata *u) {
/* Run from IO thread */
static void a2dp_prepare_buffer(struct userdata *u) {
+ size_t min_buffer_size = PA_MAX(u->read_link_mtu, u->write_link_mtu);
+
- if (u->a2dp.buffer_size >= u->link_mtu)
+ if (u->a2dp.buffer_size >= min_buffer_size)
- u->a2dp.buffer_size = 2 * u->link_mtu;
+ u->a2dp.buffer_size = 2 * min_buffer_size;
pa_xfree(u->a2dp.buffer);
u->a2dp.buffer = pa_xmalloc(u->a2dp.buffer_size);
}
pa_xfree(u->a2dp.buffer);
u->a2dp.buffer = pa_xmalloc(u->a2dp.buffer_size);
}
/* First, render some data */
if (!u->write_memchunk.memblock)
/* First, render some data */
if (!u->write_memchunk.memblock)
- pa_sink_render_full(u->sink, u->block_size, &u->write_memchunk);
+ pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
- pa_assert(u->write_memchunk.length == u->block_size);
+ pa_assert(u->write_memchunk.length == u->write_block_size);
pa_assert(u->source);
pa_assert(u->read_smoother);
pa_assert(u->source);
pa_assert(u->read_smoother);
- memchunk.memblock = pa_memblock_new(u->core->mempool, u->block_size);
+ memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
memchunk.index = memchunk.length = 0;
for (;;) {
memchunk.index = memchunk.length = 0;
for (;;) {
pa_source_post(u->source, &memchunk);
pa_source_post(u->source, &memchunk);
static void thread_func(void *userdata) {
struct userdata *u = userdata;
unsigned do_write = 0;
static void thread_func(void *userdata) {
struct userdata *u = userdata;
unsigned do_write = 0;
+ unsigned pending_read_bytes = 0;
pa_bool_t writable = FALSE;
pa_assert(u);
pa_bool_t writable = FALSE;
pa_assert(u);
goto fail;
/* We just read something, so we are supposed to write something, too */
goto fail;
/* We just read something, so we are supposed to write something, too */
+ pending_read_bytes += n_read;
+ do_write += pending_read_bytes / u->write_block_size;
+ pending_read_bytes = pending_read_bytes % u->write_block_size;
+ pending_read_bytes = 0;
u->sink->userdata = u;
u->sink->parent.process_msg = sink_process_msg;
u->sink->userdata = u;
u->sink->parent.process_msg = sink_process_msg;
- pa_sink_set_max_request(u->sink, u->block_size);
+ pa_sink_set_max_request(u->sink, u->write_block_size);
pa_sink_set_fixed_latency(u->sink,
(u->profile == PROFILE_A2DP ? FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
pa_sink_set_fixed_latency(u->sink,
(u->profile == PROFILE_A2DP ? FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
- pa_bytes_to_usec(u->block_size, &u->sample_spec));
+ pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
}
if (u->profile == PROFILE_HSP) {
}
if (u->profile == PROFILE_HSP) {
pa_source_set_fixed_latency(u->source,
(u->profile == PROFILE_A2DP_SOURCE ? FIXED_LATENCY_RECORD_A2DP : FIXED_LATENCY_RECORD_HSP) +
pa_source_set_fixed_latency(u->source,
(u->profile == PROFILE_A2DP_SOURCE ? FIXED_LATENCY_RECORD_A2DP : FIXED_LATENCY_RECORD_HSP) +
- pa_bytes_to_usec(u->block_size, &u->sample_spec));
+ pa_bytes_to_usec(u->read_block_size, &u->sample_spec));
}
if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW)) {
}
if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW)) {
a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
- u->block_size =
- (u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ u->read_block_size =
+ (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ / a2dp->frame_length * a2dp->codesize;
+
+ u->write_block_size =
+ (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
/ a2dp->frame_length * a2dp->codesize;
pa_log_info("SBC parameters:\n\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
/ a2dp->frame_length * a2dp->codesize;
pa_log_info("SBC parameters:\n\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
static int bt_transport_config(struct userdata *u) {
if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) {
static int bt_transport_config(struct userdata *u) {
if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) {
- u->block_size = u->link_mtu;
+ u->read_block_size = u->read_link_mtu;
+ u->write_block_size = u->write_link_mtu;
u->sample_spec.format = PA_SAMPLE_S16LE;
u->sample_spec.channels = 1;
u->sample_spec.rate = 8000;
u->sample_spec.format = PA_SAMPLE_S16LE;
u->sample_spec.channels = 1;
u->sample_spec.rate = 8000;