diff options
Diffstat (limited to 'audio/headset.c')
| -rw-r--r-- | audio/headset.c | 152 | 
1 files changed, 57 insertions, 95 deletions
diff --git a/audio/headset.c b/audio/headset.c index dbebf67c..b83bd3fe 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -77,12 +77,13 @@ typedef enum {  } headset_state_t;  struct pending_connect { -	int ch;  	DBusMessage *msg;  	GIOChannel *io;  };  struct headset { +	int rfcomm_ch; +  	GIOChannel *rfcomm;  	GIOChannel *sco; @@ -119,52 +120,6 @@ static void pending_connect_free(struct pending_connect *c)  	g_free(c);  } -static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg, -					const char *name, const char *descr) -{ -	DBusMessage *derr; - -	if (!conn || !msg) -		return DBUS_HANDLER_RESULT_HANDLED; - -	derr = dbus_message_new_error(msg, name, descr); -	if (!derr) { -	       	error("Unable to allocate new error return"); -		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	} - -	return send_message_and_unref(conn, derr); -} - -static DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg) -{ -	return error_reply(conn, msg, "org.bluez.audio.Error.AlreadyConnected", -				"Already connected to a device"); -} - -static DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage *msg) -{ -	return error_reply(conn, msg, "org.bluez.audio.Error.NotConnected", -				"Not connected to any device"); -} - -static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg) -{ -	return error_reply(conn, msg, "org.bluez.audio.Error.NotSupported", -			"The service is not supported by the remote device"); -} - -static DBusHandlerResult err_connect_failed(DBusConnection *conn, DBusMessage *msg, int err) -{ -	return error_reply(conn, msg, "org.bluez.audio.Error.ConnectFailed", -				strerror(err)); -} - -static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg) -{ -	return error_reply(conn, msg, "org.bluez.audio.Error.Failed", "Failed"); -} -  static gboolean headset_close_output(struct headset *hs)  {  	assert(hs != NULL); @@ -661,9 +616,10 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,  	if (cond & G_IO_NVAL)  		return FALSE; -	assert(hs != NULL && hs->pending_connect != NULL &&  -			hs->rfcomm == NULL && -			hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS); +	assert(hs != NULL); +       	assert(hs->pending_connect != NULL); +	assert(hs->rfcomm == NULL); +	assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);  	sk = g_io_channel_unix_get_fd(chan); @@ -731,7 +687,7 @@ static int rfcomm_connect(audio_device_t *device, int *err)  	ba2str(&device->bda, address); -	debug("Connecting to %s channel %d", address, hs->pending_connect->ch); +	debug("Connecting to %s channel %d", address, hs->rfcomm_ch);  	sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);  	if (sk < 0) { @@ -761,7 +717,7 @@ static int rfcomm_connect(audio_device_t *device, int *err)  	memset(&addr, 0, sizeof(addr));  	addr.rc_family = AF_BLUETOOTH;  	bacpy(&addr.rc_bdaddr, &device->bda); -	addr.rc_channel = hs->pending_connect->ch; +	addr.rc_channel = hs->rfcomm_ch;  	hs->pending_connect->io = g_io_channel_unix_new(sk);  	if (!hs->pending_connect->io) { @@ -941,47 +897,12 @@ int headset_remove_ag_record(uint32_t rec_id)  	return 0;  } -static void finish_sdp_transaction(bdaddr_t *dba)  -{ -	char address[18], *addr_ptr = address; -	DBusMessage *msg, *reply; -	DBusError derr; - -	ba2str(dba, address); - -	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", -						"org.bluez.Adapter", -						"FinishRemoteServiceTransaction"); -	if (!msg) { -		error("Unable to allocate new method call"); -		return; -	} - -	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, -					DBUS_TYPE_INVALID); - -	dbus_error_init(&derr); -	reply = dbus_connection_send_with_reply_and_block(connection, msg, -								-1, &derr); - -	dbus_message_unref(msg); - -	if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) { -		error("FinishRemoteServiceTransaction(%s) failed: %s", -				address, derr.message); -		dbus_error_free(&derr); -		return; -	} - -	dbus_message_unref(reply); -} -  static void get_record_reply(DBusPendingCall *call, void *data)  {  	DBusMessage *reply;  	DBusError derr;  	uint8_t *array; -	int array_len, record_len, err = EIO; +	int array_len, record_len, err = EIO, ch = -1;  	sdp_record_t *record = NULL;  	sdp_list_t *protos, *classes = NULL;  	uuid_t uuid; @@ -1042,17 +963,19 @@ static void get_record_reply(DBusPendingCall *call, void *data)  	}  	if (!sdp_get_access_protos(record, &protos)) { -		c->ch = sdp_get_proto_port(protos, RFCOMM_UUID); +		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 (c->ch == -1) { +	if (ch == -1) {  		error("Unable to extract RFCOMM channel from service record");  		goto failed_not_supported;  	} +	hs->rfcomm_ch = ch; +  	if (rfcomm_connect(device, &err) < 0) {  		error("Unable to connect");  		if (c->msg)  @@ -1064,7 +987,7 @@ static void get_record_reply(DBusPendingCall *call, void *data)  	sdp_record_free(record);  	dbus_message_unref(reply); -	finish_sdp_transaction(&device->bda); +	finish_sdp_transaction(connection, &device->bda);  	return; @@ -1081,7 +1004,7 @@ failed:  	pending_connect_free(hs->pending_connect);  	hs->pending_connect = NULL;  	hs->state = HEADSET_STATE_DISCONNECTED; -	finish_sdp_transaction(&device->bda); +	finish_sdp_transaction(connection, &device->bda);  }  static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, @@ -1325,6 +1248,7 @@ static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,  	const char *hs_svc = "hsp";  	const char *addr_ptr;  	char hs_address[18]; +	int err;  	assert(hs != NULL); @@ -1341,6 +1265,17 @@ static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,  	hs->pending_connect->msg = msg ? dbus_message_ref(msg) : NULL; +	if (hs->rfcomm_ch > 0) { +	       	if (rfcomm_connect(device, &err) < 0) { +			error("Unable to connect"); +			pending_connect_free(hs->pending_connect); +			hs->pending_connect = NULL; +			hs->state = HEADSET_STATE_DISCONNECTED; +			return err_connect_failed(conn, msg, err); +		} else +			return DBUS_HANDLER_RESULT_HANDLED; +	} +  	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",  						"org.bluez.Adapter",  						"GetRemoteServiceHandles"); @@ -1438,7 +1373,7 @@ static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg,  	if (headset_send_ring(device) != G_IO_ERROR_NONE) {  		dbus_message_unref(reply); -		return err_failed(connection, msg); +		return err_failed(connection, msg, "Failed");  	}  	hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device); @@ -1593,15 +1528,42 @@ static DBusSignalVTable headset_signals[] = {  	{ NULL, NULL }  }; -headset_t *headset_init(const char *object_path) +headset_t *headset_init(const char *object_path, sdp_record_t *record)  { +	int ch; +	sdp_list_t *protos; +	headset_t *headset; +  	if (!dbus_connection_register_interface(connection, object_path,  							AUDIO_HEADSET_INTERFACE,  							headset_methods,  							headset_signals, NULL))  		return NULL; -	return g_new0(headset_t, 1); +	headset = g_new0(headset_t, 1); + +	headset->rfcomm_ch = -1; + +	if (!record) +		return headset; + +	if (sdp_get_access_protos(record, &protos) < 0) { +		error("Unable to get access protos from headset record"); +		return headset; +	} + +	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 Headset service on RFCOMM channel %d", ch); +	} else +		error("Unable to get RFCOMM channel from Headset record"); + +	return headset;  }  static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  | 
