mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: implement basic CIND/CIEV support in backend-native
Set HFP call indicator based on whether transport is acquired or not.
This commit is contained in:
		
							parent
							
								
									113ab31613
								
							
						
					
					
						commit
						f92b0eee56
					
				
					 1 changed files with 42 additions and 2 deletions
				
			
		| 
						 | 
					@ -137,6 +137,8 @@ struct rfcomm {
 | 
				
			||||||
	unsigned int msbc_supported_by_hfp:1;
 | 
						unsigned int msbc_supported_by_hfp:1;
 | 
				
			||||||
	unsigned int hfp_ag_switching_codec:1;
 | 
						unsigned int hfp_ag_switching_codec:1;
 | 
				
			||||||
	unsigned int hfp_ag_initial_codec_setup:2;
 | 
						unsigned int hfp_ag_initial_codec_setup:2;
 | 
				
			||||||
 | 
						unsigned int cind_call_active:1;
 | 
				
			||||||
 | 
						unsigned int cind_call_notify:1;
 | 
				
			||||||
	enum hfp_hf_state hf_state;
 | 
						enum hfp_hf_state hf_state;
 | 
				
			||||||
	enum hsp_hs_state hs_state;
 | 
						enum hsp_hs_state hs_state;
 | 
				
			||||||
	unsigned int codec;
 | 
						unsigned int codec;
 | 
				
			||||||
| 
						 | 
					@ -676,6 +678,22 @@ static void process_hfp_hf_indicator(struct rfcomm *rfcomm, unsigned int indicat
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rfcomm_hfp_ag_set_cind(struct rfcomm *rfcomm, bool call_active)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (rfcomm->profile != SPA_BT_PROFILE_HFP_HF)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (call_active == rfcomm->cind_call_active)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rfcomm->cind_call_active = call_active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rfcomm->cind_call_notify)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rfcomm_send_reply(rfcomm, "+CIEV: 2,%d", rfcomm->cind_call_active);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
					static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -762,12 +780,20 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))");
 | 
							rfcomm_send_reply(rfcomm, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))");
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
	} else if (spa_strstartswith(buf, "AT+CIND?")) {
 | 
						} else if (spa_strstartswith(buf, "AT+CIND?")) {
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "+CIND: 0,0,0,0");
 | 
							rfcomm_send_reply(rfcomm, "+CIND: 0,%d,0,0", rfcomm->cind_call_active);
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
	} else if (spa_strstartswith(buf, "AT+CMER")) {
 | 
						} else if (spa_strstartswith(buf, "AT+CMER")) {
 | 
				
			||||||
 | 
							int mode, keyp, disp, ind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rfcomm->slc_configured = true;
 | 
							rfcomm->slc_configured = true;
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rfcomm->cind_call_active = false;
 | 
				
			||||||
 | 
							if (sscanf(buf, "AT+CMER= %d , %d , %d , %d", &mode, &keyp, &disp, &ind) == 4)
 | 
				
			||||||
 | 
								rfcomm->cind_call_notify = ind ? true : false;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								rfcomm->cind_call_notify = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* switch codec to mSBC by sending unsolicited +BCS message */
 | 
							/* switch codec to mSBC by sending unsolicited +BCS message */
 | 
				
			||||||
		if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
 | 
							if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
 | 
				
			||||||
			spa_log_debug(backend->log, "RFCOMM initial codec setup");
 | 
								spa_log_debug(backend->log, "RFCOMM initial codec setup");
 | 
				
			||||||
| 
						 | 
					@ -785,7 +811,6 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
				
			||||||
				rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
 | 
									rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	} else if (!rfcomm->slc_configured) {
 | 
						} else if (!rfcomm->slc_configured) {
 | 
				
			||||||
		spa_log_warn(backend->log, "RFCOMM receive command before SLC completed: %s", buf);
 | 
							spa_log_warn(backend->log, "RFCOMM receive command before SLC completed: %s", buf);
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "ERROR");
 | 
							rfcomm_send_reply(rfcomm, "ERROR");
 | 
				
			||||||
| 
						 | 
					@ -829,6 +854,11 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
		if (was_switching_codec)
 | 
							if (was_switching_codec)
 | 
				
			||||||
			spa_bt_device_emit_codec_switched(rfcomm->device, 0);
 | 
								spa_bt_device_emit_codec_switched(rfcomm->device, 0);
 | 
				
			||||||
 | 
						} else if (spa_strstartswith(buf, "AT+BIA=")) {
 | 
				
			||||||
 | 
							/* We only support 'call' indicator, which HFP 4.35.1 defines as
 | 
				
			||||||
 | 
							   always active (assuming CMER enabled it), so we don't need to
 | 
				
			||||||
 | 
							   parse anything here. */
 | 
				
			||||||
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
	} else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) {
 | 
						} else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) {
 | 
				
			||||||
		if (gain <= SPA_BT_VOLUME_HS_MAX) {
 | 
							if (gain <= SPA_BT_VOLUME_HS_MAX) {
 | 
				
			||||||
			if (!rfcomm->broken_mic_hw_volume)
 | 
								if (!rfcomm->broken_mic_hw_volume)
 | 
				
			||||||
| 
						 | 
					@ -1172,12 +1202,17 @@ fail_close:
 | 
				
			||||||
static int sco_acquire_cb(void *data, bool optional)
 | 
					static int sco_acquire_cb(void *data, bool optional)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct spa_bt_transport *t = data;
 | 
						struct spa_bt_transport *t = data;
 | 
				
			||||||
 | 
						struct transport_data *td = t->user_data;
 | 
				
			||||||
	struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
 | 
						struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
 | 
				
			||||||
	int sock;
 | 
						int sock;
 | 
				
			||||||
	socklen_t len;
 | 
						socklen_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_debug(backend->log, "transport %p: enter sco_acquire_cb", t);
 | 
						spa_log_debug(backend->log, "transport %p: enter sco_acquire_cb", t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
 | 
				
			||||||
 | 
						rfcomm_hfp_ag_set_cind(td->rfcomm, true);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (optional || t->fd > 0)
 | 
						if (optional || t->fd > 0)
 | 
				
			||||||
		sock = t->fd;
 | 
							sock = t->fd;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -1217,10 +1252,15 @@ fail:
 | 
				
			||||||
static int sco_release_cb(void *data)
 | 
					static int sco_release_cb(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct spa_bt_transport *t = data;
 | 
						struct spa_bt_transport *t = data;
 | 
				
			||||||
 | 
						struct transport_data *td = t->user_data;
 | 
				
			||||||
	struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
 | 
						struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(backend->log, "Transport %s released", t->path);
 | 
						spa_log_info(backend->log, "Transport %s released", t->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
 | 
				
			||||||
 | 
						rfcomm_hfp_ag_set_cind(td->rfcomm, false);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (t->sco_io) {
 | 
						if (t->sco_io) {
 | 
				
			||||||
		spa_bt_sco_io_destroy(t->sco_io);
 | 
							spa_bt_sco_io_destroy(t->sco_io);
 | 
				
			||||||
		t->sco_io = NULL;
 | 
							t->sco_io = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue