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

📄 headset.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (!hs->hfp_active)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotSuppported",						"Not Supported");	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &value,				DBUS_TYPE_INVALID))		return NULL;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	if (!strncmp(value, "incoming", 8))		err = headset_send(hs, "\r\n+CIEV:3,1\r\n");	else if (!strncmp(value, "outgoing", 8))		err = headset_send(hs, "\r\n+CIEV:3,2\r\n");	else if (!strncmp(value, "remote", 6))		err = headset_send(hs, "\r\n+CIEV:3,3\r\n");	else		err = -EINVAL;	if (err < 0) {		dbus_message_unref(reply);		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",						"%s", strerror(-err));	}	return reply;}static DBusMessage *hf_identify_call(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	const char *number;	dbus_int32_t type;	if (!hs->hfp_active && !hs->cli_active)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotSuppported",						"Not Supported");	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,			      DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID))		return NULL;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	g_free(hs->ph_number);	hs->ph_number = g_strdup(number);	hs->type = type;	return reply;}static GDBusMethodTable headset_methods[] = {	{ "Connect",		"",	"",	hs_connect,						G_DBUS_METHOD_FLAG_ASYNC },	{ "Disconnect",		"",	"",	hs_disconnect },	{ "IsConnected",	"",	"b",	hs_is_connected },	{ "IndicateCall",	"",	"",	hs_ring },	{ "CancelCall",		"",	"",	hs_cancel_ringing },	{ "Play",		"",	"",	hs_play,						G_DBUS_METHOD_FLAG_ASYNC },	{ "Stop",		"",	"",	hs_stop },	{ "IsPlaying",		"",	"b",	hs_is_playing },	{ "GetSpeakerGain",	"",	"q",	hs_get_speaker_gain },	{ "GetMicrophoneGain",	"",	"q",	hs_get_mic_gain },	{ "SetSpeakerGain",	"q",	"",	hs_set_speaker_gain },	{ "SetMicrophoneGain",	"q",	"",	hs_set_mic_gain },	{ "SetupCall",		"s",	"",	hf_setup_call },	{ "IdentifyCall",	"si",	"",	hf_identify_call },	{ NULL, NULL, NULL, NULL }};static GDBusSignalTable headset_signals[] = {	{ "Connected",			""	},	{ "Disconnected",		""	},	{ "AnswerRequested",		""	},	{ "Stopped",			""	},	{ "Playing",			""	},	{ "SpeakerGainChanged",		"q"	},	{ "MicrophoneGainChanged",	"q"	},	{ "CallTerminated",		""	},	{ NULL, NULL }};static void headset_set_channel(struct headset *headset, sdp_record_t *record,				uint16_t svc){	int ch;	sdp_list_t *protos;	if (sdp_get_access_protos(record, &protos) < 0) {		error("Unable to get access protos from headset record");		return;	}	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);	if (ch > 0) {		headset->rfcomm_ch = ch;		debug("Discovered %s service on RFCOMM channel %d",			svc == HEADSET_SVCLASS_ID ? "Headset" : "Handsfree",			ch);	} else		error("Unable to get RFCOMM channel from Headset record");}void headset_update(struct audio_device *dev, sdp_record_t *record, uint16_t svc){	struct headset *headset = dev->headset;	switch (svc) {	case HANDSFREE_SVCLASS_ID:		if (headset->hfp_handle &&				(headset->hfp_handle != record->handle)) {			error("More than one HFP record found on device");			return;		}		headset->hfp_handle = record->handle;		break;	case HEADSET_SVCLASS_ID:		if (headset->hsp_handle &&				(headset->hsp_handle != record->handle)) {			error("More than one HSP record found on device");			return;		}		headset->hsp_handle = record->handle;		/* Ignore this record if we already have access to HFP */		if (headset->hfp_handle)			return;		break;	default:		debug("Invalid record passed to headset_update");		return;	}	headset_set_channel(headset, record, svc);}static void headset_free(struct audio_device *dev){	struct headset *hs = dev->headset;	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	if (hs->sco) {		g_io_channel_close(hs->sco);		g_io_channel_unref(hs->sco);	}	if (hs->rfcomm) {		g_io_channel_close(hs->rfcomm);		g_io_channel_unref(hs->rfcomm);	}	g_free(hs);	dev->headset = NULL;}static void path_unregister(void *data){	struct audio_device *dev = data;	info("Unregistered interface %s on path %s",		AUDIO_HEADSET_INTERFACE, dev->path);	headset_free(dev);}void headset_unregister(struct audio_device *dev){	g_dbus_unregister_interface(dev->conn, dev->path,		AUDIO_HEADSET_INTERFACE);}struct headset *headset_init(struct audio_device *dev, sdp_record_t *record,				uint16_t svc){	struct headset *hs;	hs = g_new0(struct headset, 1);	hs->rfcomm_ch = -1;	hs->sp_gain = -1;	hs->mic_gain = -1;	hs->search_hfp = server_is_enabled(HANDSFREE_SVCLASS_ID);	hs->hfp_active = FALSE;	hs->cli_active = FALSE;	hs->ph_number = NULL;	if (!record)		goto register_iface;	switch (svc) {	case HANDSFREE_SVCLASS_ID:		hs->hfp_handle = record->handle;		break;	case HEADSET_SVCLASS_ID:		hs->hsp_handle = record->handle;		break;	default:		debug("Invalid record passed to headset_init");		g_free(hs);		return NULL;	}	headset_set_channel(hs, record, svc);register_iface:	if (!g_dbus_register_interface(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE,					headset_methods, headset_signals, NULL,					dev, path_unregister)) {		g_free(hs);		return NULL;	}	info("Registered interface %s on path %s",		AUDIO_HEADSET_INTERFACE, dev->path);	return hs;}uint32_t headset_config_init(GKeyFile *config){	GError *err = NULL;	gboolean value;	char *str;	/* Use the default values if there is no config file */	if (config == NULL)		return ag_features;	str = g_key_file_get_string(config, "General", "SCORouting",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else {		if (strcmp(str, "PCM") == 0)			sco_hci = FALSE;		else if (strcmp(str, "HCI") == 0)			sco_hci = TRUE;		else			error("Invalid Headset Routing value: %s", str);		g_free(str);	}	value = g_key_file_get_boolean(config, "Headset", "3WayCalling",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_THREE_WAY_CALLING;	value = g_key_file_get_boolean(config, "Headset", "EchoCancelNoiseCancel",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_EC_ANDOR_NR;	value = g_key_file_get_boolean(config, "Headset", "VoiceRecognition",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_VOICE_RECOGNITION;	value = g_key_file_get_boolean(config, "Headset", "InBandRingtone",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_INBAND_RINGTONE;	value = g_key_file_get_boolean(config, "Headset", "VoiceTags",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG;	value = g_key_file_get_boolean(config, "Headset", "RejectingCalls",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_REJECT_A_CALL;	value = g_key_file_get_boolean(config, "Headset", "EnhancedCallStatus",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_ENHANCES_CALL_STATUS;	value = g_key_file_get_boolean(config, "Headset", "EnhancedCallControl",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_ENHANCES_CALL_CONTROL;	value = g_key_file_get_boolean(config, "Headset",					"ExtendedErrorResultCodes", &err);	if (err) {		debug("audio.conf: %s", err->message);		g_error_free(err);		err = NULL;	} else if (value)		ag_features |= AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;	return ag_features;}static gboolean hs_dc_timeout(struct audio_device *dev){	headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	return FALSE;}gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id){	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	GSList *l;	struct connect_cb *cb = NULL;	if (!p)		return FALSE;	for (l = p->callbacks; l != NULL; l = l->next) {		struct connect_cb *tmp = l->data;		if (tmp->id == id) {			cb = tmp;			break;		}	}	if (!cb)		return FALSE;	p->callbacks = g_slist_remove(p->callbacks, cb);	g_free(cb);	if (p->callbacks || p->msg)		return TRUE;	pending_connect_finalize(dev);	if (hs->auto_dc) {		if (hs->rfcomm)			hs->dc_timer = g_timeout_add(DC_TIMEOUT,						(GSourceFunc) hs_dc_timeout,						dev);		else			headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	}	return TRUE;}static gboolean dummy_connect_complete(struct audio_device *dev){	pending_connect_finalize(dev);	return FALSE;}unsigned int headset_request_stream(struct audio_device *dev, headset_stream_cb_t cb,					void *user_data){	struct headset *hs = dev->headset;	unsigned int id;	if (hs->rfcomm && hs->sco) {		id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);		g_idle_add((GSourceFunc) dummy_connect_complete, dev);		return id;	}	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)		return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);	if (hs->rfcomm == NULL) {		if (rfcomm_connect(dev, cb, user_data, &id) < 0)			return 0;		hs->auto_dc = TRUE;	} else {		if (sco_connect(dev, cb, user_data, &id) < 0)			return 0;	}	hs->pending->target_state = HEADSET_STATE_PLAYING;	return id;}gboolean get_hfp_active(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->hfp_active;}void set_hfp_active(struct audio_device *dev, gboolean active){	struct headset *hs = dev->headset;	hs->hfp_active = active;}int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io){	struct headset *hs = dev->headset;	hs->tmp_rfcomm = io;	return hs->tmp_rfcomm ? 0 : -EINVAL;}int headset_close_rfcomm(struct audio_device *dev){	struct headset *hs = dev->headset;	GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;	if (hs->ring_timer) {		g_source_remove(hs->ring_timer);		hs->ring_timer = 0;	}	if (rfcomm) {		g_io_channel_close(rfcomm);		g_io_channel_unref(rfcomm);		hs->tmp_rfcomm = NULL;		hs->rfcomm = NULL;	}	hs->data_start = 0;	hs->data_length = 0;	return 0;}void headset_set_authorized(struct audio_device *dev){	struct headset *hs = dev->headset;	hs->rfcomm = hs->tmp_rfcomm;	hs->tmp_rfcomm = NULL;	g_io_add_watch(hs->rfcomm,			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,			(GIOFunc) rfcomm_io_cb, dev);	hs->auto_dc = FALSE;	if (!hs->hfp_active)		headset_set_state(dev, HEADSET_STATE_CONNECTED);}void headset_set_state(struct audio_device *dev, headset_state_t state){	struct headset *hs = dev->headset;	if (hs->state == state)		return;	switch (state) {	case HEADSET_STATE_DISCONNECTED:		close_sco(dev);		headset_close_rfcomm(dev);		g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Disconnected",						DBUS_TYPE_INVALID);		break;	case HEADSET_STATE_CONNECT_IN_PROGRESS:		break;	case HEADSET_STATE_CONNECTED:		close_sco(dev);		if (hs->state < state) {			g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Connected",						DBUS_TYPE_INVALID);		} else if (hs->state == HEADSET_STATE_PLAYING) {			g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Stopped",						DBUS_TYPE_INVALID);		}		break;	case HEADSET_STATE_PLAY_IN_PROGRESS:		break;	case HEADSET_STATE_PLAYING:		hs->sco_id = g_io_add_watch(hs->sco,					G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) sco_cb, dev);		g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Playing", DBUS_TYPE_INVALID);		if (hs->sp_gain >= 0)			headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain);		if (hs->mic_gain >= 0)			headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain);		break;	}	debug("State changed %s: %s -> %s", dev->path, str_state[hs->state],		str_state[state]);	hs->state = state;}headset_state_t headset_get_state(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->state;}int headset_get_channel(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->rfcomm_ch;}gboolean headset_is_active(struct audio_device *dev){	struct headset *hs = dev->headset;	if (hs->state != HEADSET_STATE_DISCONNECTED)		return TRUE;	return FALSE;}gboolean headset_lock(struct audio_device *dev, headset_lock_t lock){	struct headset *hs = dev->headset;	if (hs->lock & lock)		return FALSE;	hs->lock |= lock;	return TRUE;}gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock){	struct headset *hs = dev->headset;	if (!(hs->lock & lock))		return FALSE;	hs->lock &= ~lock;	if (hs->lock)		return TRUE;	if (hs->state == HEADSET_STATE_PLAYING)		headset_set_state(dev, HEADSET_STATE_CONNECTED);	if (hs->auto_dc) {		if (hs->state == HEADSET_STATE_CONNECTED)			hs->dc_timer = g_timeout_add(DC_TIMEOUT,						(GSourceFunc) hs_dc_timeout,						dev);		else			headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	}	return TRUE;}gboolean headset_suspend(struct audio_device *dev, void *data){	return TRUE;}gboolean headset_play(struct audio_device *dev, void *data){	return TRUE;}int headset_get_sco_fd(struct audio_device *dev){	struct headset *hs = dev->headset;	if (!hs->sco)		return -1;	return g_io_channel_unix_get_fd(hs->sco);}

⌨️ 快捷键说明

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