⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 headset.c

📁 BlueZ源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	return 0;}static int event_reporting(struct audio_device *dev, const char *buf){	char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */	if (strlen(buf) < 13)		return -EINVAL;	tokens = g_strsplit(&buf[8], ",", 5);	if (g_strv_length(tokens) < 4) {		g_strfreev(tokens);		return -EINVAL;	}	ag.er_mode = atoi(tokens[0]);	ag.er_ind = atoi(tokens[3]);	g_strfreev(tokens);	tokens = NULL;	debug("Event reporting (CMER): mode=%d, ind=%d",			ag.er_mode, ag.er_ind);	switch (ag.er_ind) {	case 0:	case 1:		telephony_event_reporting_req(dev, ag.er_ind);		break;	default:		return -EINVAL;	}	return 0;}static int call_hold(struct audio_device *dev, const char *buf){	struct headset *hs = dev->headset;	int err;	if (strlen(buf) < 9)		return -EINVAL;	if (buf[8] != '?') {		telephony_call_hold_req(dev, &buf[8]);		return 0;	}	err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);	if (err < 0)		return err;	err = headset_send(hs, "\r\nOK\r\n");	if (err < 0)		return err;	if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)		return 0;	hfp_slc_complete(dev);	return 0;}static int button_press(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	g_dbus_emit_signal(device->conn, device->path,			AUDIO_HEADSET_INTERFACE, "AnswerRequested",			DBUS_TYPE_INVALID);	if (ag.ring_timer) {		g_source_remove(ag.ring_timer);		ag.ring_timer = 0;	}	return headset_send(hs, "\r\nOK\r\n");}int telephony_answer_call_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int answer_call(struct audio_device *device, const char *buf){	if (ag.ring_timer) {		g_source_remove(ag.ring_timer);		ag.ring_timer = 0;	}	if (ag.number) {		g_free(ag.number);		ag.number = NULL;	}	telephony_answer_call_req(device);	return 0;}int telephony_terminate_call_rsp(void *telephony_device,					cme_error_t err){	struct audio_device *device = telephony_device;	struct headset *hs = device->headset;	if (err != CME_ERROR_NONE)		return telephony_generic_rsp(telephony_device, err);	g_dbus_emit_signal(device->conn, device->path,			AUDIO_HEADSET_INTERFACE, "CallTerminated",			DBUS_TYPE_INVALID);	return headset_send(hs, "\r\nOK\r\n");}static int terminate_call(struct audio_device *device, const char *buf){	if (ag.number) {		g_free(ag.number);		ag.number = NULL;	}	if (ag.ring_timer) {		g_source_remove(ag.ring_timer);		ag.ring_timer = 0;	}	telephony_terminate_call_req(device);	return 0;}static int cli_notification(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	if (strlen(buf) < 9)		return -EINVAL;	hs->cli_active = buf[8] == '1' ? TRUE : FALSE;	return headset_send(hs, "\r\nOK\r\n");}int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int response_and_hold(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	if (strlen(buf) < 8)		return -EINVAL;	if (buf[7] == '=') {		telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);		return 0;	}	if (ag.rh >= 0)		headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);	return headset_send(hs, "\r\nOK\r\n", ag.rh);}int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int last_dialed_number(struct audio_device *device, const char *buf){	telephony_last_dialed_number_req(device);	return 0;}int telephony_dial_number_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int dial_number(struct audio_device *device, const char *buf){	char number[BUF_SIZE];	size_t buf_len;	buf_len = strlen(buf);	if (buf[buf_len - 1] != ';') {		debug("Rejecting non-voice call dial request");		return -EINVAL;	}	memset(number, 0, sizeof(number));	strncpy(number, &buf[3], buf_len - 4);	telephony_dial_number_req(device, number);	return 0;}static int signal_gain_setting(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	const char *property;	const char *name;	dbus_uint16_t gain;	if (strlen(buf) < 8) {		error("Too short string for Gain setting");		return -EINVAL;	}	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);	if (gain > 15) {		error("Invalid gain value received: %u", gain);		return -EINVAL;	}	switch (buf[5]) {	case HEADSET_GAIN_SPEAKER:		if (hs->sp_gain == gain)			goto ok;		name = "SpeakerGainChanged";		property = "SpeakerGain";		hs->sp_gain = gain;		break;	case HEADSET_GAIN_MICROPHONE:		if (hs->mic_gain == gain)			goto ok;		name = "MicrophoneGainChanged";		property = "MicrophoneGain";		hs->mic_gain = gain;		break;	default:		error("Unknown gain setting");		return -EINVAL;	}	g_dbus_emit_signal(device->conn, device->path,				AUDIO_HEADSET_INTERFACE, name,				DBUS_TYPE_UINT16, &gain,				DBUS_TYPE_INVALID);	emit_property_changed(device->conn, device->path,				AUDIO_HEADSET_INTERFACE, property,				DBUS_TYPE_UINT16, &gain);ok:	return headset_send(hs, "\r\nOK\r\n");}int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int dtmf_tone(struct audio_device *device, const char *buf){	if (strlen(buf) < 8) {		error("Too short string for DTMF tone");		return -EINVAL;	}	telephony_transmit_dtmf_req(device, buf[7]);	return 0;}int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int subscriber_number(struct audio_device *device, const char *buf){	telephony_subscriber_number_req(device);	return 0;}int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}static int list_current_calls(struct audio_device *device, const char *buf){	telephony_list_current_calls_req(device);	return 0;}static int extended_errors(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	if (strlen(buf) < 9)		return -EINVAL;	if (buf[8] == '1') {		hs->cme_enabled = TRUE;		debug("CME errors enabled for headset %p", hs);	} else {		hs->cme_enabled = FALSE;		debug("CME errors disabled for headset %p", hs);	}	return headset_send(hs, "\r\nOK\r\n");}static int call_waiting_notify(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	if (strlen(buf) < 9)		return -EINVAL;	if (buf[8] == '1') {		hs->cwa_enabled = TRUE;		debug("Call waiting notifiaction enabled for headset %p", hs);	} else {		hs->cwa_enabled = FALSE;		debug("Call waiting notification disabled for headset %p", hs);	}	return headset_send(hs, "\r\nOK\r\n");}int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}int telephony_call_hold_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}int telephony_disable_nr_and_ec_rsp(void *telephony_device, cme_error_t err){	return telephony_generic_rsp(telephony_device, err);}int telephony_operator_selection_ind(int mode, const char *oper){	if (!active_devices)		return -ENODEV;	send_foreach_headset(active_devices, hfp_cmp, "\r\n+COPS: %d,0,%s\r\n",				mode, oper);	return 0;}static int operator_selection(struct audio_device *device, const char *buf){	struct headset *hs = device->headset;	if (strlen(buf) < 8)		return -EINVAL;	switch (buf[7]) {	case '?':		telephony_operator_selection_req(device);		break;	case '=':		return headset_send(hs, "\r\nOK\r\n");	default:		return -EINVAL;	}	return 0;}static int disable_nr_and_ec(struct audio_device *device, const char *buf){	if (strlen(buf) < 9)		return -EINVAL;	telephony_disable_nr_and_ec_req(device);	return 0;}static struct event event_callbacks[] = {	{ "ATA", answer_call },	{ "ATD", dial_number },	{ "AT+VG", signal_gain_setting },	{ "AT+BRSF", supported_features },	{ "AT+CIND", report_indicators },	{ "AT+CMER", event_reporting },	{ "AT+CHLD", call_hold },	{ "AT+CHUP", terminate_call },	{ "AT+CKPD", button_press },	{ "AT+CLIP", cli_notification },	{ "AT+BTRH", response_and_hold },	{ "AT+BLDN", last_dialed_number },	{ "AT+VTS", dtmf_tone },	{ "AT+CNUM", subscriber_number },	{ "AT+CLCC", list_current_calls },	{ "AT+CMEE", extended_errors },	{ "AT+CCWA", call_waiting_notify },	{ "AT+COPS", operator_selection },	{ "AT+NREC", disable_nr_and_ec },	{ 0 }};static int handle_event(struct audio_device *device, const char *buf){	struct event *ev;	debug("Received %s", buf);	for (ev = event_callbacks; ev->cmd; ev++) {		if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))			return ev->callback(device, buf);	}	return -EINVAL;}static void close_sco(struct audio_device *device){	struct headset *hs = device->headset;	if (hs->sco) {		g_source_remove(hs->sco_id);		hs->sco_id = 0;		g_io_channel_close(hs->sco);		g_io_channel_unref(hs->sco);		hs->sco = NULL;	}}static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,				struct audio_device *device){	struct headset *hs;	unsigned char buf[BUF_SIZE];	char *cr;	gsize bytes_read = 0;	gsize free_space;	int err;	off_t cmd_len;	if (cond & G_IO_NVAL)		return FALSE;	hs = device->headset;	if (cond & (G_IO_ERR | G_IO_HUP))		goto failed;	if (g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1,				&bytes_read) != G_IO_ERROR_NONE)		return TRUE;	free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1;	if (free_space < bytes_read) {		/* Very likely that the HS is sending us garbage so		 * just ignore the data and disconnect */		error("Too much data to fit incomming buffer");		goto failed;	}	memcpy(&hs->buf[hs->data_start], buf, bytes_read);	hs->data_length += bytes_read;	/* Make sure the data is null terminated so we can use string	 * functions */	hs->buf[hs->data_start + hs->data_length] = '\0';	cr = strchr(&hs->buf[hs->data_start], '\r');	if (!cr)		return TRUE;	cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];	*cr = '\0';	err = handle_event(device, &hs->buf[hs->data_start]);	if (err == -EINVAL) {		error("Badly formated or unrecognized command: %s",				&hs->buf[hs->data_start]);		err = headset_send(hs, "\r\nERROR\r\n");	} else if (err < 0)		error("Error handling command %s: %s (%d)",			&hs->buf[hs->data_start], strerror(-err), -err);	hs->data_start += cmd_len;	hs->data_length -= cmd_len;	if (!hs->data_length)		hs->data_start = 0;	return TRUE;failed:	headset_set_state(device, HEADSET_STATE_DISCONNECTED);	return FALSE;}static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,			struct audio_device *device){	struct headset *hs;	if (cond & G_IO_NVAL)		return FALSE;	hs = device->headset;	error("Audio connection got disconnected");	headset_set_state(device, HEADSET_STATE_CONNECTED);	return FALSE;}static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,			const bdaddr_t *dst, gpointer user_data){	struct audio_device *dev = user_data;	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	char hs_address[18];	if (err < 0) {		error("connect(): %s (%d)", strerror(-err), -err);		goto failed;	}	ba2str(&dev->dst, hs_address);	hs->rfcomm = chan;	p->io = NULL;	if (server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID) &&			hs->hfp_handle != 0)		hs->hfp_active = TRUE;	else		hs->hfp_active = FALSE;	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,			(GIOFunc) rfcomm_io_cb, dev);	debug("%s: Connected to %s", dev->path, hs_address);	/* In HFP mode wait for Service Level Connection */	if (hs->hfp_active)		return;	headset_set_state(dev, HEADSET_STATE_CONNECTED);	if (p->target_state == HEADSET_STATE_PLAYING) {		p->err = sco_connect(dev, NULL, NULL, NULL);		if (p->err < 0)			goto failed;		return;	}	if (p->msg) {		DBusMessage *reply = dbus_message_new_method_return(p->msg);		g_dbus_send_message(dev->conn, reply);	}	pending_connect_finalize(dev);	return;failed:	if (p->msg)		error_connection_attempt_failed(dev->conn, p->msg, p->err);	pending_connect_finalize(dev);	if (hs->rfcomm)		headset_set_state(dev, HEADSET_STATE_CONNECTED);	else		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);}static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data){	struct audio_device *dev = user_data;	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	int ch = -1;	sdp_record_t *record = NULL;	sdp_list_t *protos, *classes = NULL;	uuid_t uuid;	if (err < 0) {		error("Unable to get service record: %s (%d)", strerror(-err),			-err);		goto failed_not_supported;	}	if (!recs || !recs->data) {		error("No records found");		goto failed_not_supported;	}	record = recs->data;	if (sdp_get_service_classes(record, &classes) < 0) {		error("Unable to get service classes from record");		goto failed_not_supported;	}	memcpy(&uuid, classes->data, sizeof(uuid));	if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16) {		error("Not a 16 bit UUID");		goto failed_not_supported;	}	if (hs->search_hfp) {		if (uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {			error("Service record didn't contain the HFP UUID");			goto failed_not_supported;		}		hs->hfp_handle = record->handle;	} else {		if (uuid.value.uuid16 != HEADSET_SVCLASS_ID) {			error("Service record didn't contain the HSP UUID");			goto failed_not_supported;		}		hs->hsp_handle = record->handle;	}	if (!sdp_get_access_protos(record, &protos)) {		ch = sdp_get_proto_port(protos, RFCOMM_UUID);		sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,					NULL);		sdp_list_free(protos, NULL);		protos = NULL;	}	if (ch == -1) {		error("Unable to extract RFCOMM channel from service record");		goto failed_not_supported;	}	hs->rfcomm_ch = ch;	err = rfcomm_connect(dev, NULL, NULL, NULL);	if (err < 0) {		error("Unable to connect: %s (%s)", strerror(-err), -err);		p->err = -err;		error_connection_attempt_failed(dev->conn, p->msg, p->err);		goto failed;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -