diff options
-rw-r--r-- | audio/audio.conf | 12 | ||||
-rw-r--r-- | audio/headset.c | 114 | ||||
-rw-r--r-- | audio/headset.h | 2 | ||||
-rw-r--r-- | audio/main.c | 111 | ||||
-rw-r--r-- | audio/manager.c | 115 | ||||
-rw-r--r-- | audio/manager.h | 5 |
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); |