From: "Frédéric Danis" <frederic.danis@linux.intel.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH v18 10/16] audio: Add headset audio properties to MediaTransport
Date: Thu, 23 Aug 2012 16:38:59 +0200 [thread overview]
Message-ID: <1345732745-28706-11-git-send-email-frederic.danis@linux.intel.com> (raw)
In-Reply-To: <1345732745-28706-1-git-send-email-frederic.danis@linux.intel.com>
---
audio/headset.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++--
audio/headset.h | 18 +++++
audio/transport.c | 94 ++++++++++++++++++++++-
doc/media-api.txt | 12 +++
4 files changed, 335 insertions(+), 9 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index aa9d0e7..aa9ceeb 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -85,6 +85,12 @@ struct headset_nrec_callback {
void *user_data;
};
+struct headset_gain_callback {
+ unsigned int id;
+ headset_gain_cb cb;
+ void *user_data;
+};
+
struct connect_cb {
unsigned int id;
headset_stream_cb_t cb;
@@ -129,6 +135,8 @@ struct headset {
char *connection_path;
guint watch;
GSList *nrec_cbs;
+ GSList *out_gain_cbs;
+ GSList *in_gain_cbs;
int out_gain;
int in_gain;
@@ -338,6 +346,7 @@ static gboolean headset_connection_property_changed(DBusConnection *connection,
struct headset *hs = dev->headset;
const char *property;
DBusMessageIter iter;
+ GSList *l;
dbus_message_iter_init(message, &iter);
@@ -363,12 +372,16 @@ static gboolean headset_connection_property_changed(DBusConnection *connection,
return TRUE;
dbus_message_iter_get_basic(&variant, &dbus_val);
- DBG("Receive InputGain=%d", dbus_val);
if (dbus_val > 15)
return TRUE;
hs->in_gain = dbus_val;
+ for (l = hs->in_gain_cbs; l; l = l->next) {
+ struct headset_gain_callback *gain_cb = l->data;
+
+ gain_cb->cb(dev, hs->in_gain, gain_cb->user_data);
+ }
} else if (g_str_equal(property, "OutputGain") == TRUE) {
DBusMessageIter variant;
dbus_uint16_t dbus_val;
@@ -386,12 +399,16 @@ static gboolean headset_connection_property_changed(DBusConnection *connection,
return TRUE;
dbus_message_iter_get_basic(&variant, &dbus_val);
- DBG("Receive OutputGain=%d", dbus_val);
if (dbus_val > 15)
return TRUE;
hs->out_gain = dbus_val;
+ for (l = hs->out_gain_cbs; l; l = l->next) {
+ struct headset_gain_callback *gain_cb = l->data;
+
+ gain_cb->cb(dev, hs->out_gain, gain_cb->user_data);
+ }
} else if (g_str_equal(property, "NREC") == TRUE) {
DBusMessageIter variant;
@@ -408,7 +425,12 @@ static gboolean headset_connection_property_changed(DBusConnection *connection,
return TRUE;
dbus_message_iter_get_basic(&variant, &hs->nrec);
- DBG("Receive NREC=%s", hs->nrec ? "TRUE" : "FALSE");
+
+ for (l = hs->nrec_cbs; l; l = l->next) {
+ struct headset_nrec_callback *nrec_cb = l->data;
+
+ nrec_cb->cb(dev, hs->nrec, nrec_cb->user_data);
+ }
} else if (g_str_equal(property, "AudioCodec") == TRUE) {
DBusMessageIter variant;
char codec;
@@ -971,6 +993,8 @@ static void headset_free(struct audio_device *dev)
headset_close_rfcomm(dev);
g_slist_free_full(hs->nrec_cbs, g_free);
+ g_slist_free_full(hs->out_gain_cbs, g_free);
+ g_slist_free_full(hs->in_gain_cbs, g_free);
g_free(hs);
dev->headset = NULL;
@@ -1069,6 +1093,92 @@ uint32_t headset_config_init(GKeyFile *config)
return telephony_get_ag_features();
}
+static void telephony_connection_set_property(struct audio_device *dev,
+ const char *name, int type, const void *value)
+{
+ struct headset *hs = dev->headset;
+ DBusMessage *msg;
+ DBusMessageIter iter, var;
+ const char *str_type;
+
+ if (hs->connection_name == NULL)
+ return;
+
+ if (hs->connection_path == NULL)
+ return;
+
+ switch (type) {
+ case DBUS_TYPE_BOOLEAN:
+ str_type = DBUS_TYPE_BOOLEAN_AS_STRING;
+ break;
+
+ case DBUS_TYPE_UINT16:
+ str_type = DBUS_TYPE_UINT16_AS_STRING;
+ break;
+
+ default:
+ return;
+ }
+
+ msg = dbus_message_new_method_call(hs->connection_name,
+ hs->connection_path,
+ AUDIO_TELEPHONY_CONNECTION_INTERFACE,
+ "SetProperty");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, str_type,
+ &var);
+ dbus_message_iter_append_basic(&var, type, value);
+ dbus_message_iter_close_container(&iter, &var);
+
+ g_dbus_send_message(dev->conn, msg);
+ return;
+}
+
+void headset_set_nrec(struct audio_device *dev, gboolean nrec)
+{
+ struct headset *hs = dev->headset;
+
+ hs->nrec = nrec;
+
+ telephony_connection_set_property(dev, "NREC", DBUS_TYPE_BOOLEAN,
+ &nrec);
+}
+
+void headset_set_inband_ringtone(struct audio_device *dev, gboolean inband)
+{
+ struct headset *hs = dev->headset;
+
+ hs->inband = inband;
+
+ telephony_connection_set_property(dev, "InbandRingtone",
+ DBUS_TYPE_BOOLEAN, &inband);
+}
+
+void headset_set_speaker_gain(struct audio_device *dev, gboolean gain)
+{
+ struct headset *hs = dev->headset;
+
+ hs->out_gain = gain;
+
+ telephony_connection_set_property(dev, "OutputGain", DBUS_TYPE_UINT16,
+ &gain);
+}
+
+void headset_set_microphone_gain(struct audio_device *dev, gboolean gain)
+{
+ struct headset *hs = dev->headset;
+
+ hs->in_gain = gain;
+
+ telephony_connection_set_property(dev, "InputGain", DBUS_TYPE_UINT16,
+ &gain);
+}
+
static gboolean hs_dc_timeout(struct audio_device *dev)
{
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
@@ -1456,7 +1566,12 @@ int headset_get_sco_fd(struct audio_device *dev)
gboolean headset_get_nrec(struct audio_device *dev)
{
- return TRUE;
+ struct headset *hs = dev->headset;
+
+ if (!hs->tel_dev)
+ return TRUE;
+
+ return hs->nrec;
}
unsigned int headset_add_nrec_cb(struct audio_device *dev,
@@ -1495,7 +1610,12 @@ gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id)
gboolean headset_get_inband(struct audio_device *dev)
{
- return TRUE;
+ struct headset *hs = dev->headset;
+
+ if (!hs->tel_dev)
+ return TRUE;
+
+ return hs->inband;
}
gboolean headset_get_sco_hci(struct audio_device *dev)
@@ -1503,6 +1623,96 @@ gboolean headset_get_sco_hci(struct audio_device *dev)
return sco_hci;
}
+uint16_t headset_get_output_gain(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (!hs->tel_dev)
+ return 0;
+
+ return hs->out_gain;
+}
+
+unsigned int headset_add_output_gain_cb(struct audio_device *dev,
+ headset_gain_cb cb, void *user_data)
+{
+ struct headset *hs = dev->headset;
+ struct headset_gain_callback *gain_cb;
+ static unsigned int id = 0;
+
+ gain_cb = g_new(struct headset_gain_callback, 1);
+ gain_cb->cb = cb;
+ gain_cb->user_data = user_data;
+ gain_cb->id = ++id;
+
+ hs->out_gain_cbs = g_slist_prepend(hs->out_gain_cbs, gain_cb);
+
+ return gain_cb->id;
+}
+
+gboolean headset_remove_output_gain_cb(struct audio_device *dev,
+ unsigned int id)
+{
+ struct headset *hs = dev->headset;
+ GSList *l;
+
+ for (l = hs->out_gain_cbs; l != NULL; l = l->next) {
+ struct headset_gain_callback *cb = l->data;
+ if (cb && cb->id == id) {
+ hs->out_gain_cbs = g_slist_remove(hs->out_gain_cbs, cb);
+ g_free(cb);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+uint16_t headset_get_input_gain(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (!hs->tel_dev)
+ return 0;
+
+ return hs->in_gain;
+}
+
+unsigned int headset_add_input_gain_cb(struct audio_device *dev,
+ headset_gain_cb cb, void *user_data)
+{
+ struct headset *hs = dev->headset;
+ struct headset_gain_callback *gain_cb;
+ static unsigned int id = 0;
+
+ gain_cb = g_new(struct headset_gain_callback, 1);
+ gain_cb->cb = cb;
+ gain_cb->user_data = user_data;
+ gain_cb->id = ++id;
+
+ hs->in_gain_cbs = g_slist_prepend(hs->in_gain_cbs, gain_cb);
+
+ return gain_cb->id;
+}
+
+gboolean headset_remove_input_gain_cb(struct audio_device *dev,
+ unsigned int id)
+{
+ struct headset *hs = dev->headset;
+ GSList *l;
+
+ for (l = hs->in_gain_cbs; l != NULL; l = l->next) {
+ struct headset_gain_callback *cb = l->data;
+ if (cb && cb->id == id) {
+ hs->in_gain_cbs = g_slist_remove(hs->in_gain_cbs, cb);
+ g_free(cb);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
void headset_shutdown(struct audio_device *dev)
{
struct pending_connect *p = dev->headset->pending;
diff --git a/audio/headset.h b/audio/headset.h
index c24e225..8cadd68 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -47,6 +47,9 @@ typedef void (*headset_state_cb) (struct audio_device *dev,
typedef void (*headset_nrec_cb) (struct audio_device *dev,
gboolean nrec,
void *user_data);
+typedef void (*headset_gain_cb) (struct audio_device *dev,
+ uint16_t gain,
+ void *user_data);
unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data);
gboolean headset_remove_state_cb(unsigned int id);
@@ -101,6 +104,16 @@ unsigned int headset_add_nrec_cb(struct audio_device *dev,
gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id);
gboolean headset_get_inband(struct audio_device *dev);
gboolean headset_get_sco_hci(struct audio_device *dev);
+uint16_t headset_get_output_gain(struct audio_device *dev);
+unsigned int headset_add_output_gain_cb(struct audio_device *dev,
+ headset_gain_cb cb, void *user_data);
+gboolean headset_remove_output_gain_cb(struct audio_device *dev,
+ unsigned int id);
+uint16_t headset_get_input_gain(struct audio_device *dev);
+unsigned int headset_add_input_gain_cb(struct audio_device *dev,
+ headset_gain_cb cb, void *user_data);
+gboolean headset_remove_input_gain_cb(struct audio_device *dev,
+ unsigned int id);
gboolean headset_is_active(struct audio_device *dev);
@@ -115,3 +128,8 @@ void headset_profile_connection_complete(struct audio_device *dev,
const char *connection_name,
const char *connection_path);
void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid);
+
+void headset_set_nrec(struct audio_device *dev, gboolean nrec);
+void headset_set_inband_ringtone(struct audio_device *dev, gboolean inband);
+void headset_set_speaker_gain(struct audio_device *dev, gboolean gain);
+void headset_set_microphone_gain(struct audio_device *dev, gboolean gain);
diff --git a/audio/transport.c b/audio/transport.c
index 832ad2a..d2a7c0a 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -71,6 +71,8 @@ struct a2dp_transport {
struct headset_transport {
struct audio_device *device;
unsigned int nrec_id;
+ unsigned int output_gain_id;
+ unsigned int input_gain_id;
};
struct media_transport {
@@ -788,26 +790,57 @@ static int set_property_headset(struct media_transport *transport,
const char *property,
DBusMessageIter *value)
{
+ struct headset_transport *headset = transport->data;
+
if (g_strcmp0(property, "NREC") == 0) {
gboolean nrec;
if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
- return -EINVAL;
+ goto failed;
+
dbus_message_iter_get_basic(value, &nrec);
- /* FIXME: set new nrec */
+ headset_set_nrec(headset->device, nrec);
return 0;
} else if (g_strcmp0(property, "InbandRingtone") == 0) {
gboolean inband;
if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
- return -EINVAL;
+ goto failed;
+
dbus_message_iter_get_basic(value, &inband);
- /* FIXME: set new inband */
+ headset_set_inband_ringtone(headset->device, inband);
+ return 0;
+ } else if (g_strcmp0(property, "OutputGain") == 0) {
+ uint16_t gain;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ goto failed;
+
+ dbus_message_iter_get_basic(value, &gain);
+
+ if (gain > 15)
+ goto failed;
+
+ headset_set_speaker_gain(headset->device, gain);
+ return 0;
+ } else if (g_strcmp0(property, "InputGain") == 0) {
+ uint16_t gain;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ goto failed;
+
+ dbus_message_iter_get_basic(value, &gain);
+
+ if (gain > 15)
+ goto failed;
+
+ headset_set_microphone_gain(headset->device, gain);
return 0;
}
+failed:
return -EINVAL;
}
@@ -880,6 +913,7 @@ static void get_properties_headset(struct media_transport *transport,
DBusMessageIter *dict)
{
gboolean nrec, inband;
+ uint16_t output_gain, input_gain;
const char *routing;
nrec = headset_get_nrec(transport->device);
@@ -888,6 +922,12 @@ static void get_properties_headset(struct media_transport *transport,
inband = headset_get_inband(transport->device);
dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband);
+ output_gain = headset_get_output_gain(transport->device);
+ dict_append_entry(dict, "OutputGain", DBUS_TYPE_UINT16, &output_gain);
+
+ input_gain = headset_get_input_gain(transport->device);
+ dict_append_entry(dict, "InputGain", DBUS_TYPE_UINT16, &input_gain);
+
routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM";
dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing);
}
@@ -988,6 +1028,14 @@ static void destroy_headset(void *data)
if (headset->nrec_id > 0)
headset_remove_nrec_cb(headset->device, headset->nrec_id);
+ if (headset->output_gain_id > 0)
+ headset_remove_output_gain_cb(headset->device,
+ headset->output_gain_id);
+
+ if (headset->input_gain_id > 0)
+ headset_remove_input_gain_cb(headset->device,
+ headset->input_gain_id);
+
g_free(headset);
}
@@ -1027,6 +1075,38 @@ static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
DBUS_TYPE_BOOLEAN, &nrec);
}
+static void headset_output_gain_changed(struct audio_device *dev, uint16_t gain,
+ void *user_data)
+{
+ struct media_transport *transport = user_data;
+
+ DBG("");
+
+ if (gain > 15)
+ return;
+
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "OutputGain", DBUS_TYPE_UINT16,
+ &gain);
+}
+
+static void headset_input_gain_changed(struct audio_device *dev, uint16_t gain,
+ void *user_data)
+{
+ struct media_transport *transport = user_data;
+
+ DBG("");
+
+ if (gain > 15)
+ return;
+
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "InputGain", DBUS_TYPE_UINT16,
+ &gain);
+}
+
struct media_transport *media_transport_create(DBusConnection *conn,
struct media_endpoint *endpoint,
struct audio_device *device,
@@ -1071,6 +1151,12 @@ struct media_transport *media_transport_create(DBusConnection *conn,
headset->nrec_id = headset_add_nrec_cb(device,
headset_nrec_changed,
transport);
+ headset->output_gain_id = headset_add_output_gain_cb(device,
+ headset_output_gain_changed,
+ transport);
+ headset->input_gain_id = headset_add_input_gain_cb(device,
+ headset_input_gain_changed,
+ transport);
transport->resume = resume_headset;
transport->suspend = suspend_headset;
diff --git a/doc/media-api.txt b/doc/media-api.txt
index e5eeaa0..f9b0ffa 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -349,3 +349,15 @@ Properties object Device [readonly]
acquired by the sender.
Possible Values: 0-127
+
+ uint16 OutputGain [readwrite]
+
+ Optional. The speaker gain when available.
+
+ Possible values: 0-15
+
+ uint16 InputGain [readwrite]
+
+ Optional. The microphone gain when available.
+
+ Possible values: 0-15
--
1.7.9.5
next prev parent reply other threads:[~2012-08-23 14:38 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-23 14:38 [PATCH v18 00/16] Add org.bluez.Telephony interface Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 01/16] doc: Add telephony interface design document Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 02/16] doc: Add telephony interface to audio-api.txt Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 03/16] doc: Add HSP HS channel to assigned numbers Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 04/16] audio: Remove telephony driver from headset.c Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 05/16] audio: Remove dummy telephony driver Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 06/16] audio: Remove maemo5 " Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 07/16] audio: Remove maemo6 " Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 08/16] audio: Remove oFono " Frédéric Danis
2012-08-23 14:38 ` [PATCH v18 09/16] audio: Add org.bluez.Telephony interface Frédéric Danis
2012-08-23 14:38 ` Frédéric Danis [this message]
2012-08-23 14:39 ` [PATCH v18 11/16] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
2012-08-23 14:39 ` [PATCH v18 12/16] audio: Move HFP HF server " Frédéric Danis
2012-08-23 14:39 ` [PATCH v18 13/16] audio: Add DUN GW to org.bluez.Telephony Frédéric Danis
2012-08-23 14:39 ` [PATCH v18 14/16] audio: Add SAP " Frédéric Danis
2012-08-23 14:39 ` [PATCH v18 15/16] adapter: Add API to get fast connectable mode Frédéric Danis
2012-08-23 14:39 ` [PATCH v18 16/16] audio: Add fast connectable to telephony interface Frédéric Danis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1345732745-28706-11-git-send-email-frederic.danis@linux.intel.com \
--to=frederic.danis@linux.intel.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).