mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: lc3: pick qos values from BAP spec tables
Don't believe QoS values recommended by the device, which may be suboptimal. Instead, pick the values from the BAP v1.0.1 Table 5.2. Link: https://github.com/bluez/bluez/issues/713
This commit is contained in:
		
							parent
							
								
									08819e3d17
								
							
						
					
					
						commit
						cde8f9261c
					
				
					 1 changed files with 139 additions and 102 deletions
				
			
		| 
						 | 
				
			
			@ -48,6 +48,17 @@ struct pac_data {
 | 
			
		|||
	bool duplex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct bap_qos {
 | 
			
		||||
	uint8_t rate;
 | 
			
		||||
	uint8_t frame_duration;
 | 
			
		||||
	bool framing;
 | 
			
		||||
	uint16_t framelen;
 | 
			
		||||
	uint8_t retransmission;
 | 
			
		||||
	uint16_t latency;
 | 
			
		||||
	uint32_t delay;
 | 
			
		||||
	unsigned int priority;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint8_t rate;
 | 
			
		||||
	uint8_t frame_duration;
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +103,73 @@ static const struct {
 | 
			
		|||
	{ BAP_CHANNEL_RS,   SPA_AUDIO_CHANNEL_SR }, /* is it the right mapping? */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define BAP_QOS(rate_, duration_, framing_, framelen_, rtn_, latency_, delay_, priority_) \
 | 
			
		||||
	((struct bap_qos){ .rate = (rate_), .frame_duration = (duration_), .framing = (framing_), \
 | 
			
		||||
			 .framelen = (framelen_), .retransmission = (rtn_), .latency = (latency_),	\
 | 
			
		||||
			 .delay = (delay_), .priority = (priority_) })
 | 
			
		||||
 | 
			
		||||
static const struct bap_qos bap_qos_configs[] = {
 | 
			
		||||
	/* Priority: low-latency > high-reliability, 7.5ms > 10ms,
 | 
			
		||||
	 * bigger frequency and sdu better */
 | 
			
		||||
 | 
			
		||||
	/* BAP v1.0.1 Table 5.2; low-latency */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_8KHZ,  LC3_CONFIG_DURATION_7_5, false,  26, 2,  8, 40000, 30), /* 8_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_8KHZ,  LC3_CONFIG_DURATION_10,  false,  30, 2, 10, 40000, 20), /* 8_2_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false,  30, 2,  8, 40000, 31), /* 16_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10,  false,  40, 2, 10, 40000, 21), /* 16_2_1 (mandatory) */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false,  45, 2,  8, 40000, 32), /* 24_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10,  false,  60, 2, 10, 40000, 22), /* 24_2_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false,  60, 2,  8, 40000, 33), /* 32_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10,  false,  80, 2, 10, 40000, 23), /* 32_2_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5,  true,  97, 5, 24, 40000, 34), /* 441_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10,   true, 130, 5, 31, 40000, 24), /* 441_2_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false,  75, 5, 15, 40000, 35), /* 48_1_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 100, 5, 20, 40000, 25), /* 48_2_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false,  90, 5, 15, 40000, 36), /* 48_3_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 120, 5, 20, 40000, 26), /* 48_4_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 5, 15, 40000, 37), /* 48_5_1 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 155, 5, 20, 40000, 27), /* 48_6_1 */
 | 
			
		||||
 | 
			
		||||
	/* BAP v1.0.1 Table 5.2; high-reliability */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_8KHZ,  LC3_CONFIG_DURATION_7_5, false,  26, 13,  75, 40000, 10), /* 8_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_8KHZ,  LC3_CONFIG_DURATION_10,  false,  30, 13,  95, 40000,  0), /* 8_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false,  30, 13,  75, 40000, 11), /* 16_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10,  false,  40, 13,  95, 40000,  1), /* 16_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false,  45, 13,  75, 40000, 12), /* 24_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10,  false,  60, 13,  95, 40000,  2), /* 24_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false,  60, 13,  75, 40000, 13), /* 32_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10,  false,  80, 13,  95, 40000,  3), /* 32_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5,  true,  97, 13,  80, 40000, 14), /* 441_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10,   true, 130, 13,  85, 40000,  4), /* 441_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false,  75, 13,  75, 40000, 15), /* 48_1_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 100, 13,  95, 40000,  5), /* 48_2_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false,  90, 13,  75, 40000, 16), /* 48_3_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 120, 13, 100, 40000,  6), /* 48_4_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13,  75, 40000, 17), /* 48_5_2 */
 | 
			
		||||
	BAP_QOS(LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10,  false, 155, 13, 100, 40000,  7), /* 48_6_2 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned int get_rate_mask(uint8_t rate) {
 | 
			
		||||
	switch (rate) {
 | 
			
		||||
	case LC3_CONFIG_FREQ_8KHZ: return LC3_FREQ_8KHZ;
 | 
			
		||||
	case LC3_CONFIG_FREQ_16KHZ: return LC3_FREQ_16KHZ;
 | 
			
		||||
	case LC3_CONFIG_FREQ_24KHZ: return LC3_FREQ_24KHZ;
 | 
			
		||||
	case LC3_CONFIG_FREQ_32KHZ: return LC3_FREQ_32KHZ;
 | 
			
		||||
	case LC3_CONFIG_FREQ_44KHZ: return LC3_FREQ_44KHZ;
 | 
			
		||||
	case LC3_CONFIG_FREQ_48KHZ: return LC3_FREQ_48KHZ;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int get_duration_mask(uint8_t rate) {
 | 
			
		||||
	switch (rate) {
 | 
			
		||||
	case LC3_CONFIG_DURATION_7_5: return LC3_DUR_7_5;
 | 
			
		||||
	case LC3_CONFIG_DURATION_10: return LC3_DUR_10;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct ltv *ltv = (struct ltv *)dest;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,6 +294,30 @@ static bool supports_channel_count(uint8_t mask, uint8_t count)
 | 
			
		|||
	return mask & (1u << (count - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct bap_qos *select_bap_qos(unsigned int rate_mask, unsigned int duration_mask, uint16_t framelen_min, uint16_t framelen_max)
 | 
			
		||||
{
 | 
			
		||||
	const struct bap_qos *best = NULL;
 | 
			
		||||
	unsigned int best_priority = 0;
 | 
			
		||||
 | 
			
		||||
	SPA_FOR_EACH_ELEMENT_VAR(bap_qos_configs, c) {
 | 
			
		||||
		if (c->priority < best_priority)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (!(get_rate_mask(c->rate) & rate_mask))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (!(get_duration_mask(c->frame_duration) & duration_mask))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (c->framing)
 | 
			
		||||
			continue;  /* XXX: framing not supported */
 | 
			
		||||
		if (c->framelen < framelen_min || c->framelen > framelen_max)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		best = c;
 | 
			
		||||
		best_priority = c->priority;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return best;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int select_channels(uint8_t channel_counts, uint32_t locations, uint32_t channel_allocation,
 | 
			
		||||
		uint32_t *allocation)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -280,6 +382,9 @@ static bool select_config(bap_lc3_t *conf, const struct pac_data *pac,	struct sp
 | 
			
		|||
	int max_frames = -1;
 | 
			
		||||
	uint8_t channel_counts = LC3_CHAN_1; /* Default: 1 channel (BAP v1.0.1 Sec 4.3.1) */
 | 
			
		||||
	uint8_t max_channels = 0;
 | 
			
		||||
	uint8_t duration_mask = 0;
 | 
			
		||||
	uint16_t rate_mask = 0;
 | 
			
		||||
	const struct bap_qos *bap_qos = NULL;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	if (!data_size)
 | 
			
		||||
| 
						 | 
				
			
			@ -289,8 +394,6 @@ static bool select_config(bap_lc3_t *conf, const struct pac_data *pac,	struct sp
 | 
			
		|||
	conf->sink = pac->sink;
 | 
			
		||||
	conf->duplex = pac->duplex;
 | 
			
		||||
 | 
			
		||||
	conf->frame_duration = 0xFF;
 | 
			
		||||
 | 
			
		||||
	/* XXX: we always use one frame block */
 | 
			
		||||
	conf->n_blks = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -305,43 +408,15 @@ static bool select_config(bap_lc3_t *conf, const struct pac_data *pac,	struct sp
 | 
			
		|||
		switch (ltv->type) {
 | 
			
		||||
		case LC3_TYPE_FREQ:
 | 
			
		||||
			spa_return_val_if_fail(ltv->len == 3, false);
 | 
			
		||||
			{
 | 
			
		||||
				uint16_t rate = ltv->value[0] + (ltv->value[1] << 8);
 | 
			
		||||
				if (rate & LC3_FREQ_48KHZ)
 | 
			
		||||
					conf->rate = LC3_CONFIG_FREQ_48KHZ;
 | 
			
		||||
				else if (rate & LC3_FREQ_32KHZ)
 | 
			
		||||
					conf->rate = LC3_CONFIG_FREQ_32KHZ;
 | 
			
		||||
				else if (rate & LC3_FREQ_24KHZ)
 | 
			
		||||
					conf->rate = LC3_CONFIG_FREQ_24KHZ;
 | 
			
		||||
				else if (rate & LC3_FREQ_16KHZ)
 | 
			
		||||
					conf->rate = LC3_CONFIG_FREQ_16KHZ;
 | 
			
		||||
				else if (rate & LC3_FREQ_8KHZ)
 | 
			
		||||
					conf->rate = LC3_CONFIG_FREQ_8KHZ;
 | 
			
		||||
				else {
 | 
			
		||||
					spa_debugc(debug_ctx, "unsupported rate: 0x%04x", rate);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			rate_mask = ltv->value[0] + (ltv->value[1] << 8);
 | 
			
		||||
			break;
 | 
			
		||||
		case LC3_TYPE_DUR:
 | 
			
		||||
			spa_return_val_if_fail(ltv->len == 2, false);
 | 
			
		||||
			{
 | 
			
		||||
				uint8_t duration = ltv->value[0];
 | 
			
		||||
				if (duration & LC3_DUR_7_5)
 | 
			
		||||
					conf->frame_duration = LC3_CONFIG_DURATION_7_5;
 | 
			
		||||
				else if (duration & LC3_DUR_10)
 | 
			
		||||
					conf->frame_duration = LC3_CONFIG_DURATION_10;
 | 
			
		||||
				else {
 | 
			
		||||
					spa_debugc(debug_ctx, "unsupported duration: 0x%02x", duration);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			duration_mask = ltv->value[0];
 | 
			
		||||
			break;
 | 
			
		||||
		case LC3_TYPE_CHAN:
 | 
			
		||||
			spa_return_val_if_fail(ltv->len == 2, false);
 | 
			
		||||
			{
 | 
			
		||||
				channel_counts = ltv->value[0];
 | 
			
		||||
			}
 | 
			
		||||
			channel_counts = ltv->value[0];
 | 
			
		||||
			break;
 | 
			
		||||
		case LC3_TYPE_FRAMELEN:
 | 
			
		||||
			spa_return_val_if_fail(ltv->len == 5, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -390,52 +465,20 @@ static bool select_config(bap_lc3_t *conf, const struct pac_data *pac,	struct sp
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (conf->frame_duration == 0xFF || !conf->rate) {
 | 
			
		||||
		spa_debugc(debug_ctx, "no frame duration or rate");
 | 
			
		||||
	/*
 | 
			
		||||
	 * Select supported rate + frame length combination
 | 
			
		||||
	 */
 | 
			
		||||
	bap_qos = select_bap_qos(rate_mask, duration_mask, framelen_min, framelen_max);
 | 
			
		||||
 | 
			
		||||
	if (!bap_qos) {
 | 
			
		||||
		spa_debugc(debug_ctx, "no compatible configuration found, rate:0x%08x, duration:0x%08x frame:%u-%u",
 | 
			
		||||
				rate_mask, duration_mask, framelen_min, framelen_max);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* BAP v1.0.1 Table 5.2; high-reliability */
 | 
			
		||||
	switch (conf->rate) {
 | 
			
		||||
	case LC3_CONFIG_FREQ_48KHZ:
 | 
			
		||||
		if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
 | 
			
		||||
			conf->framelen = 117;	/* 48_5_2 */
 | 
			
		||||
		else
 | 
			
		||||
			conf->framelen = 120;	/* 48_4_2 */
 | 
			
		||||
		break;
 | 
			
		||||
	case LC3_CONFIG_FREQ_32KHZ:
 | 
			
		||||
		if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
 | 
			
		||||
			conf->framelen = 60;    /* 32_1_2 */
 | 
			
		||||
		else
 | 
			
		||||
			conf->framelen = 80;    /* 32_2_2 */
 | 
			
		||||
		break;
 | 
			
		||||
	case LC3_CONFIG_FREQ_24KHZ:
 | 
			
		||||
		if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
 | 
			
		||||
			conf->framelen = 45;	/* 24_1_2 */
 | 
			
		||||
		else
 | 
			
		||||
			conf->framelen = 60;	/* 24_2_2 */
 | 
			
		||||
		break;
 | 
			
		||||
	case LC3_CONFIG_FREQ_16KHZ:
 | 
			
		||||
		if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
 | 
			
		||||
			conf->framelen = 30;	/* 16_1_2 */
 | 
			
		||||
		else
 | 
			
		||||
			conf->framelen = 40;	/* 16_2_2 */
 | 
			
		||||
		break;
 | 
			
		||||
	case LC3_CONFIG_FREQ_8KHZ:
 | 
			
		||||
		if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
 | 
			
		||||
			conf->framelen = 26;	/* 8_1_2 */
 | 
			
		||||
		else
 | 
			
		||||
			conf->framelen = 30;	/* 8_2_2 */
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		spa_debugc(debug_ctx, "invalid rate");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (conf->framelen < framelen_min || conf->framelen > framelen_max) {
 | 
			
		||||
		spa_debugc(debug_ctx, "invalid framelen: %u %u", framelen_min, framelen_max);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	conf->rate = bap_qos->rate;
 | 
			
		||||
	conf->frame_duration = bap_qos->frame_duration;
 | 
			
		||||
	conf->framelen = bap_qos->framelen;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -790,6 +833,7 @@ static int codec_get_qos(const struct media_codec *codec,
 | 
			
		|||
		const struct bap_endpoint_qos *endpoint_qos,
 | 
			
		||||
		struct bap_codec_qos *qos)
 | 
			
		||||
{
 | 
			
		||||
	const struct bap_qos *bap_qos;
 | 
			
		||||
	bap_lc3_t conf;
 | 
			
		||||
 | 
			
		||||
	spa_zero(*qos);
 | 
			
		||||
| 
						 | 
				
			
			@ -797,6 +841,14 @@ static int codec_get_qos(const struct media_codec *codec,
 | 
			
		|||
	if (!parse_conf(&conf, config, config_size))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	bap_qos = select_bap_qos(get_rate_mask(conf.rate), get_duration_mask(conf.frame_duration),
 | 
			
		||||
			conf.framelen, conf.framelen);
 | 
			
		||||
	if (!bap_qos) {
 | 
			
		||||
		/* shouldn't happen: select_config should pick existing one */
 | 
			
		||||
		spa_log_error(log, "no QoS settings found");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qos->framing = false;
 | 
			
		||||
	if (endpoint_qos->phy & 0x2)
 | 
			
		||||
		qos->phy = 0x2;
 | 
			
		||||
| 
						 | 
				
			
			@ -804,42 +856,27 @@ static int codec_get_qos(const struct media_codec *codec,
 | 
			
		|||
		qos->phy = 0x1;
 | 
			
		||||
	else
 | 
			
		||||
		qos->phy = 0x2;
 | 
			
		||||
 | 
			
		||||
	qos->sdu = conf.framelen * conf.n_blks * get_channel_count(conf.channels);
 | 
			
		||||
	qos->interval = (conf.frame_duration == LC3_CONFIG_DURATION_7_5 ? 7500 : 10000);
 | 
			
		||||
	qos->target_latency = BT_ISO_QOS_TARGET_LATENCY_RELIABILITY;
 | 
			
		||||
	qos->target_latency = BT_ISO_QOS_TARGET_LATENCY_BALANCED;
 | 
			
		||||
 | 
			
		||||
	/* Default values from BAP v1.0.1 Table 5.2; high-reliability */
 | 
			
		||||
	qos->delay = 40000U;
 | 
			
		||||
	qos->retransmission = 13;
 | 
			
		||||
 | 
			
		||||
	switch (conf.rate) {
 | 
			
		||||
	case LC3_CONFIG_FREQ_8KHZ:
 | 
			
		||||
	case LC3_CONFIG_FREQ_16KHZ:
 | 
			
		||||
	case LC3_CONFIG_FREQ_24KHZ:
 | 
			
		||||
	case LC3_CONFIG_FREQ_32KHZ:
 | 
			
		||||
		/* F_1_2, F_2_2 */
 | 
			
		||||
		qos->latency = (conf.frame_duration == LC3_CONFIG_DURATION_7_5 ? 75 : 95);
 | 
			
		||||
		break;
 | 
			
		||||
	case LC3_CONFIG_FREQ_48KHZ:
 | 
			
		||||
		/* 48_5_2, 48_4_2 */
 | 
			
		||||
		qos->latency = (conf.frame_duration == LC3_CONFIG_DURATION_7_5 ? 75 : 100);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		qos->latency = 100;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	qos->delay = bap_qos->delay;
 | 
			
		||||
	qos->latency = bap_qos->latency;
 | 
			
		||||
	qos->retransmission = bap_qos->retransmission;
 | 
			
		||||
 | 
			
		||||
	/* Clamp to ASE values (if known) */
 | 
			
		||||
	if (endpoint_qos->latency >= 0x0005 && endpoint_qos->latency <= 0x0FA0)
 | 
			
		||||
		/* Values outside the range are RFU */
 | 
			
		||||
		qos->latency = endpoint_qos->latency;
 | 
			
		||||
	if (endpoint_qos->retransmission)
 | 
			
		||||
		qos->retransmission = endpoint_qos->retransmission;
 | 
			
		||||
	if (endpoint_qos->delay_min)
 | 
			
		||||
		qos->delay = SPA_MAX(qos->delay, endpoint_qos->delay_min);
 | 
			
		||||
	if (endpoint_qos->delay_max)
 | 
			
		||||
		qos->delay = SPA_MIN(qos->delay, endpoint_qos->delay_max);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * We ignore endpoint suggested latency and RTN. On current devices
 | 
			
		||||
	 * these do not appear to be very useful numbers, so it's better
 | 
			
		||||
	 * to just pick one from the table in the spec.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue