summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/audio.conf12
-rw-r--r--audio/headset.c114
-rw-r--r--audio/headset.h2
-rw-r--r--audio/main.c111
-rw-r--r--audio/manager.c115
-rw-r--r--audio/manager.h5
6 files changed, 232 insertions, 127 deletions
diff --git a/audio/audio.conf b/audio/audio.conf
index 3fe8965f..ae9742b8 100644
--- a/audio/audio.conf
+++ b/audio/audio.conf
@@ -20,6 +20,18 @@
# Defaults to false
DisableHFP=true
+# HFP Gateway features
+# Defaults to false
+3WayCalling=false
+EchoCancelNoiseCancel=false
+VoiceRecognition=false
+InBandRingtone=false
+VoiceTags=false
+RejectingCalls=false
+EnhancedCallStatus=false
+EnhancedCallControl=false
+ExtendedErrorResultCodes=false
+
# Just an example of potential config options for the other interfaces
#[A2DP]
#SourceCount=2
diff --git a/audio/headset.c b/audio/headset.c
index 73c832f2..0fc013d7 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -73,8 +73,10 @@
#define AG_FEATURE_REJECT_A_CALL 0x0020
#define AG_FEATURE_ENHANCES_CALL_STATUS 0x0040
#define AG_FEATURE_ENHANCES_CALL_CONTROL 0x0080
+#define AG_FEATURE_EXTENDED_ERROR_RESULT_CODES 0x0100
/*Audio Gateway features.Default is In-band Ringtone*/
-static unsigned int ag_features = AG_FEATURE_INBAND_RINGTONE;
+static unsigned int ag_features;
+static gboolean sco_hci = TRUE;
static char *str_state[] = {
"HEADSET_STATE_DISCONNECTED",
@@ -1586,6 +1588,116 @@ register_iface:
return hs;
}
+int 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 0;
+
+ 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 0;
+}
+
void headset_free(struct device *dev)
{
struct headset *hs = dev->headset;
diff --git a/audio/headset.h b/audio/headset.h
index 4869bb36..a70ad973 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -47,6 +47,8 @@ struct headset *headset_init(struct device *dev, sdp_record_t *record,
void headset_free(struct device *dev);
+int headset_config_init(GKeyFile *config);
+
void headset_update(struct device *dev, sdp_record_t *record, uint16_t svc);
unsigned int headset_request_stream(struct device *dev, headset_stream_cb_t cb,
diff --git a/audio/main.c b/audio/main.c
index 52396beb..75cb67e6 100644
--- a/audio/main.c
+++ b/audio/main.c
@@ -42,32 +42,17 @@
#include "device.h"
#include "manager.h"
-static gboolean disable_hfp = TRUE;
-static gboolean sco_hci = TRUE;
-static int source_count = 1;
-
static GMainLoop *main_loop = NULL;
-static struct enabled_interfaces enabled = {
- .headset = TRUE,
- .gateway = FALSE,
- .sink = TRUE,
- .source = FALSE,
- .control = TRUE,
- .target = FALSE,
-};
-
static void sig_term(int sig)
{
g_main_loop_quit(main_loop);
}
-static void read_config(const char *file)
+static GKeyFile *load_config_file(const char *file)
{
- GKeyFile *keyfile;
GError *err = NULL;
- gboolean no_hfp;
- char *str;
+ GKeyFile *keyfile;
keyfile = g_key_file_new();
@@ -75,96 +60,17 @@ static void read_config(const char *file)
error("Parsing %s failed: %s", file, err->message);
g_error_free(err);
g_key_file_free(keyfile);
- return;
- }
-
- str = g_key_file_get_string(keyfile, "General", "SCORouting", &err);
- if (err) {
- debug("%s: %s", file, 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);
- }
-
- str = g_key_file_get_string(keyfile, "General", "Enable", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_error_free(err);
- err = NULL;
- } else {
- if (strstr(str, "Headset"))
- enabled.headset = TRUE;
- if (strstr(str, "Gateway"))
- enabled.gateway = TRUE;
- if (strstr(str, "Sink"))
- enabled.sink = TRUE;
- if (strstr(str, "Source"))
- enabled.source = TRUE;
- if (strstr(str, "Control"))
- enabled.control = TRUE;
- if (strstr(str, "Target"))
- enabled.target = TRUE;
- g_free(str);
+ return NULL;
}
- str = g_key_file_get_string(keyfile, "General", "Disable", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_error_free(err);
- err = NULL;
- } else {
- if (strstr(str, "Headset"))
- enabled.headset = FALSE;
- if (strstr(str, "Gateway"))
- enabled.gateway = FALSE;
- if (strstr(str, "Sink"))
- enabled.sink = FALSE;
- if (strstr(str, "Source"))
- enabled.source = FALSE;
- if (strstr(str, "Control"))
- enabled.control = FALSE;
- if (strstr(str, "Target"))
- enabled.target = FALSE;
- g_free(str);
- }
-
- no_hfp = g_key_file_get_boolean(keyfile, "Headset", "DisableHFP",
- &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_error_free(err);
- err = NULL;
- } else
- disable_hfp = no_hfp;
-
- str = g_key_file_get_string(keyfile, "A2DP", "SourceCount", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_error_free(err);
- err = NULL;
- } else {
- source_count = atoi(str);
- g_free(str);
- }
-
- debug("Config options: DisableHFP=%s, SCORouting=%s, SourceCount=%d",
- disable_hfp ? "true" : "false",
- sco_hci ? "HCI" : "PCM", source_count);
-
- g_key_file_free(keyfile);
+ return keyfile;
}
int main(int argc, char *argv[])
{
DBusConnection *conn;
struct sigaction sa;
+ GKeyFile *config;
start_logging("audio", "Bluetooth Audio daemon");
@@ -180,7 +86,7 @@ int main(int argc, char *argv[])
enable_debug();
- read_config(CONFIGDIR "/audio.conf");
+ config = load_config_file(CONFIGDIR "/audio.conf");
main_loop = g_main_loop_new(NULL, FALSE);
@@ -195,14 +101,15 @@ int main(int argc, char *argv[])
exit(1);
}
- if (audio_init(conn, &enabled, disable_hfp, sco_hci,
- source_count) < 0) {
+ if (audio_init(conn, config) < 0) {
error("Audio init failed!");
exit(1);
}
if (argc > 1 && !strcmp(argv[1], "-s"))
register_external_service(conn, "audio", "Audio service", "");
+ if (config)
+ g_key_file_free(config);
g_main_loop_run(main_loop);
diff --git a/audio/manager.c b/audio/manager.c
index cd4ba873..dd580f8c 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -107,7 +107,13 @@ static uint32_t hf_record_id = 0;
static GIOChannel *hs_server = NULL;
static GIOChannel *hf_server = NULL;
-static const struct enabled_interfaces *enabled;
+static struct enabled_interfaces enabled = {
+ .headset = TRUE,
+ .gateway = FALSE,
+ .sink = TRUE,
+ .source = FALSE,
+ .control = TRUE,
+};
static void get_next_record(struct audio_sdp_data *data);
static DBusHandlerResult get_handles(const char *uuid,
@@ -225,10 +231,10 @@ gboolean server_is_enabled(uint16_t svc)
ret = (hf_server != NULL);
break;
case AUDIO_SINK_SVCLASS_ID:
- return enabled->sink;
+ return enabled.sink;
case AV_REMOTE_TARGET_SVCLASS_ID:
case AV_REMOTE_SVCLASS_ID:
- return enabled->control;
+ return enabled.control;
default:
ret = FALSE;
break;
@@ -1069,11 +1075,11 @@ static void parse_stored_devices(char *key, char *value, void *data)
/* Change storage to source adapter */
bacpy(&device->store, src);
- if (enabled->headset && strstr(value, "headset"))
+ if (enabled.headset && strstr(value, "headset"))
device->headset = headset_init(device, NULL, 0);
- if (enabled->sink && strstr(value, "sink"))
+ if (enabled.sink && strstr(value, "sink"))
device->sink = sink_init(device);
- if (enabled->control && strstr(value, "control"))
+ if (enabled.control && strstr(value, "control"))
device->control = control_init(device);
add_device(device, FALSE);
}
@@ -1529,12 +1535,14 @@ static GIOChannel *server_socket(uint8_t *channel)
return io;
}
-static int headset_server_init(DBusConnection *conn, gboolean no_hfp)
+static int headset_server_init(DBusConnection *conn, GKeyFile *config)
{
uint8_t chan = DEFAULT_HS_AG_CHANNEL;
sdp_buf_t buf;
+ gboolean no_hfp = FALSE;
+ GError *err = NULL;
- if (!(enabled->headset || enabled->gateway))
+ if (!(enabled.headset || enabled.gateway))
return 0;
hs_server = server_socket(&chan);
@@ -1556,7 +1564,17 @@ static int headset_server_init(DBusConnection *conn, gboolean no_hfp)
}
g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) ag_io_cb, NULL);
+ (GIOFunc) ag_io_cb, NULL);
+
+ if (config) {
+ no_hfp = g_key_file_get_boolean(config, "Headset", "DisableHFP",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+ }
if (no_hfp)
return 0;
@@ -1582,7 +1600,7 @@ static int headset_server_init(DBusConnection *conn, gboolean no_hfp)
}
g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) ag_io_cb, NULL);
+ (GIOFunc) ag_io_cb, NULL);
return 0;
}
@@ -1610,14 +1628,55 @@ static void server_exit(void)
}
}
-int audio_init(DBusConnection *conn, struct enabled_interfaces *enable,
- gboolean no_hfp, gboolean sco_hci, int source_count)
+int audio_init(DBusConnection *conn, GKeyFile *config)
{
int sinks, sources;
+ char *str;
+ GError *err = NULL;
connection = dbus_connection_ref(conn);
- enabled = enable;
+ if (config) {
+ str = g_key_file_get_string(config, "General", "Enable", &err);
+
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ if (strstr(str, "Headset"))
+ enabled.headset = TRUE;
+ if (strstr(str, "Gateway"))
+ enabled.gateway = TRUE;
+ if (strstr(str, "Sink"))
+ enabled.sink = TRUE;
+ if (strstr(str, "Source"))
+ enabled.source = TRUE;
+ if (strstr(str, "Control"))
+ enabled.control = TRUE;
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(config, "General", "Disable", &err);
+
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ if (strstr(str, "Headset"))
+ enabled.headset = FALSE;
+ if (strstr(str, "Gateway"))
+ enabled.gateway = FALSE;
+ if (strstr(str, "Sink"))
+ enabled.sink = FALSE;
+ if (strstr(str, "Source"))
+ enabled.source = FALSE;
+ if (strstr(str, "Control"))
+ enabled.control = FALSE;
+ g_free(str);
+ }
+ }
if (!dbus_connection_create_object_path(conn, AUDIO_MANAGER_PATH,
NULL, manager_unregister)) {
@@ -1625,15 +1684,31 @@ int audio_init(DBusConnection *conn, struct enabled_interfaces *enable,
goto failed;
}
- if (headset_server_init(conn, no_hfp) < 0)
- goto failed;
+ if (enabled.headset) {
+ if (headset_config_init(config) < 0)
+ goto failed;
- if (enable->sink)
- sources = source_count;
- else
+ if (headset_server_init(conn, config) < 0)
+ goto failed;
+ }
+
+ if (enabled.sink) {
+ if (config) {
+ str = g_key_file_get_string(config, "A2DP",
+ "SourceCount", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ sources = atoi(str);
+ g_free(str);
+ }
+ }
+ } else
sources = 0;
- if (enable->source)
+ if (enabled.source)
sinks = 1;
else
sinks = 0;
@@ -1641,7 +1716,7 @@ int audio_init(DBusConnection *conn, struct enabled_interfaces *enable,
if (a2dp_init(conn, sources, sinks) < 0)
goto failed;
- if (enable->control && avrcp_init(conn) < 0)
+ if (enabled.control && avrcp_init(conn) < 0)
goto failed;
if (!dbus_connection_register_interface(conn, AUDIO_MANAGER_PATH,
diff --git a/audio/manager.h b/audio/manager.h
index 85fe4881..e740a524 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -32,14 +32,11 @@ struct enabled_interfaces {
gboolean sink;
gboolean source;
gboolean control;
- gboolean target;
};
typedef void (*create_dev_cb_t) (struct device *dev, void *user_data);
-int audio_init(DBusConnection *conn, struct enabled_interfaces *enabled,
- gboolean no_hfp, gboolean sco_hci, int source_count);
-
+int audio_init(DBusConnection *conn, GKeyFile *config);
void audio_exit(void);
uint32_t add_service_record(DBusConnection *conn, sdp_buf_t *buf);