diff options
Diffstat (limited to 'audio/manager.c')
| -rw-r--r-- | audio/manager.c | 203 | 
1 files changed, 170 insertions, 33 deletions
| diff --git a/audio/manager.c b/audio/manager.c index 869557ca..6154e766 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -103,11 +103,15 @@ static struct device *default_dev = NULL;  static GSList *devices = NULL; -static uint32_t hs_record_id = 0; -static uint32_t hf_record_id = 0; +static uint32_t hsp_ag_record_id = 0; +static uint32_t hfp_ag_record_id = 0; -static GIOChannel *hs_server = NULL; -static GIOChannel *hf_server = NULL; +static uint32_t hsp_hs_record_id = 0; + +static GIOChannel *hsp_ag_server = NULL; +static GIOChannel *hfp_ag_server = NULL; + +static GIOChannel *hsp_hs_server = NULL;  static struct enabled_interfaces enabled = {  	.headset	= TRUE, @@ -227,10 +231,16 @@ gboolean server_is_enabled(uint16_t svc)  	switch (svc) {  	case HEADSET_SVCLASS_ID: -		ret = (hs_server != NULL); +		ret = (hsp_ag_server != NULL); +		break; +	case HEADSET_AGW_SVCLASS_ID: +		ret = (hsp_hs_server != NULL);  		break;  	case HANDSFREE_SVCLASS_ID: -		ret = (hf_server != NULL); +		ret = (hfp_ag_server != NULL); +		break; +	case HANDSFREE_AGW_SVCLASS_ID: +		ret = FALSE;  		break;  	case AUDIO_SINK_SVCLASS_ID:  		return enabled.sink; @@ -1222,6 +1232,62 @@ static sdp_record_t *hsp_ag_record(uint8_t ch)  	return record;  } +static sdp_record_t *hsp_hs_record(uint8_t ch) +{ +	sdp_list_t *svclass_id, *pfseq, *apseq, *root; +	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid; +	uuid_t l2cap_uuid, rfcomm_uuid; +	sdp_profile_desc_t profile; +	sdp_record_t *record; +	sdp_list_t *aproto, *proto[2]; +	sdp_data_t *channel; + +	record = sdp_record_alloc(); +	if (!record) +		return NULL; + +	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); +	root = sdp_list_append(0, &root_uuid); +	sdp_set_browse_groups(record, root); + +	sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID); +	svclass_id = sdp_list_append(0, &svclass_uuid); +	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); +	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); +	sdp_set_service_classes(record, svclass_id); + +	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID); +	profile.version = 0x0100; +	pfseq = sdp_list_append(0, &profile); +	sdp_set_profile_descs(record, pfseq); + +	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); +	proto[0] = sdp_list_append(0, &l2cap_uuid); +	apseq = sdp_list_append(0, proto[0]); + +	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); +	proto[1] = sdp_list_append(0, &rfcomm_uuid); +	channel = sdp_data_alloc(SDP_UINT8, &ch); +	proto[1] = sdp_list_append(proto[1], channel); +	apseq = sdp_list_append(apseq, proto[1]); + +	aproto = sdp_list_append(0, apseq); +	sdp_set_access_protos(record, aproto); + +	sdp_set_info_attr(record, "Headset", 0, 0); + +	sdp_data_free(channel); +	sdp_list_free(proto[0], 0); +	sdp_list_free(proto[1], 0); +	sdp_list_free(apseq, 0); +	sdp_list_free(pfseq, 0); +	sdp_list_free(aproto, 0); +	sdp_list_free(root, 0); +	sdp_list_free(svclass_id, 0); + +	return record; +} +  static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)  {  	sdp_list_t *svclass_id, *pfseq, *apseq, *root; @@ -1360,7 +1426,7 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  		return TRUE;  	} -	if (chan == hs_server) { +	if (chan == hsp_ag_server) {  		hfp_active = FALSE;  		uuid = HSP_AG_UUID;  	} else { @@ -1406,6 +1472,12 @@ failed:  	return TRUE;  } +static gboolean hs_io_cb(GIOChannel *chan, GIOCondition cond, void *data) +{ +	/*Stub*/ +	return TRUE; +} +  static GIOChannel *server_socket(uint8_t *channel, gboolean master)  {  	int sock, lm; @@ -1469,7 +1541,7 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)  	GError *err = NULL;  	uint32_t features; -	if (!(enabled.headset || enabled.gateway)) +	if (!enabled.headset)  		return 0;  	if (config) { @@ -1494,8 +1566,8 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)  			hfp = tmp;  	} -	hs_server = server_socket(&chan, master); -	if (!hs_server) +	hsp_ag_server = server_socket(&chan, master); +	if (!hsp_ag_server)  		return -1;  	record = hsp_ag_record(chan); @@ -1507,14 +1579,15 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)  	if (add_record_to_server(BDADDR_ANY, record) < 0) {  		error("Unable to register HS AG service record");  		sdp_record_free(record); -		g_io_channel_unref(hs_server); -		hs_server = NULL; +		g_io_channel_unref(hsp_ag_server); +		hsp_ag_server = NULL;  		return -1;  	} -	hs_record_id = record->handle; +	hsp_ag_record_id = record->handle; -	g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, -				(GIOFunc) ag_io_cb, NULL); +	g_io_add_watch(hsp_ag_server, +			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +			(GIOFunc) ag_io_cb, NULL);  	features = headset_config_init(config); @@ -1523,8 +1596,8 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)  	chan = DEFAULT_HF_AG_CHANNEL; -	hf_server = server_socket(&chan, master); -	if (!hf_server) +	hfp_ag_server = server_socket(&chan, master); +	if (!hfp_ag_server)  		return -1;  	record = hfp_ag_record(chan, features); @@ -1536,38 +1609,97 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)  	if (add_record_to_server(BDADDR_ANY, record) < 0) {  		error("Unable to register HF AG service record");  		sdp_record_free(record); -		g_io_channel_unref(hf_server); -		hf_server = NULL; +		g_io_channel_unref(hfp_ag_server); +		hfp_ag_server = NULL;  		return -1;  	} -	hf_record_id = record->handle; +	hfp_ag_record_id = record->handle; -	g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +	g_io_add_watch(hfp_ag_server, +			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,  			(GIOFunc) ag_io_cb, NULL);  	return 0;  } +static int gateway_server_init(DBusConnection *conn, GKeyFile *config) +{ +	uint8_t chan = DEFAULT_HSP_HS_CHANNEL; +	sdp_record_t *record; +	gboolean master = TRUE; +	GError *err = NULL; + +	if (!enabled.gateway) +		return 0; + +	if (config) { +		gboolean tmp; + +		tmp = g_key_file_get_boolean(config, "General", "Master", +						&err); +		if (err) { +			debug("audio.conf: %s", err->message); +			g_error_free(err); +			err = NULL; +		} else +			master = tmp; +	} + +	hsp_hs_server = server_socket(&chan, master); +	if (!hsp_hs_server) +		return -1; + +	record = hsp_hs_record(chan); +	if (!record) { +		error("Unable to allocate new service record"); +		return -1; +	} + +	if (add_record_to_server(BDADDR_ANY, record) < 0) { +		error("Unable to register HSP HS service record"); +		sdp_record_free(record); +		g_io_channel_unref(hsp_hs_server); +		hsp_hs_server = NULL; +		return -1; +	} +	hsp_hs_record_id = record->handle; + +	g_io_add_watch(hsp_hs_server, +			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +			(GIOFunc) hs_io_cb, NULL); +	return 0; +} +  static void server_exit(void)  { -	if (hs_record_id) { -		remove_record_from_server(hs_record_id); -		hs_record_id = 0; +	if (hsp_ag_record_id) { +		remove_record_from_server(hsp_ag_record_id); +		hsp_ag_record_id = 0;  	} -	if (hs_server) { -		g_io_channel_unref(hs_server); -		hs_server = NULL; +	if (hsp_ag_server) { +		g_io_channel_unref(hsp_ag_server); +		hsp_ag_server = NULL;  	} -	if (hf_record_id) { -		remove_record_from_server(hf_record_id); -		hf_record_id = 0; +	if (hsp_hs_record_id) { +		remove_record_from_server(hsp_hs_record_id); +		hsp_hs_record_id = 0;  	} -	if (hf_server) { -		g_io_channel_unref(hf_server); -		hf_server = NULL; +	if (hsp_hs_server) { +		g_io_channel_unref(hsp_hs_server); +		hsp_hs_server = NULL; +	} + +	if (hfp_ag_record_id) { +		remove_record_from_server(hfp_ag_record_id); +		hfp_ag_record_id = 0; +	} + +	if (hfp_ag_server) { +		g_io_channel_unref(hfp_ag_server); +		hfp_ag_server = NULL;  	}  } @@ -1631,6 +1763,11 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *config)  			goto failed;  	} +	if (enabled.gateway) { +		if (gateway_server_init(conn, config) < 0) +			goto failed; +	} +  	if (enabled.source || enabled.sink) {  		if (a2dp_init(conn, config) < 0)  			goto failed; | 
