mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: telephony: Add CMEE support
This commit is contained in:
		
							parent
							
								
									7e5cd195ac
								
							
						
					
					
						commit
						b7c00e2f24
					
				
					 3 changed files with 204 additions and 82 deletions
				
			
		| 
						 | 
					@ -131,6 +131,7 @@ enum hfp_hf_state {
 | 
				
			||||||
	hfp_hf_chld,
 | 
						hfp_hf_chld,
 | 
				
			||||||
	hfp_hf_clip,
 | 
						hfp_hf_clip,
 | 
				
			||||||
	hfp_hf_ccwa,
 | 
						hfp_hf_ccwa,
 | 
				
			||||||
 | 
						hfp_hf_cmee,
 | 
				
			||||||
	hfp_hf_slc1,
 | 
						hfp_hf_slc1,
 | 
				
			||||||
	hfp_hf_slc2,
 | 
						hfp_hf_slc2,
 | 
				
			||||||
	hfp_hf_vgs,
 | 
						hfp_hf_vgs,
 | 
				
			||||||
| 
						 | 
					@ -183,6 +184,7 @@ struct rfcomm {
 | 
				
			||||||
	unsigned int clip_notify:1;
 | 
						unsigned int clip_notify:1;
 | 
				
			||||||
	unsigned int hfp_hf_3way:1;
 | 
						unsigned int hfp_hf_3way:1;
 | 
				
			||||||
	unsigned int hfp_hf_clcc:1;
 | 
						unsigned int hfp_hf_clcc:1;
 | 
				
			||||||
 | 
						unsigned int hfp_hf_cme:1;
 | 
				
			||||||
	unsigned int hfp_hf_in_progress:1;
 | 
						unsigned int hfp_hf_in_progress:1;
 | 
				
			||||||
	unsigned int chld_supported:1;
 | 
						unsigned int chld_supported:1;
 | 
				
			||||||
	enum hfp_hf_state hf_state;
 | 
						enum hfp_hf_state hf_state;
 | 
				
			||||||
| 
						 | 
					@ -1313,7 +1315,8 @@ static bool hfp_hf_wait_for_reply(struct rfcomm *rfcomm, char *buf, size_t len)
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				spa_log_debug(backend->log, "RFCOMM event: %s", token);
 | 
									spa_log_debug(backend->log, "RFCOMM event: %s", token);
 | 
				
			||||||
				if (spa_strstartswith(token, "OK") || spa_strstartswith(token, "ERROR")) {
 | 
									if (spa_strstartswith(token, "OK") || spa_strstartswith(token, "ERROR") ||
 | 
				
			||||||
 | 
											spa_strstartswith(token, "+CME ERROR:")) {
 | 
				
			||||||
					spa_log_debug(backend->log, "RFCOMM reply found: %s", token);
 | 
										spa_log_debug(backend->log, "RFCOMM reply found: %s", token);
 | 
				
			||||||
					reply_found = true;
 | 
										reply_found = true;
 | 
				
			||||||
					strncpy(buf, token, len);
 | 
										strncpy(buf, token, len);
 | 
				
			||||||
| 
						 | 
					@ -1328,12 +1331,23 @@ static bool hfp_hf_wait_for_reply(struct rfcomm *rfcomm, char *buf, size_t len)
 | 
				
			||||||
	return reply_found;
 | 
						return reply_found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_answer(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_get_error_from_reply(char *reply, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (spa_strstartswith(reply, "+CME ERROR:")) {
 | 
				
			||||||
 | 
							*cme_error = atoi(reply + strlen("+CME ERROR:"));
 | 
				
			||||||
 | 
							*err = BT_TELEPHONY_ERROR_CME;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void hfp_hf_answer(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm_call_data *call_data = data;
 | 
						struct rfcomm_call_data *call_data = data;
 | 
				
			||||||
	struct rfcomm *rfcomm = call_data->rfcomm;
 | 
						struct rfcomm *rfcomm = call_data->rfcomm;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (call_data->call->state != CALL_STATE_INCOMING) {
 | 
						if (call_data->call->state != CALL_STATE_INCOMING) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_INVALID_STATE;
 | 
							*err = BT_TELEPHONY_ERROR_INVALID_STATE;
 | 
				
			||||||
| 
						 | 
					@ -1341,21 +1355,26 @@ static void hfp_hf_answer(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "ATA");
 | 
						rfcomm_send_cmd(rfcomm, "ATA");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to answer call");
 | 
							spa_log_info(backend->log, "Failed to answer call");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_hangup(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_hangup(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm_call_data *call_data = data;
 | 
						struct rfcomm_call_data *call_data = data;
 | 
				
			||||||
	struct rfcomm *rfcomm = call_data->rfcomm;
 | 
						struct rfcomm *rfcomm = call_data->rfcomm;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (call_data->call->state) {
 | 
						switch (call_data->call->state) {
 | 
				
			||||||
	case CALL_STATE_ACTIVE:
 | 
						case CALL_STATE_ACTIVE:
 | 
				
			||||||
| 
						 | 
					@ -1373,9 +1392,13 @@ static void hfp_hf_hangup(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to hangup call");
 | 
							spa_log_info(backend->log, "Failed to hangup call");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1409,25 +1432,30 @@ static struct spa_bt_telephony_call *hfp_hf_add_call(struct rfcomm *rfcomm, stru
 | 
				
			||||||
	return call;
 | 
						return call;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_dial(void *data, const char *number, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_dial(void *data, const char *number, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(backend->log, "Dialing: \"%s\"", number);
 | 
						spa_log_info(backend->log, "Dialing: \"%s\"", number);
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "ATD%s;", number);
 | 
						rfcomm_send_cmd(rfcomm, "ATD%s;", number);
 | 
				
			||||||
	if (hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) && spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (res && spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		struct spa_bt_telephony_call *call;
 | 
							struct spa_bt_telephony_call *call;
 | 
				
			||||||
		call = hfp_hf_add_call(rfcomm, rfcomm->telephony_ag, CALL_STATE_DIALING, number);
 | 
							call = hfp_hf_add_call(rfcomm, rfcomm->telephony_ag, CALL_STATE_DIALING, number);
 | 
				
			||||||
		*err = call ? BT_TELEPHONY_ERROR_NONE : BT_TELEPHONY_ERROR_FAILED;
 | 
							*err = call ? BT_TELEPHONY_ERROR_NONE : BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to dial: \"%s\"", number);
 | 
							spa_log_info(backend->log, "Failed to dial: \"%s\"", number);
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1435,6 +1463,7 @@ static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_held = false;
 | 
						bool found_held = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rfcomm->chld_supported) {
 | 
						if (!rfcomm->chld_supported) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
							*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
				
			||||||
| 
						 | 
					@ -1462,9 +1491,13 @@ static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+CHLD=2");
 | 
						rfcomm_send_cmd(rfcomm, "AT+CHLD=2");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to swap calls");
 | 
							spa_log_info(backend->log, "Failed to swap calls");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1472,7 +1505,7 @@ static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1480,6 +1513,7 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_waiting = false;
 | 
						bool found_waiting = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rfcomm->chld_supported) {
 | 
						if (!rfcomm->chld_supported) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
							*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
				
			||||||
| 
						 | 
					@ -1503,9 +1537,13 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+CHLD=1");
 | 
						rfcomm_send_cmd(rfcomm, "AT+CHLD=1");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to release and answer calls");
 | 
							spa_log_info(backend->log, "Failed to release and answer calls");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1513,7 +1551,7 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1521,6 +1559,7 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_held = false;
 | 
						bool found_held = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rfcomm->chld_supported) {
 | 
						if (!rfcomm->chld_supported) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
							*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
				
			||||||
| 
						 | 
					@ -1548,9 +1587,13 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+CHLD=1");
 | 
						rfcomm_send_cmd(rfcomm, "AT+CHLD=1");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to release and swap calls");
 | 
							spa_log_info(backend->log, "Failed to release and swap calls");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1558,7 +1601,7 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1566,6 +1609,7 @@ static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_waiting = false;
 | 
						bool found_waiting = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rfcomm->chld_supported) {
 | 
						if (!rfcomm->chld_supported) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
							*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
				
			||||||
| 
						 | 
					@ -1589,9 +1633,13 @@ static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+CHLD=2");
 | 
						rfcomm_send_cmd(rfcomm, "AT+CHLD=2");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to hold and answer calls");
 | 
							spa_log_info(backend->log, "Failed to hold and answer calls");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1599,7 +1647,7 @@ static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_hangup_all(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_hangup_all(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1607,6 +1655,7 @@ static void hfp_hf_hangup_all(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_held = false;
 | 
						bool found_held = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
 | 
						spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
 | 
				
			||||||
		switch (call->state) {
 | 
							switch (call->state) {
 | 
				
			||||||
| 
						 | 
					@ -1630,23 +1679,31 @@ static void hfp_hf_hangup_all(void *data, enum spa_bt_telephony_error *err)
 | 
				
			||||||
	/* Hangup held calls */
 | 
						/* Hangup held calls */
 | 
				
			||||||
	if (found_held) {
 | 
						if (found_held) {
 | 
				
			||||||
		rfcomm_send_cmd(rfcomm, "AT+CHLD=0");
 | 
							rfcomm_send_cmd(rfcomm, "AT+CHLD=0");
 | 
				
			||||||
		if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
							res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
							if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
			spa_log_info(backend->log, "Failed to hangup held calls");
 | 
								spa_log_info(backend->log, "Failed to hangup held calls");
 | 
				
			||||||
			*err = BT_TELEPHONY_ERROR_FAILED;
 | 
								if (res)
 | 
				
			||||||
 | 
									hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Hangup active calls */
 | 
						/* Hangup active calls */
 | 
				
			||||||
	if (found_active) {
 | 
						if (found_active) {
 | 
				
			||||||
		rfcomm_send_cmd(rfcomm, "AT+CHUP");
 | 
							rfcomm_send_cmd(rfcomm, "AT+CHUP");
 | 
				
			||||||
		if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
							res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
							if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
			spa_log_info(backend->log, "Failed to hangup active calls");
 | 
								spa_log_info(backend->log, "Failed to hangup active calls");
 | 
				
			||||||
			*err = BT_TELEPHONY_ERROR_FAILED;
 | 
								if (res)
 | 
				
			||||||
 | 
									hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
| 
						 | 
					@ -1654,6 +1711,7 @@ static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *er
 | 
				
			||||||
	bool found_active = false;
 | 
						bool found_active = false;
 | 
				
			||||||
	bool found_held = false;
 | 
						bool found_held = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rfcomm->chld_supported) {
 | 
						if (!rfcomm->chld_supported) {
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
							*err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
 | 
				
			||||||
| 
						 | 
					@ -1681,9 +1739,13 @@ static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *er
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+CHLD=3");
 | 
						rfcomm_send_cmd(rfcomm, "AT+CHLD=3");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to create multiparty");
 | 
							spa_log_info(backend->log, "Failed to create multiparty");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1691,13 +1753,14 @@ static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *er
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_send_tones(void *data, const char *tones, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_send_tones(void *data, const char *tones, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
	struct spa_bt_telephony_call *call;
 | 
						struct spa_bt_telephony_call *call;
 | 
				
			||||||
	bool found = false;
 | 
						bool found = false;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
 | 
						spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
 | 
				
			||||||
		if (call->state == CALL_STATE_ACTIVE) {
 | 
							if (call->state == CALL_STATE_ACTIVE) {
 | 
				
			||||||
| 
						 | 
					@ -1713,20 +1776,25 @@ static void hfp_hf_send_tones(void *data, const char *tones, enum spa_bt_telepho
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+VTS=%s", tones);
 | 
						rfcomm_send_cmd(rfcomm, "AT+VTS=%s", tones);
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to send tones: %s", tones);
 | 
							spa_log_info(backend->log, "Failed to send tones: %s", tones);
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*err = BT_TELEPHONY_ERROR_NONE;
 | 
						*err = BT_TELEPHONY_ERROR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hfp_hf_transport_activate(void *data, enum spa_bt_telephony_error *err)
 | 
					static void hfp_hf_transport_activate(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rfcomm *rfcomm = data;
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
	struct impl *backend = rfcomm->backend;
 | 
						struct impl *backend = rfcomm->backend;
 | 
				
			||||||
	char reply[20];
 | 
						char reply[20];
 | 
				
			||||||
 | 
						bool res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_list_is_empty(&rfcomm->telephony_ag->call_list)) {
 | 
						if (spa_list_is_empty(&rfcomm->telephony_ag->call_list)) {
 | 
				
			||||||
		spa_log_debug(backend->log, "no ongoing call");
 | 
							spa_log_debug(backend->log, "no ongoing call");
 | 
				
			||||||
| 
						 | 
					@ -1740,9 +1808,13 @@ static void hfp_hf_transport_activate(void *data, enum spa_bt_telephony_error *e
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rfcomm_send_cmd(rfcomm, "AT+BCC");
 | 
						rfcomm_send_cmd(rfcomm, "AT+BCC");
 | 
				
			||||||
	if (!hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply)) || !spa_strstartswith(reply, "OK")) {
 | 
						res = hfp_hf_wait_for_reply(rfcomm, reply, sizeof(reply));
 | 
				
			||||||
 | 
						if (!res || !spa_strstartswith(reply, "OK")) {
 | 
				
			||||||
		spa_log_info(backend->log, "Failed to send AT+BCC");
 | 
							spa_log_info(backend->log, "Failed to send AT+BCC");
 | 
				
			||||||
		*err = BT_TELEPHONY_ERROR_FAILED;
 | 
							if (res)
 | 
				
			||||||
 | 
								hfp_hf_get_error_from_reply(reply, err, cme_error);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								*err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1774,6 +1846,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
 | 
				
			||||||
			rfcomm->codec_negotiation_supported = true;
 | 
								rfcomm->codec_negotiation_supported = true;
 | 
				
			||||||
		rfcomm->hfp_hf_3way = (features & SPA_BT_HFP_AG_FEATURE_3WAY) != 0;
 | 
							rfcomm->hfp_hf_3way = (features & SPA_BT_HFP_AG_FEATURE_3WAY) != 0;
 | 
				
			||||||
		rfcomm->hfp_hf_clcc = (features & SPA_BT_HFP_AG_FEATURE_ENHANCED_CALL_STATUS) != 0;
 | 
							rfcomm->hfp_hf_clcc = (features & SPA_BT_HFP_AG_FEATURE_ENHANCED_CALL_STATUS) != 0;
 | 
				
			||||||
 | 
							rfcomm->hfp_hf_cme = (features & SPA_BT_HFP_AG_FEATURE_EXTENDED_RES_CODE) != 0;
 | 
				
			||||||
	} else if (sscanf(token, "+BCS:%u", &selected_codec) == 1 && rfcomm->codec_negotiation_supported) {
 | 
						} else if (sscanf(token, "+BCS:%u", &selected_codec) == 1 && rfcomm->codec_negotiation_supported) {
 | 
				
			||||||
		if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC &&
 | 
							if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC &&
 | 
				
			||||||
				selected_codec != HFP_AUDIO_CODEC_LC3_SWB) {
 | 
									selected_codec != HFP_AUDIO_CODEC_LC3_SWB) {
 | 
				
			||||||
| 
						 | 
					@ -2175,6 +2248,13 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			SPA_FALLTHROUGH;
 | 
								SPA_FALLTHROUGH;
 | 
				
			||||||
		case hfp_hf_ccwa:
 | 
							case hfp_hf_ccwa:
 | 
				
			||||||
 | 
								if (rfcomm->hfp_hf_cme) {
 | 
				
			||||||
 | 
									rfcomm_send_cmd(rfcomm, "AT+CMEE=1");
 | 
				
			||||||
 | 
									rfcomm->hf_state = hfp_hf_cmee;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								SPA_FALLTHROUGH;
 | 
				
			||||||
 | 
							case hfp_hf_cmee:
 | 
				
			||||||
			rfcomm->hf_state = hfp_hf_slc1;
 | 
								rfcomm->hf_state = hfp_hf_slc1;
 | 
				
			||||||
			rfcomm->slc_configured = true;
 | 
								rfcomm->slc_configured = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -225,20 +225,20 @@ struct callimpl {
 | 
				
			||||||
	} prev;
 | 
						} prev;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ag_emit(ag,m,v,...) 		spa_callbacks_call(&ag->callbacks, struct spa_bt_telephony_ag_callbacks, m, v, ##__VA_ARGS__)
 | 
					#define ag_emit(ag,m,v,...) 				spa_callbacks_call(&ag->callbacks, struct spa_bt_telephony_ag_callbacks, m, v, ##__VA_ARGS__)
 | 
				
			||||||
#define ag_emit_dial(s,n,e)		ag_emit(s,dial,0,n,e)
 | 
					#define ag_emit_dial(s,n,e,cme)				ag_emit(s,dial,0,n,e,cme)
 | 
				
			||||||
#define ag_emit_swap_calls(s,e)		ag_emit(s,swap_calls,0,e)
 | 
					#define ag_emit_swap_calls(s,e,cme)			ag_emit(s,swap_calls,0,e,cme)
 | 
				
			||||||
#define ag_emit_release_and_answer(s,e)	ag_emit(s,release_and_answer,0,e)
 | 
					#define ag_emit_release_and_answer(s,e,cme)	ag_emit(s,release_and_answer,0,e,cme)
 | 
				
			||||||
#define ag_emit_release_and_swap(s,e)	ag_emit(s,release_and_swap,0,e)
 | 
					#define ag_emit_release_and_swap(s,e,cme)	ag_emit(s,release_and_swap,0,e,cme)
 | 
				
			||||||
#define ag_emit_hold_and_answer(s,e)	ag_emit(s,hold_and_answer,0,e)
 | 
					#define ag_emit_hold_and_answer(s,e,cme)	ag_emit(s,hold_and_answer,0,e,cme)
 | 
				
			||||||
#define ag_emit_hangup_all(s,e)		ag_emit(s,hangup_all,0,e)
 | 
					#define ag_emit_hangup_all(s,e,cme)			ag_emit(s,hangup_all,0,e,cme)
 | 
				
			||||||
#define ag_emit_create_multiparty(s,e)	ag_emit(s,create_multiparty,0,e)
 | 
					#define ag_emit_create_multiparty(s,e,cme)	ag_emit(s,create_multiparty,0,e,cme)
 | 
				
			||||||
#define ag_emit_send_tones(s,t,e)	ag_emit(s,send_tones,0,t,e)
 | 
					#define ag_emit_send_tones(s,t,e,cme)		ag_emit(s,send_tones,0,t,e,cme)
 | 
				
			||||||
#define ag_emit_transport_activate(s,e) ag_emit(s,transport_activate,0,e)
 | 
					#define ag_emit_transport_activate(s,e,cme) ag_emit(s,transport_activate,0,e,cme)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define call_emit(c,m,v,...) 	spa_callbacks_call(&c->callbacks, struct spa_bt_telephony_call_callbacks, m, v, ##__VA_ARGS__)
 | 
					#define call_emit(c,m,v,...) 	spa_callbacks_call(&c->callbacks, struct spa_bt_telephony_call_callbacks, m, v, ##__VA_ARGS__)
 | 
				
			||||||
#define call_emit_answer(s,e)	call_emit(s,answer,0,e)
 | 
					#define call_emit_answer(s,e,cme)	call_emit(s,answer,0,e,cme)
 | 
				
			||||||
#define call_emit_hangup(s,e)	call_emit(s,hangup,0,e)
 | 
					#define call_emit_hangup(s,e,cme)	call_emit(s,hangup,0,e,cme)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dbus_iter_append_ag_interfaces(DBusMessageIter *i, struct spa_bt_telephony_ag *ag);
 | 
					static void dbus_iter_append_ag_interfaces(DBusMessageIter *i, struct spa_bt_telephony_ag *ag);
 | 
				
			||||||
static void dbus_iter_append_call_properties(DBusMessageIter *i, struct spa_bt_telephony_call *call, bool all);
 | 
					static void dbus_iter_append_call_properties(DBusMessageIter *i, struct spa_bt_telephony_call *call, bool all);
 | 
				
			||||||
| 
						 | 
					@ -248,6 +248,7 @@ static void dbus_iter_append_call_properties(DBusMessageIter *i, struct spa_bt_t
 | 
				
			||||||
#define PW_TELEPHONY_ERROR_INVALID_FORMAT "org.pipewire.Telephony.Error.InvalidFormat"
 | 
					#define PW_TELEPHONY_ERROR_INVALID_FORMAT "org.pipewire.Telephony.Error.InvalidFormat"
 | 
				
			||||||
#define PW_TELEPHONY_ERROR_INVALID_STATE "org.pipewire.Telephony.Error.InvalidState"
 | 
					#define PW_TELEPHONY_ERROR_INVALID_STATE "org.pipewire.Telephony.Error.InvalidState"
 | 
				
			||||||
#define PW_TELEPHONY_ERROR_IN_PROGRESS "org.pipewire.Telephony.Error.InProgress"
 | 
					#define PW_TELEPHONY_ERROR_IN_PROGRESS "org.pipewire.Telephony.Error.InProgress"
 | 
				
			||||||
 | 
					#define PW_TELEPHONY_ERROR_CME "org.pipewire.Telephony.Error.CME"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *telephony_error_to_dbus (enum spa_bt_telephony_error err)
 | 
					static const char *telephony_error_to_dbus (enum spa_bt_telephony_error err)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -262,12 +263,14 @@ static const char *telephony_error_to_dbus (enum spa_bt_telephony_error err)
 | 
				
			||||||
		return PW_TELEPHONY_ERROR_INVALID_STATE;
 | 
							return PW_TELEPHONY_ERROR_INVALID_STATE;
 | 
				
			||||||
	case BT_TELEPHONY_ERROR_IN_PROGRESS:
 | 
						case BT_TELEPHONY_ERROR_IN_PROGRESS:
 | 
				
			||||||
		return PW_TELEPHONY_ERROR_IN_PROGRESS;
 | 
							return PW_TELEPHONY_ERROR_IN_PROGRESS;
 | 
				
			||||||
 | 
						case BT_TELEPHONY_ERROR_CME:
 | 
				
			||||||
 | 
							return PW_TELEPHONY_ERROR_CME;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return "";
 | 
							return "";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *telephony_error_to_description (enum spa_bt_telephony_error err)
 | 
					static const char *telephony_error_to_description (enum spa_bt_telephony_error err, uint8_t cme_error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (err) {
 | 
						switch (err) {
 | 
				
			||||||
	case BT_TELEPHONY_ERROR_FAILED:
 | 
						case BT_TELEPHONY_ERROR_FAILED:
 | 
				
			||||||
| 
						 | 
					@ -280,6 +283,33 @@ static const char *telephony_error_to_description (enum spa_bt_telephony_error e
 | 
				
			||||||
		return "The current state does not allow this method call";
 | 
							return "The current state does not allow this method call";
 | 
				
			||||||
	case BT_TELEPHONY_ERROR_IN_PROGRESS:
 | 
						case BT_TELEPHONY_ERROR_IN_PROGRESS:
 | 
				
			||||||
		return "Command already in progress";
 | 
							return "Command already in progress";
 | 
				
			||||||
 | 
						case BT_TELEPHONY_ERROR_CME:
 | 
				
			||||||
 | 
							switch (cme_error) {
 | 
				
			||||||
 | 
							case 0: return "AG failure";
 | 
				
			||||||
 | 
							case 1: return "no connection to phone";
 | 
				
			||||||
 | 
							case 3: return "operation not allowed";
 | 
				
			||||||
 | 
							case 4: return "operation not supported";
 | 
				
			||||||
 | 
							case 5: return "PH-SIM PIN required";
 | 
				
			||||||
 | 
							case 10: return "SIM not inserted";
 | 
				
			||||||
 | 
							case 11: return "SIM PIN required";
 | 
				
			||||||
 | 
							case 12: return "SIM PUK required";
 | 
				
			||||||
 | 
							case 13: return "SIM failure";
 | 
				
			||||||
 | 
							case 14: return "SIM busy";
 | 
				
			||||||
 | 
							case 16: return "incorrect password";
 | 
				
			||||||
 | 
							case 17: return "SIM PIN2 required";
 | 
				
			||||||
 | 
							case 18: return "SIM PUK2 required";
 | 
				
			||||||
 | 
							case 20: return "memory full";
 | 
				
			||||||
 | 
							case 21: return "invalid index";
 | 
				
			||||||
 | 
							case 23: return "memory failure";
 | 
				
			||||||
 | 
							case 24: return "text string too long";
 | 
				
			||||||
 | 
							case 25: return "invalid characters in text string";
 | 
				
			||||||
 | 
							case 26: return "dial string too long";
 | 
				
			||||||
 | 
							case 27: return "invalid characters in dial string";
 | 
				
			||||||
 | 
							case 30: return "no network service";
 | 
				
			||||||
 | 
							case 31: return "network Timeout";
 | 
				
			||||||
 | 
							case 32: return "network not allowed - Emergency calls only";
 | 
				
			||||||
 | 
							default: return "Unknown CME error";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return "";
 | 
							return "";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -816,6 +846,7 @@ static DBusMessage *ag_dial(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *number = NULL;
 | 
						const char *number = NULL;
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
	spa_autoptr(DBusMessage) r = NULL;
 | 
						spa_autoptr(DBusMessage) r = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dbus_message_get_args(m, NULL,
 | 
						if (!dbus_message_get_args(m, NULL,
 | 
				
			||||||
| 
						 | 
					@ -829,7 +860,7 @@ static DBusMessage *ag_dial(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	agimpl->dial_in_progress = true;
 | 
						agimpl->dial_in_progress = true;
 | 
				
			||||||
	if (!ag_emit_dial(agimpl, number, &err)) {
 | 
						if (!ag_emit_dial(agimpl, number, &err, &cme_error)) {
 | 
				
			||||||
		agimpl->dial_in_progress = false;
 | 
							agimpl->dial_in_progress = false;
 | 
				
			||||||
		goto failed;
 | 
							goto failed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -853,79 +884,86 @@ static DBusMessage *ag_dial(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
failed:
 | 
					failed:
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_swap_calls(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_swap_calls(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_swap_calls(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_swap_calls(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_release_and_answer(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_release_and_answer(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_release_and_answer(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_release_and_answer(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_release_and_swap(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_release_and_swap(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_release_and_swap(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_release_and_swap(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_hold_and_answer(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_hold_and_answer(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_hold_and_answer(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_hold_and_answer(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_hangup_all(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_hangup_all(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_hangup_all(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_hangup_all(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_create_multiparty(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_create_multiparty(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_create_multiparty(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_create_multiparty(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_send_tones(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_send_tones(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *tones = NULL;
 | 
						const char *tones = NULL;
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dbus_message_get_args(m, NULL,
 | 
						if (!dbus_message_get_args(m, NULL,
 | 
				
			||||||
				DBUS_TYPE_STRING, &tones,
 | 
									DBUS_TYPE_STRING, &tones,
 | 
				
			||||||
| 
						 | 
					@ -937,23 +975,24 @@ static DBusMessage *ag_send_tones(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
		goto failed;
 | 
							goto failed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_send_tones(agimpl, tones, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_send_tones(agimpl, tones, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
failed:
 | 
					failed:
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *ag_transport_activate(struct agimpl *agimpl, DBusMessage *m)
 | 
					static DBusMessage *ag_transport_activate(struct agimpl *agimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ag_emit_transport_activate(agimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (ag_emit_transport_activate(agimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusHandlerResult ag_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
					static DBusHandlerResult ag_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -1488,23 +1527,25 @@ static DBusMessage *call_properties_set(struct callimpl *callimpl, DBusMessage *
 | 
				
			||||||
static DBusMessage *call_answer(struct callimpl *callimpl, DBusMessage *m)
 | 
					static DBusMessage *call_answer(struct callimpl *callimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (call_emit_answer(callimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (call_emit_answer(callimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusMessage *call_hangup(struct callimpl *callimpl, DBusMessage *m)
 | 
					static DBusMessage *call_hangup(struct callimpl *callimpl, DBusMessage *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
						enum spa_bt_telephony_error err = BT_TELEPHONY_ERROR_FAILED;
 | 
				
			||||||
 | 
						uint8_t cme_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (call_emit_hangup(callimpl, &err) && err == BT_TELEPHONY_ERROR_NONE)
 | 
						if (call_emit_hangup(callimpl, &err, &cme_error) && err == BT_TELEPHONY_ERROR_NONE)
 | 
				
			||||||
		return dbus_message_new_method_return(m);
 | 
							return dbus_message_new_method_return(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
						return dbus_message_new_error(m, telephony_error_to_dbus (err),
 | 
				
			||||||
		telephony_error_to_description (err));
 | 
							telephony_error_to_description (err, cme_error));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusHandlerResult call_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
					static DBusHandlerResult call_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ enum spa_bt_telephony_error {
 | 
				
			||||||
	BT_TELEPHONY_ERROR_INVALID_FORMAT,
 | 
						BT_TELEPHONY_ERROR_INVALID_FORMAT,
 | 
				
			||||||
	BT_TELEPHONY_ERROR_INVALID_STATE,
 | 
						BT_TELEPHONY_ERROR_INVALID_STATE,
 | 
				
			||||||
	BT_TELEPHONY_ERROR_IN_PROGRESS,
 | 
						BT_TELEPHONY_ERROR_IN_PROGRESS,
 | 
				
			||||||
 | 
						BT_TELEPHONY_ERROR_CME,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum spa_bt_telephony_call_state {
 | 
					enum spa_bt_telephony_call_state {
 | 
				
			||||||
| 
						 | 
					@ -65,24 +66,24 @@ struct spa_bt_telephony_ag_callbacks {
 | 
				
			||||||
#define SPA_VERSION_BT_TELEPHONY_AG_CALLBACKS	0
 | 
					#define SPA_VERSION_BT_TELEPHONY_AG_CALLBACKS	0
 | 
				
			||||||
	uint32_t version;
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*dial)(void *data, const char *number, enum spa_bt_telephony_error *err);
 | 
						void (*dial)(void *data, const char *number, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*swap_calls)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*swap_calls)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*release_and_answer)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*release_and_answer)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*release_and_swap)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*release_and_swap)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*hold_and_answer)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*hold_and_answer)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*hangup_all)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*hangup_all)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*create_multiparty)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*create_multiparty)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*send_tones)(void *data, const char *tones, enum spa_bt_telephony_error *err);
 | 
						void (*send_tones)(void *data, const char *tones, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*transport_activate)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*transport_activate)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spa_bt_telephony_call_callbacks {
 | 
					struct spa_bt_telephony_call_callbacks {
 | 
				
			||||||
#define SPA_VERSION_BT_TELEPHONY_CALL_CALLBACKS	0
 | 
					#define SPA_VERSION_BT_TELEPHONY_CALL_CALLBACKS	0
 | 
				
			||||||
	uint32_t version;
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*answer)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*answer)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
	void (*hangup)(void *data, enum spa_bt_telephony_error *err);
 | 
						void (*hangup)(void *data, enum spa_bt_telephony_error *err, uint8_t *cme_error);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spa_bt_telephony *telephony_new(struct spa_log *log, struct spa_dbus *dbus,
 | 
					struct spa_bt_telephony *telephony_new(struct spa_log *log, struct spa_dbus *dbus,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue