diff options
Diffstat (limited to 'audio/headset.c')
| -rw-r--r-- | audio/headset.c | 225 | 
1 files changed, 104 insertions, 121 deletions
| diff --git a/audio/headset.c b/audio/headset.c index 0956208a..9ce11d10 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -107,12 +107,12 @@ static DBusConnection *connection = NULL;  static GMainLoop *main_loop = NULL;  struct manager *audio_manager_new(DBusConnection *conn); -void audio_manager_free(struct manager *amanager); -struct headset *audio_manager_find_headset_by_bda(struct manager *amanager, const bdaddr_t *bda); -void audio_manager_add_headset(struct manager *amanager, struct headset *hs); -gboolean audio_manager_create_headset_server(struct manager *amanager, uint8_t chan); -static DBusHandlerResult am_get_default_headset(struct manager *amanager, DBusMessage *msg); -static DBusHandlerResult am_create_headset(struct manager *amanager, DBusMessage *msg); +void audio_manager_free(struct manager *manager); +struct headset *audio_manager_find_headset_by_bda(struct manager *manager, const bdaddr_t *bda); +void audio_manager_add_headset(struct manager *manager, struct headset *hs); +gboolean audio_manager_create_headset_server(struct manager *manager, uint8_t chan); +static DBusHandlerResult am_get_default_headset(struct manager *manager, DBusMessage *msg); +static DBusHandlerResult am_create_headset(struct manager *manager, DBusMessage *msg);  struct headset *audio_headset_new(DBusConnection *conn, const bdaddr_t *bda);  void audio_headset_unref(struct headset *hs); @@ -139,7 +139,7 @@ static void pending_connect_free(struct pending_connect *c)  		dbus_message_unref(c->msg);  	if (c->conn)  		dbus_connection_unref(c->conn); -	free(c); +	g_free(c);  }  static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg, @@ -269,9 +269,9 @@ static int parse_headset_event(const char *buf, char *rsp, int rsp_len)  	return rv;  } -static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, +				struct headset *hs)  { -	struct headset *hs = data;  	unsigned char buf[BUF_SIZE];  	char *cr;  	gsize bytes_read = 0; @@ -356,16 +356,16 @@ failed:  	return FALSE;  } -static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, void *data) +static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, +				struct manager *manager)  {  	int srv_sk, cli_sk;  	struct sockaddr_rc addr;  	socklen_t size;  	char hs_address[18];  	struct headset *hs = NULL; -	struct manager *amanager = (struct manager *) data; -	assert(amanager != NULL); +	assert(manager != NULL);  	if (cond & G_IO_NVAL)  		return FALSE; @@ -386,7 +386,7 @@ static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  		return TRUE;  	} -	hs = audio_manager_find_headset_by_bda(amanager, &addr.rc_bdaddr); +	hs = audio_manager_find_headset_by_bda(manager, &addr.rc_bdaddr);  	if (!hs) {  		hs = audio_headset_new(connection, &addr.rc_bdaddr);  		if (!hs) { @@ -395,7 +395,7 @@ static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)  			return TRUE;  		} -		audio_manager_add_headset(amanager, hs); +		audio_manager_add_headset(manager, hs);  	}  	/* audio_headset_authorize(hs); */ @@ -434,27 +434,15 @@ static gboolean audio_input_to_sco_cb(GIOChannel *chan, GIOCondition cond, gpoin  	gsize bytes_written, total_bytes_written;  	GIOError err; -	if (!hs || !hs->sco) { -		error("The headset is invalid or does not have a SCO connection up"); -		audio_headset_close_input(hs); +	if (cond & G_IO_NVAL)  		return FALSE; -	} -	if (cond & G_IO_NVAL) { -		g_io_channel_unref(chan); -		return FALSE; -	} - -	if (cond & (G_IO_HUP | G_IO_ERR)) { -		audio_headset_close_input(hs); -		return FALSE; -	} +	if (cond & (G_IO_HUP | G_IO_ERR)) +		goto failed;  	err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read); -	if (err != G_IO_ERROR_NONE) { -		audio_headset_close_input(hs); -		return FALSE; -	} +	if (err != G_IO_ERROR_NONE) +		goto failed;  	total_bytes_written = bytes_written = 0;  	err = G_IO_ERROR_NONE; @@ -469,6 +457,26 @@ static gboolean audio_input_to_sco_cb(GIOChannel *chan, GIOCondition cond, gpoin  	};  	return TRUE; + +failed: +	audio_headset_close_input(hs); +	return FALSE; +} + +static void close_sco(struct headset *hs) +{ +	g_io_channel_close(hs->sco); +	g_io_channel_unref(hs->sco); +	hs->sco = NULL; +	if (hs->audio_output) { +		g_io_channel_unref(hs->audio_output); +		hs->audio_output = NULL; +	} +	if (hs->audio_input) +		audio_headset_close_input(hs); +	assert(hs->rfcomm); +	hs->state = HEADSET_STATE_CONNECTED; +	hs_signal(hs, "Stopped");  }  static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond, gpointer data) @@ -482,20 +490,8 @@ static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond  	if (cond & G_IO_NVAL)  		return FALSE; -	if (cond & (G_IO_HUP | G_IO_ERR)) { -		error("Audio connection got disconnected"); -		g_io_channel_close(chan); -		g_io_channel_unref(hs->sco); -		hs->sco = NULL; -		if (hs->audio_output) { -			g_io_channel_close(hs->audio_output); -			hs->audio_output = NULL; -		} -		assert(hs->rfcomm); -		hs->state = HEADSET_STATE_CONNECTED; -		hs_signal(hs, "Stopped"); -		return FALSE; -	} +	if (cond & (G_IO_HUP | G_IO_ERR)) +		goto disconn;  	if (!hs->audio_output && hs->output)  		audio_headset_open_output(hs, hs->output); @@ -503,10 +499,10 @@ static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond  	err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read);  	if (err != G_IO_ERROR_NONE) -		return FALSE; +		goto disconn;  	if (!hs->audio_output) { -		error("no audio output"); +		error("got %d bytes audio but have nowhere to write it", bytes_read);  		return TRUE;  	} @@ -524,6 +520,11 @@ static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond  	};  	return TRUE; + +disconn: +	error("Audio connection got disconnected"); +	close_sco(hs); +	return FALSE;  }  static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, @@ -1423,14 +1424,7 @@ static DBusHandlerResult hs_stop(struct headset *hs, DBusMessage *msg)  		hs->state = HEADSET_STATE_CONNECTED;  	} -	if (hs->sco) { -		g_io_channel_close(hs->sco); -		hs->sco = NULL; -		hs->state = HEADSET_STATE_CONNECTED; -	} - -	hs_signal(hs, "Stopped"); -	hs->state = HEADSET_STATE_CONNECTED; +	close_sco(hs);  	if (reply)  		send_message_and_unref(connection, reply); @@ -1516,7 +1510,7 @@ void audio_headset_unref(struct headset *hs)  {  	assert(hs != NULL); -	free(hs); +	g_free(hs);  }  gboolean audio_headset_close_output(struct headset *hs) @@ -1526,6 +1520,7 @@ gboolean audio_headset_close_output(struct headset *hs)  	if (hs->audio_output == NULL)   		return FALSE; +	g_io_channel_close(hs->audio_output);  	g_io_channel_unref(hs->audio_output);  	hs->audio_output = NULL; @@ -1541,8 +1536,8 @@ gboolean audio_headset_open_output(struct headset *hs, const char *output)  	audio_headset_close_output(hs);  	if (output && hs->output) { -		free(hs->output); -		hs->output = strdup(output); +		g_free(hs->output); +		hs->output = g_strdup(output);  	}  	assert(hs->output); @@ -1572,11 +1567,10 @@ gboolean audio_headset_close_input(struct headset *hs)  	if (hs->audio_input == NULL)   		return FALSE; +	g_io_channel_close(hs->audio_input);  	g_io_channel_unref(hs->audio_input);  	hs->audio_input = NULL; -	hs->state = HEADSET_STATE_CONNECTED; -  	return TRUE;  } @@ -1586,12 +1580,10 @@ gboolean audio_headset_open_input(struct headset *hs, const char *input)  	assert(hs != NULL); -	audio_headset_close_input(hs); -  	/* we keep the input name, and NULL can be use to reopen */  	if (input && hs->input) { -		free(hs->input); -		hs->input = strdup(input); +		g_free(hs->input); +		hs->input = g_strdup(input);  	}  	assert(hs->input); @@ -1609,18 +1601,16 @@ gboolean audio_headset_open_input(struct headset *hs, const char *input)  		return FALSE;  	} -	g_io_channel_set_close_on_unref(hs->audio_input, TRUE); -  	return TRUE;  } -gboolean audio_manager_create_headset_server(struct manager *amanager, uint8_t chan) +gboolean audio_manager_create_headset_server(struct manager *manager, uint8_t chan)  {  	int srv_sk; -	assert(amanager != NULL); +	assert(manager != NULL); -	if (amanager->server_sk) { +	if (manager->server_sk) {  		error("Server socket already created");  		return FALSE;  	} @@ -1631,27 +1621,27 @@ gboolean audio_manager_create_headset_server(struct manager *amanager, uint8_t c  		return FALSE;  	} -	if (!amanager->record_id) -		amanager->record_id = add_ag_record(chan); +	if (!manager->record_id) +		manager->record_id = add_ag_record(chan); -	if (!amanager->record_id) { +	if (!manager->record_id) {  		error("Unable to register service record");  		close(srv_sk);  		return FALSE;  	} -	amanager->server_sk = g_io_channel_unix_new(srv_sk); -	if (!amanager->server_sk) { +	manager->server_sk = g_io_channel_unix_new(srv_sk); +	if (!manager->server_sk) {  		error("Unable to allocate new GIOChannel"); -		remove_ag_record(amanager->record_id); -		amanager->record_id = 0; +		remove_ag_record(manager->record_id); +		manager->record_id = 0;  		close(srv_sk);  		return FALSE;  	} -	g_io_add_watch(amanager->server_sk, +	g_io_add_watch(manager->server_sk,  			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, -			(GIOFunc) server_io_cb, amanager); +			(GIOFunc) server_io_cb, manager);  	return TRUE;  } @@ -1663,27 +1653,27 @@ static gint headset_bda_cmp(gconstpointer headset, gconstpointer bda)  	return bacmp(&hs->bda, bda);  } -struct headset *audio_manager_find_headset_by_bda(struct manager *amanager, const bdaddr_t *bda) +struct headset *audio_manager_find_headset_by_bda(struct manager *manager, const bdaddr_t *bda)  {  	GSList *elem; -	assert(amanager); -	elem = g_slist_find_custom(amanager->headset_list, bda, headset_bda_cmp); +	assert(manager); +	elem = g_slist_find_custom(manager->headset_list, bda, headset_bda_cmp);  	return elem ? elem->data : NULL;  } -void audio_manager_add_headset(struct manager *amanager, struct headset *hs) +void audio_manager_add_headset(struct manager *manager, struct headset *hs)  { -	assert(amanager && hs); +	assert(manager && hs); -	if (g_slist_find(amanager->headset_list, hs)) +	if (g_slist_find(manager->headset_list, hs))  		return; -	amanager->headset_list = g_slist_append(amanager->headset_list, hs); +	manager->headset_list = g_slist_append(manager->headset_list, hs);  } -static DBusHandlerResult am_create_headset(struct manager *amanager,  +static DBusHandlerResult am_create_headset(struct manager *manager,   						DBusMessage *msg)  {  	const char *object_path; @@ -1693,7 +1683,7 @@ static DBusHandlerResult am_create_headset(struct manager *amanager,  	DBusMessage *reply;  	DBusError derr; -	if (!amanager) +	if (!manager)  		return err_not_connected(connection, msg);  	dbus_error_init(&derr); @@ -1714,14 +1704,14 @@ static DBusHandlerResult am_create_headset(struct manager *amanager,  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	str2ba(address, &bda); -	hs = audio_manager_find_headset_by_bda(amanager, &bda); +	hs = audio_manager_find_headset_by_bda(manager, &bda);  	if (!hs) {  		hs = audio_headset_new(connection, &bda);  		if (!hs)  			return error_reply(connection, msg,  					"org.bluez.Error.Failed",  					"Unable to create new headset object"); -		audio_manager_add_headset(amanager, hs); +		audio_manager_add_headset(manager, hs);  	}  	object_path = hs->object_path; @@ -1731,14 +1721,14 @@ static DBusHandlerResult am_create_headset(struct manager *amanager,  	return send_message_and_unref(connection, reply);  } -static DBusHandlerResult am_get_default_headset(struct manager *amanager,  +static DBusHandlerResult am_get_default_headset(struct manager *manager,   						DBusMessage *msg)  {  	DBusMessage *reply;  	char object_path[128];  	const char *opath = object_path; -	if (!amanager) +	if (!manager)  		return err_not_connected(connection, msg);  	reply = dbus_message_new_method_return(msg); @@ -1756,7 +1746,7 @@ static DBusHandlerResult am_message(DBusConnection *conn,  					DBusMessage *msg, void *data)  {  	const char *interface, *member; -	struct manager *amanager = (struct manager *)data; +	struct manager *manager = data;  	interface = dbus_message_get_interface(msg);  	member = dbus_message_get_member(msg); @@ -1769,10 +1759,10 @@ static DBusHandlerResult am_message(DBusConnection *conn,  		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  	if (strcmp(member, "CreateHeadset") == 0) -		return am_create_headset(amanager, msg); +		return am_create_headset(manager, msg);  	if (strcmp(member, "DefaultHeadset") == 0) -		return am_get_default_headset(amanager, msg); +		return am_get_default_headset(manager, msg);  	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  } @@ -1781,51 +1771,44 @@ static const DBusObjectPathVTable am_table = {  	.message_function = am_message,  }; -struct manager* audio_manager_new(DBusConnection *conn) +struct manager *audio_manager_new(DBusConnection *conn)  { -	struct manager *amanager; - -	amanager = malloc(sizeof(struct manager)); - -	if (!amanager) { -		error("Allocating new hs connection struct failed!"); -		return NULL; -	} +	struct manager *manager; -	memset(amanager, 0, sizeof(struct manager)); +	manager = g_new0(struct manager, 1);  	if (!dbus_connection_register_object_path(conn, AUDIO_MANAGER_PATH, -						&am_table, amanager)) { +						&am_table, manager)) {  		error("D-Bus failed to register %s path", AUDIO_MANAGER_PATH); -		free(amanager); +		g_free(manager);  		return NULL;  	} -	return amanager; +	return manager;  } -void audio_manager_free(struct manager* amanager) +void audio_manager_free(struct manager *manager)  { -	assert(amanager != NULL); +	assert(manager != NULL); -	if (amanager->record_id) { -		remove_ag_record(amanager->record_id); -		amanager->record_id = 0; +	if (manager->record_id) { +		remove_ag_record(manager->record_id); +		manager->record_id = 0;  	} -	if (amanager->server_sk) { -		g_io_channel_unref(amanager->server_sk); -		amanager->server_sk = NULL; +	if (manager->server_sk) { +		g_io_channel_unref(manager->server_sk); +		manager->server_sk = NULL;  	} -	if (amanager->headset_list) { -		g_slist_foreach(amanager->headset_list, (GFunc) audio_headset_unref, -				amanager); -		g_slist_free(amanager->headset_list); -		amanager->headset_list = NULL; +	if (manager->headset_list) { +		g_slist_foreach(manager->headset_list, (GFunc) audio_headset_unref, +				manager); +		g_slist_free(manager->headset_list); +		manager->headset_list = NULL;  	} -	free(amanager); +	g_free(manager);  }  static gboolean register_service(const char *ident, const char *name, | 
