* [RFC v3 1/6] audio: Move tel drivers to DBus interface
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
2011-12-05 9:00 ` Luiz Augusto von Dentz
2011-12-01 15:14 ` [RFC v3 2/6] audio: Remove tel drivers Frédéric Danis
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
Makefile.am | 13 +-
audio/headset.c | 614 ++--------------------------------------------
audio/headset.h | 2 +
audio/manager.c | 4 +-
audio/telephony.c | 529 +++++++++++++++++++++++++++++++++++++++
audio/telephony.h | 25 +--
doc/assigned-numbers.txt | 1 +
doc/audio-api.txt | 91 +++++++
8 files changed, 648 insertions(+), 631 deletions(-)
create mode 100644 audio/telephony.c
diff --git a/Makefile.am b/Makefile.am
index 07b8626..31c1083 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -154,14 +154,8 @@ builtin_sources += audio/main.c \
audio/unix.h audio/unix.c \
audio/media.h audio/media.c \
audio/transport.h audio/transport.c \
- audio/telephony.h audio/a2dp-codecs.h
-builtin_nodist += audio/telephony.c
-
-noinst_LIBRARIES += audio/libtelephony.a
-
-audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
- audio/telephony-maemo5.c audio/telephony-ofono.c \
- audio/telephony-maemo6.c
+ audio/telephony.h audio/telephony.c \
+ audio/a2dp-codecs.h
endif
if SAPPLUGIN
@@ -476,9 +470,6 @@ MAINTAINERCLEANFILES = Makefile.in \
src/builtin.h: src/genbuiltin $(builtin_sources)
$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
-audio/telephony.c: audio/@TELEPHONY_DRIVER@
- $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
-
sap/sap.c: sap/@SAP_DRIVER@
$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
diff --git a/audio/headset.c b/audio/headset.c
index 6aef6a8..74eb7a4 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -70,8 +70,6 @@
#define HEADSET_GAIN_MICROPHONE 'M'
static struct {
- gboolean telephony_ready; /* Telephony plugin initialized */
- uint32_t features; /* HFP AG features */
const struct indicator *indicators; /* Available HFP indicators */
int er_mode; /* Event reporting mode */
int er_ind; /* Event reporting for indicators */
@@ -81,8 +79,6 @@ static struct {
guint ring_timer; /* For incoming call indication */
const char *chld; /* Response to AT+CHLD=? */
} ag = {
- .telephony_ready = FALSE,
- .features = 0,
.er_mode = 3,
.er_ind = 0,
.rh = BTRH_NOT_SUPPORTED,
@@ -236,40 +232,6 @@ static void print_ag_features(uint32_t features)
g_free(str);
}
-static void print_hf_features(uint32_t features)
-{
- GString *gstr;
- char *str;
-
- if (features == 0) {
- DBG("HFP HF features: (none)");
- return;
- }
-
- gstr = g_string_new("HFP HF features: ");
-
- if (features & HF_FEATURE_EC_ANDOR_NR)
- g_string_append(gstr, "\"EC and/or NR function\" ");
- if (features & HF_FEATURE_CALL_WAITING_AND_3WAY)
- g_string_append(gstr, "\"Call waiting and 3-way calling\" ");
- if (features & HF_FEATURE_CLI_PRESENTATION)
- g_string_append(gstr, "\"CLI presentation capability\" ");
- if (features & HF_FEATURE_VOICE_RECOGNITION)
- g_string_append(gstr, "\"Voice recognition activation\" ");
- if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL)
- g_string_append(gstr, "\"Remote volume control\" ");
- if (features & HF_FEATURE_ENHANCED_CALL_STATUS)
- g_string_append(gstr, "\"Enhanced call status\" ");
- if (features & HF_FEATURE_ENHANCED_CALL_CONTROL)
- g_string_append(gstr, "\"Enhanced call control\" ");
-
- str = g_string_free(gstr, FALSE);
-
- DBG("%s", str);
-
- g_free(str);
-}
-
static const char *state2str(headset_state_t state)
{
switch (state) {
@@ -333,97 +295,6 @@ static int __attribute__((format(printf, 2, 3)))
return ret;
}
-static int supported_features(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- int err;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- slc->hf_features = strtoul(&buf[8], NULL, 10);
-
- print_hf_features(slc->hf_features);
-
- err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
- if (err < 0)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-static char *indicator_ranges(const struct indicator *indicators)
-{
- int i;
- GString *gstr;
-
- gstr = g_string_new("\r\n+CIND: ");
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (i == 0)
- g_string_append_printf(gstr, "(\"%s\",(%s))",
- indicators[i].desc,
- indicators[i].range);
- else
- g_string_append_printf(gstr, ",(\"%s\",(%s))",
- indicators[i].desc,
- indicators[i].range);
- }
-
- g_string_append(gstr, "\r\n");
-
- return g_string_free(gstr, FALSE);
-}
-
-static char *indicator_values(const struct indicator *indicators)
-{
- int i;
- GString *gstr;
-
- gstr = g_string_new("\r\n+CIND: ");
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (i == 0)
- g_string_append_printf(gstr, "%d", indicators[i].val);
- else
- g_string_append_printf(gstr, ",%d", indicators[i].val);
- }
-
- g_string_append(gstr, "\r\n");
-
- return g_string_free(gstr, FALSE);
-}
-
-static int report_indicators(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- int err;
- char *str;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- if (ag.indicators == NULL) {
- error("HFP AG indicators not initialized");
- return headset_send(hs, "\r\nERROR\r\n");
- }
-
- if (buf[7] == '=')
- str = indicator_ranges(ag.indicators);
- else
- str = indicator_values(ag.indicators);
-
- err = headset_send(hs, "%s", str);
-
- g_free(str);
-
- if (err < 0)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -656,7 +527,7 @@ static int hfp_cmp(struct headset *hs)
return -1;
}
-static void hfp_slc_complete(struct audio_device *dev)
+void headset_slc_complete(struct audio_device *dev)
{
struct headset *hs = dev->headset;
struct pending_connect *p = hs->pending;
@@ -721,73 +592,10 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
return 0;
if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
- ag.features & AG_FEATURE_THREE_WAY_CALLING)
- return 0;
-
- hfp_slc_complete(device);
-
- return 0;
-}
-
-static int event_reporting(struct audio_device *dev, const char *buf)
-{
- char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */
-
- if (strlen(buf) < 13)
- return -EINVAL;
-
- tokens = g_strsplit(&buf[8], ",", 5);
- if (g_strv_length(tokens) < 4) {
- g_strfreev(tokens);
- return -EINVAL;
- }
-
- ag.er_mode = atoi(tokens[0]);
- ag.er_ind = atoi(tokens[3]);
-
- g_strfreev(tokens);
- tokens = NULL;
-
- DBG("Event reporting (CMER): mode=%d, ind=%d",
- ag.er_mode, ag.er_ind);
-
- switch (ag.er_ind) {
- case 0:
- case 1:
- telephony_event_reporting_req(dev, ag.er_ind);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int call_hold(struct audio_device *dev, const char *buf)
-{
- struct headset *hs = dev->headset;
- int err;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] != '?') {
- telephony_call_hold_req(dev, &buf[8]);
+ telephony_get_ag_features() & AG_FEATURE_THREE_WAY_CALLING)
return 0;
- }
- err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
- if (err < 0)
- return err;
-
- err = headset_send(hs, "\r\nOK\r\n");
- if (err < 0)
- return err;
-
- if (hs->state != HEADSET_STATE_CONNECTING)
- return 0;
-
- hfp_slc_complete(dev);
+ headset_slc_complete(device);
return 0;
}
@@ -797,47 +605,11 @@ int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
return telephony_generic_rsp(telephony_device, err);
}
-static int key_press(struct audio_device *device, const char *buf)
-{
- if (strlen(buf) < 9)
- return -EINVAL;
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, "AnswerRequested",
- DBUS_TYPE_INVALID);
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- telephony_key_press_req(device, &buf[8]);
-
- return 0;
-}
-
int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int answer_call(struct audio_device *device, const char *buf)
-{
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- if (ag.number) {
- g_free(ag.number);
- ag.number = NULL;
- }
-
- telephony_answer_call_req(device);
-
- return 0;
-}
-
int telephony_terminate_call_rsp(void *telephony_device,
cme_error_t err)
{
@@ -854,99 +626,21 @@ int telephony_terminate_call_rsp(void *telephony_device,
return headset_send(hs, "\r\nOK\r\n");
}
-static int terminate_call(struct audio_device *device, const char *buf)
-{
- if (ag.number) {
- g_free(ag.number);
- ag.number = NULL;
- }
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- telephony_terminate_call_req(device);
-
- return 0;
-}
-
-static int cli_notification(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int response_and_hold(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- if (ag.rh == BTRH_NOT_SUPPORTED)
- return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED);
-
- if (buf[7] == '=') {
- telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);
- return 0;
- }
-
- if (ag.rh >= 0)
- headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int last_dialed_number(struct audio_device *device, const char *buf)
-{
- telephony_last_dialed_number_req(device);
-
- return 0;
-}
-
int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int dial_number(struct audio_device *device, const char *buf)
-{
- char number[BUF_SIZE];
- size_t buf_len;
-
- buf_len = strlen(buf);
-
- if (buf[buf_len - 1] != ';') {
- DBG("Rejecting non-voice call dial request");
- return -EINVAL;
- }
-
- memset(number, 0, sizeof(number));
- strncpy(number, &buf[3], buf_len - 4);
-
- telephony_dial_number_req(device, number);
-
- return 0;
-}
-
static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
{
struct headset *hs = device->headset;
@@ -994,111 +688,21 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
return 0;
}
-static int signal_gain_setting(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- dbus_uint16_t gain;
- int err;
-
- if (strlen(buf) < 8) {
- error("Too short string for Gain setting");
- return -EINVAL;
- }
-
- gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
-
- err = headset_set_gain(device, gain, buf[5]);
- if (err < 0 && err != -EALREADY)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int dtmf_tone(struct audio_device *device, const char *buf)
-{
- char tone;
-
- if (strlen(buf) < 8) {
- error("Too short string for DTMF tone");
- return -EINVAL;
- }
-
- tone = buf[7];
- if (tone >= '#' && tone <= 'D')
- telephony_transmit_dtmf_req(device, tone);
- else
- return -EINVAL;
-
- return 0;
-}
-
int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int subscriber_number(struct audio_device *device, const char *buf)
-{
- telephony_subscriber_number_req(device);
-
- return 0;
-}
-
int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int list_current_calls(struct audio_device *device, const char *buf)
-{
- telephony_list_current_calls_req(device);
-
- return 0;
-}
-
-static int extended_errors(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '1') {
- slc->cme_enabled = TRUE;
- DBG("CME errors enabled for headset %p", hs);
- } else {
- slc->cme_enabled = FALSE;
- DBG("CME errors disabled for headset %p", hs);
- }
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-static int call_waiting_notify(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '1') {
- slc->cwa_enabled = TRUE;
- DBG("Call waiting notification enabled for headset %p", hs);
- } else {
- slc->cwa_enabled = FALSE;
- DBG("Call waiting notification disabled for headset %p", hs);
- }
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
@@ -1146,108 +750,6 @@ int telephony_operator_selection_ind(int mode, const char *oper)
return 0;
}
-static int operator_selection(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- switch (buf[7]) {
- case '?':
- telephony_operator_selection_req(device);
- break;
- case '=':
- return headset_send(hs, "\r\nOK\r\n");
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int nr_and_ec(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '0')
- slc->nrec_req = FALSE;
- else
- slc->nrec_req = TRUE;
-
- telephony_nr_and_ec_req(device, slc->nrec_req);
-
- return 0;
-}
-
-static int voice_dial(struct audio_device *device, const char *buf)
-{
- gboolean enable;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '0')
- enable = FALSE;
- else
- enable = TRUE;
-
- telephony_voice_dial_req(device, enable);
-
- return 0;
-}
-
-static int apple_command(struct audio_device *device, const char *buf)
-{
- DBG("Got Apple command: %s", buf);
-
- return telephony_generic_rsp(device, CME_ERROR_NONE);
-}
-
-static struct event event_callbacks[] = {
- { "ATA", answer_call },
- { "ATD", dial_number },
- { "AT+VG", signal_gain_setting },
- { "AT+BRSF", supported_features },
- { "AT+CIND", report_indicators },
- { "AT+CMER", event_reporting },
- { "AT+CHLD", call_hold },
- { "AT+CHUP", terminate_call },
- { "AT+CKPD", key_press },
- { "AT+CLIP", cli_notification },
- { "AT+BTRH", response_and_hold },
- { "AT+BLDN", last_dialed_number },
- { "AT+VTS", dtmf_tone },
- { "AT+CNUM", subscriber_number },
- { "AT+CLCC", list_current_calls },
- { "AT+CMEE", extended_errors },
- { "AT+CCWA", call_waiting_notify },
- { "AT+COPS", operator_selection },
- { "AT+NREC", nr_and_ec },
- { "AT+BVRA", voice_dial },
- { "AT+XAPL", apple_command },
- { "AT+IPHONEACCEV", apple_command },
- { 0 }
-};
-
-static int handle_event(struct audio_device *device, const char *buf)
-{
- struct event *ev;
-
- DBG("Received %s", buf);
-
- for (ev = event_callbacks; ev->cmd; ev++) {
- if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
- return ev->callback(device, buf);
- }
-
- return -EINVAL;
-}
-
static void close_sco(struct audio_device *device)
{
struct headset *hs = device->headset;
@@ -1266,94 +768,6 @@ static void close_sco(struct audio_device *device)
}
}
-static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
- struct audio_device *device)
-{
- struct headset *hs;
- struct headset_slc *slc;
- unsigned char buf[BUF_SIZE];
- ssize_t bytes_read;
- size_t free_space;
- int fd;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- hs = device->headset;
- slc = hs->slc;
-
- if (cond & (G_IO_ERR | G_IO_HUP)) {
- DBG("ERR or HUP on RFCOMM socket");
- goto failed;
- }
-
- fd = g_io_channel_unix_get_fd(chan);
-
- bytes_read = read(fd, buf, sizeof(buf) - 1);
- if (bytes_read < 0)
- return TRUE;
-
- free_space = sizeof(slc->buf) - slc->data_start -
- slc->data_length - 1;
-
- if (free_space < (size_t) bytes_read) {
- /* Very likely that the HS is sending us garbage so
- * just ignore the data and disconnect */
- error("Too much data to fit incomming buffer");
- goto failed;
- }
-
- memcpy(&slc->buf[slc->data_start], buf, bytes_read);
- slc->data_length += bytes_read;
-
- /* Make sure the data is null terminated so we can use string
- * functions */
- slc->buf[slc->data_start + slc->data_length] = '\0';
-
- while (slc->data_length > 0) {
- char *cr;
- int err;
- off_t cmd_len;
-
- cr = strchr(&slc->buf[slc->data_start], '\r');
- if (!cr)
- break;
-
- cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
- *cr = '\0';
-
- if (cmd_len > 1)
- err = handle_event(device, &slc->buf[slc->data_start]);
- else
- /* Silently skip empty commands */
- err = 0;
-
- if (err == -EINVAL) {
- error("Badly formated or unrecognized command: %s",
- &slc->buf[slc->data_start]);
- err = headset_send(hs, "\r\nERROR\r\n");
- if (err < 0)
- goto failed;
- } else if (err < 0)
- error("Error handling command %s: %s (%d)",
- &slc->buf[slc->data_start],
- strerror(-err), -err);
-
- slc->data_start += cmd_len;
- slc->data_length -= cmd_len;
-
- if (!slc->data_length)
- slc->data_start = 0;
- }
-
- return TRUE;
-
-failed:
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
- return FALSE;
-}
-
static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
struct audio_device *device)
{
@@ -1381,7 +795,7 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
}
/* For HFP telephony isn't ready just disconnect */
- if (hs->hfp_active && !ag.telephony_ready) {
+ if (hs->hfp_active && !telephony_get_ready_state()) {
error("Unable to accept HFP connection since the telephony "
"subsystem isn't initialized");
goto failed;
@@ -1397,8 +811,7 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
else
hs->auto_dc = FALSE;
- g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, dev);
+ hs->slc = telephony_device_connecting(chan, dev);
DBG("%s: Connected to %s", dev->path, hs_address);
@@ -1740,7 +1153,7 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
else if (hs->state > HEADSET_STATE_CONNECTING)
return btd_error_already_connected(msg);
- if (hs->hfp_handle && !ag.telephony_ready)
+ if (hs->hfp_handle && !telephony_get_ready_state())
return btd_error_not_ready(msg);
device->auto_connect = FALSE;
@@ -2245,7 +1658,7 @@ uint32_t headset_config_init(GKeyFile *config)
/* Use the default values if there is no config file */
if (config == NULL)
- return ag.features;
+ return telephony_get_ag_features();
str = g_key_file_get_string(config, "General", "SCORouting",
&err);
@@ -2275,7 +1688,7 @@ uint32_t headset_config_init(GKeyFile *config)
g_free(str);
}
- return ag.features;
+ return telephony_get_ag_features();
}
static gboolean hs_dc_timeout(struct audio_device *dev)
@@ -2518,6 +1931,10 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
case HEADSET_STATE_DISCONNECTED:
value = FALSE;
close_sco(dev);
+
+ if (dev->headset->slc)
+ telephony_device_disconnect(dev->headset->slc);
+
headset_close_rfcomm(dev);
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
@@ -2546,7 +1963,8 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
if (hs->state < state) {
- if (ag.features & AG_FEATURE_INBAND_RINGTONE)
+ if (telephony_get_ag_features() &
+ AG_FEATURE_INBAND_RINGTONE)
slc->inband_ring = TRUE;
else
slc->inband_ring = FALSE;
@@ -2880,15 +2298,13 @@ int telephony_ready_ind(uint32_t features,
const struct indicator *indicators, int rh,
const char *chld)
{
- ag.telephony_ready = TRUE;
- ag.features = features;
ag.indicators = indicators;
ag.rh = rh;
ag.chld = chld;
DBG("Telephony plugin initialized");
- print_ag_features(ag.features);
+ print_ag_features(telephony_get_ag_features());
return 0;
}
diff --git a/audio/headset.h b/audio/headset.h
index 99eeca8..d43952f 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -111,3 +111,5 @@ gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
gboolean headset_suspend(struct audio_device *dev, void *data);
gboolean headset_play(struct audio_device *dev, void *data);
void headset_shutdown(struct audio_device *dev);
+
+void headset_slc_complete(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 8de5515..4624552 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -880,7 +880,7 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
/* telephony driver already initialized*/
if (telephony == TRUE)
return;
- telephony_init();
+ telephony_init(adapter);
telephony = TRUE;
return;
}
@@ -896,7 +896,7 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
return;
}
- telephony_exit();
+ telephony_exit(adapter);
telephony = FALSE;
}
diff --git a/audio/telephony.c b/audio/telephony.c
new file mode 100644
index 0000000..4aa3892
--- /dev/null
+++ b/audio/telephony.c
@@ -0,0 +1,529 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2011 Frederic Danis <frederic.danis@intel.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "btio.h"
+#include "log.h"
+#include "device.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "sdp-client.h"
+#include "headset.h"
+#include "telephony.h"
+#include "dbus-common.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
+
+#define DEFAULT_HS_HS_CHANNEL 6
+#define DEFAULT_HF_HS_CHANNEL 7
+
+struct telsrv {
+ GSList *servers; /* server list */
+};
+
+struct tel_device {
+ struct tel_agent *agent;
+ struct audio_device *au_dev;
+ GIOChannel *rfcomm;
+ uint16_t version;
+ uint16_t features;
+};
+
+struct default_agent {
+ char *uuid; /* agent property UUID */
+ uint8_t channel;
+ const char *r_uuid;
+ uint16_t r_class;
+ uint16_t r_profile;
+};
+
+struct tel_agent {
+ char *name; /* agent DBus bus id */
+ char *path; /* agent object path */
+ uint16_t version;
+ uint16_t features;
+ struct default_agent *properties;
+};
+
+static DBusConnection *connection = NULL;
+
+struct telsrv telsrv;
+
+static void free_agent(struct tel_agent *agent)
+{
+ if (agent->name)
+ g_free(agent->name);
+
+ if (agent->path)
+ g_free(agent->path);
+
+ g_free(agent);
+}
+
+static struct tel_agent *find_agent(const char *sender, const char *path,
+ const char *uuid)
+{
+ GSList *l;
+
+ for (l = telsrv.servers; l; l = l->next) {
+ struct tel_agent *agent = l->data;
+
+ if (sender && g_strcmp0(agent->name, sender) != 0)
+ continue;
+
+ if (path && g_strcmp0(agent->path, path) != 0)
+ continue;
+
+ if (uuid && g_strcmp0(agent->properties->uuid, uuid) != 0)
+ continue;
+
+ return agent;
+ }
+
+ return NULL;
+}
+
+static int parse_properties(DBusMessageIter *props, const char **uuid,
+ uint16_t *version, uint16_t *features)
+{
+ gboolean has_uuid = FALSE;
+
+ while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(props, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+ if (strcasecmp(key, "UUID") == 0) {
+ if (var != DBUS_TYPE_STRING)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, uuid);
+ has_uuid = TRUE;
+ } else if (strcasecmp(key, "Version") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, version);
+ } else if (strcasecmp(key, "Features") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, features);
+ }
+
+ dbus_message_iter_next(props);
+ }
+
+ return (has_uuid) ? 0 : -EINVAL;
+}
+
+static int dev_close(struct tel_device *dev)
+{
+ int sock;
+
+ if (dev->rfcomm) {
+ sock = g_io_channel_unix_get_fd(dev->rfcomm);
+ shutdown(sock, SHUT_RDWR);
+ }
+
+ return 0;
+}
+
+static gboolean agent_sendfd(struct tel_device *dev, int fd,
+ DBusPendingCallNotifyFunction notify)
+{
+ struct tel_agent *agent = dev->agent;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict;
+ char *str;
+ DBusPendingCall *call;
+
+ msg = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.TelephonyAgent", "NewConnection");
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ str = g_strdup(agent->properties->uuid);
+ dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &str);
+ g_free(str);
+
+ dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16, &dev->version);
+
+ if (dev->features != 0xFFFF)
+ dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
+ &dev->features);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (dbus_connection_send_with_reply(connection, msg, &call, -1) == FALSE)
+ return FALSE;
+
+ dbus_pending_call_set_notify(call, notify, dev, NULL);
+ dbus_pending_call_unref(call);
+ dbus_message_unref(msg);
+
+ return TRUE;
+}
+
+static gboolean agent_disconnect_cb(GIOChannel *chan, GIOCondition cond,
+ struct tel_device *dev)
+{
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+
+static void newconnection_reply(DBusPendingCall *call, void *user_data)
+{
+ struct tel_device *dev = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+
+ if (!dev->rfcomm) {
+ DBG("RFCOMM disconnected from server before agent reply");
+ goto done;
+ }
+
+ dbus_error_init(&derr);
+ if (!dbus_set_error_from_message(&derr, reply)) {
+ DBG("Agent reply: file descriptor passed successfully");
+ g_io_add_watch(dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) agent_disconnect_cb, dev);
+ headset_slc_complete(dev->au_dev);
+ goto done;
+ }
+
+ DBG("Agent reply: %s", derr.message);
+
+ dbus_error_free(&derr);
+ dev_close(dev);
+ headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct tel_device *dev = user_data;
+ sdp_data_t *sdpdata;
+ uuid_t uuid;
+ sdp_list_t *profiles;
+ sdp_profile_desc_t *desc;
+ int sk, ret;
+
+ if (err < 0) {
+ error("Unable to get service record: %s (%d)", strerror(-err),
+ -err);
+ goto failed;
+ }
+
+ if (!recs || !recs->data) {
+ error("No records found");
+ goto failed;
+ }
+
+ sdpdata = sdp_data_get(recs->data, SDP_ATTR_SUPPORTED_FEATURES);
+ if (sdpdata && sdpdata->dtd == SDP_UINT16)
+ dev->features = sdpdata->val.uint16;
+
+ sdp_uuid16_create(&uuid, dev->agent->properties->r_profile);
+
+ sdp_get_profile_descs(recs->data, &profiles);
+ if (profiles == NULL)
+ goto failed;
+
+ desc = profiles->data;
+
+ if (sdp_uuid16_cmp(&desc->uuid, &uuid) == 0)
+ dev->version = desc->version;
+
+ sdp_list_free(profiles, free);
+
+ sk = g_io_channel_unix_get_fd(dev->rfcomm);
+
+ ret = agent_sendfd(dev, sk, newconnection_reply);
+
+ return;
+
+failed:
+ headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
+}
+
+void *telephony_device_connecting(GIOChannel *io, void *telephony_device)
+{
+ struct audio_device *device = telephony_device;
+ struct tel_device *dev;
+ const char *agent_uuid;
+ struct tel_agent *agent;
+ uuid_t uuid;
+ int err;
+
+ /*TODO: check for HS roles */
+ if (headset_get_hfp_active(device))
+ agent_uuid = HFP_AG_UUID;
+ else
+ agent_uuid = HSP_AG_UUID;
+
+ agent = find_agent(NULL, NULL, agent_uuid);
+ if (agent == NULL) {
+ error("No agent registered for %s", agent_uuid);
+ return NULL;
+ }
+
+ dev = g_new0(struct tel_device, 1);
+ dev->agent = agent;
+ dev->au_dev = telephony_device;
+ dev->rfcomm = io;
+ dev->features = 0xFFFF;
+
+ sdp_uuid16_create(&uuid, agent->properties->r_class);
+
+ err = bt_search_service(&device->src, &device->dst, &uuid,
+ get_record_cb, dev, NULL);
+ if (err < 0) {
+ g_free(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+void telephony_device_connected(void *telephony_device)
+{
+ DBG("telephony-dbus: device %p connected", telephony_device);
+}
+
+void telephony_device_disconnect(void *slc)
+{
+ struct tel_device *dev = slc;
+
+ dev_close(dev);
+}
+
+void telephony_device_disconnected(void *telephony_device)
+{
+ DBG("telephony-dbus: device %p disconnected", telephony_device);
+}
+
+gboolean telephony_get_ready_state(void)
+{
+ return find_agent(NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
+}
+
+uint32_t telephony_get_ag_features(void)
+{
+ return 0;
+}
+
+static struct default_agent default_properties[] = {
+ {HSP_HS_UUID,
+ DEFAULT_HS_HS_CHANNEL,
+ HSP_AG_UUID,
+ HEADSET_AGW_SVCLASS_ID,
+ HEADSET_PROFILE_ID},
+ {HSP_AG_UUID,
+ DEFAULT_HS_AG_CHANNEL,
+ HSP_HS_UUID,
+ HEADSET_SVCLASS_ID,
+ HEADSET_PROFILE_ID},
+ {HFP_HS_UUID,
+ DEFAULT_HF_HS_CHANNEL,
+ HFP_AG_UUID,
+ HANDSFREE_AGW_SVCLASS_ID,
+ HANDSFREE_PROFILE_ID},
+ {HFP_AG_UUID,
+ DEFAULT_HF_AG_CHANNEL,
+ HFP_HS_UUID,
+ HANDSFREE_SVCLASS_ID,
+ HANDSFREE_PROFILE_ID}
+};
+
+static DBusMessage *register_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter args, props;
+ const char *sender, *path, *uuid;
+ uint16_t version = 0;
+ uint16_t features = 0xFFFF;
+ struct tel_agent *agent;
+ int i;
+
+ sender = dbus_message_get_sender(msg);
+
+ dbus_message_iter_init(msg, &args);
+
+ dbus_message_iter_get_basic(&args, &path);
+ dbus_message_iter_next(&args);
+
+ if (find_agent(sender, path, NULL) != NULL)
+ return btd_error_already_exists(msg);
+
+ dbus_message_iter_recurse(&args, &props);
+ if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
+ return btd_error_invalid_args(msg);
+
+ if (parse_properties(&props, &uuid, &version, &features) < 0)
+ return btd_error_invalid_args(msg);
+
+ if (find_agent(NULL, NULL, uuid) != NULL)
+ return btd_error_already_exists(msg);
+
+ /* initialize agent properties */
+ for (i=0 ; i<4; i++) {
+ if (strcasecmp(uuid, default_properties[i].uuid) == 0) {
+ agent = g_new0(struct tel_agent, 1);
+ agent->properties = &default_properties[i];
+ agent->name = g_strdup(sender);
+ agent->path = g_strdup(path);
+ agent->version = version;
+ agent->features = features;
+ break;
+ }
+ }
+
+ if (i == 4)
+ return btd_error_invalid_args(msg);
+
+ DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
+ sender, path, uuid, version, features);
+
+ telsrv.servers = g_slist_append(telsrv.servers, agent);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *sender, *path;
+ struct tel_agent *agent;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ agent = find_agent(sender, path, NULL);
+ if (agent == NULL)
+ return btd_error_does_not_exist(msg);
+
+ telsrv.servers = g_slist_remove(telsrv.servers, agent);
+
+ DBG("Unregister agent : %s%s", sender, path);
+
+ free_agent(agent);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable telsrv_methods[] = {
+ { "RegisterAgent", "oa{sv}", "", register_agent },
+ { "UnregisterAgent", "o", "", unregister_agent },
+ { NULL, NULL, NULL, NULL }
+};
+
+static void path_unregister(void *data)
+{
+ DBG("Unregistered interface %s", AUDIO_TELEPHONY_INTERFACE);
+}
+
+static int register_interface(void *adapter)
+{
+ const char *path;
+
+ if (DBUS_TYPE_UNIX_FD < 0)
+ return -1;
+
+ path = adapter_get_path(adapter);
+
+ if (!g_dbus_register_interface(connection, path,
+ AUDIO_TELEPHONY_INTERFACE,
+ telsrv_methods, NULL,
+ NULL, adapter, path_unregister)) {
+ error("D-Bus failed to register %s interface",
+ AUDIO_TELEPHONY_INTERFACE);
+ return -1;
+ }
+
+ DBG("Registered interface %s", AUDIO_TELEPHONY_INTERFACE);
+
+ return 0;
+}
+
+static void unregister_interface(void *adapter)
+{
+ g_dbus_unregister_interface(connection, adapter_get_path(adapter),
+ AUDIO_TELEPHONY_INTERFACE);
+}
+
+int telephony_init(void *adapter)
+{
+ DBG("");
+
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+ return register_interface(adapter);
+}
+
+void telephony_exit(void *adapter)
+{
+ DBG("");
+
+ unregister_interface(adapter);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/audio/telephony.h b/audio/telephony.h
index 73b390c..7d1d337 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -144,26 +144,13 @@ struct indicator {
/* Notify telephony-*.c of connected/disconnected devices. Implemented by
* telephony-*.c
*/
+void *telephony_device_connecting(GIOChannel *io, void *telephony_device);
void telephony_device_connected(void *telephony_device);
+void telephony_device_disconnect(void *slc);
void telephony_device_disconnected(void *telephony_device);
-/* HF requests (sent by the handsfree device). These are implemented by
- * telephony-*.c
- */
-void telephony_event_reporting_req(void *telephony_device, int ind);
-void telephony_response_and_hold_req(void *telephony_device, int rh);
-void telephony_last_dialed_number_req(void *telephony_device);
-void telephony_terminate_call_req(void *telephony_device);
-void telephony_answer_call_req(void *telephony_device);
-void telephony_dial_number_req(void *telephony_device, const char *number);
-void telephony_transmit_dtmf_req(void *telephony_device, char tone);
-void telephony_subscriber_number_req(void *telephony_device);
-void telephony_list_current_calls_req(void *telephony_device);
-void telephony_operator_selection_req(void *telephony_device);
-void telephony_call_hold_req(void *telephony_device, const char *cmd);
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
-void telephony_voice_dial_req(void *telephony_device, gboolean enable);
-void telephony_key_press_req(void *telephony_device, const char *keys);
+gboolean telephony_get_ready_state(void);
+uint32_t telephony_get_ag_features(void);
/* AG responses to HF requests. These are implemented by headset.c */
int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
@@ -240,5 +227,5 @@ static inline int telephony_get_indicator(const struct indicator *indicators,
return -ENOENT;
}
-int telephony_init(void);
-void telephony_exit(void);
+int telephony_init(void *adapter);
+void telephony_exit(void *adapter);
diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
index cda934c..120d7ea 100644
--- a/doc/assigned-numbers.txt
+++ b/doc/assigned-numbers.txt
@@ -8,6 +8,7 @@ avoid conflicts.
Profile Channel
-----------------------
DUN 1
+HSP HS 6
HFP HF 7
OPP 9
FTP 10
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index b85400b..73d87cc 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -456,3 +456,94 @@ properties boolean Connected [readonly]
uint16 MicrophoneGain [readonly]
The speaker gain when available.
+
+
+Telephony hierarchy [experiemental]
+===================
+
+Service org.bluez
+Interface org.bluez.Telephony
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods void RegisterAgent(object path, dict properties)
+
+ Register a TelephonyAgent to sender, the sender can
+ register as many agents as it likes.
+
+ Note: If the sender disconnects its agents are
+ automatically unregistered.
+
+ possible properties:
+
+ string UUID:
+
+ UUID of the profile which the agent is
+ for.
+
+ uint16 Version:
+
+ Version of the profile which the agent
+ implements.
+
+ uint16 Features:
+
+ Agent supported features as defined in
+ profile spec e.g. HFP.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+
+ void UnregisterAgent(object path)
+
+ Unregister sender agent.
+
+TelephonyAgent hierarchy
+========================
+
+Service unique name
+Interface org.bluez.TelephonyAgent
+Object path freely definable
+
+Methods void NewConnection(filedescriptor fd, dict properties)
+
+ This method gets called whenever a new connection
+ has been established. This method assumes that DBus
+ daemon with file descriptor passing capability is
+ being used.
+
+ The agent should only return successfully once the
+ establishment of the service level connection (SLC)
+ has been completed. In the case of Handsfree this
+ means that BRSF exchange has been performed and
+ necessary initialization has been done.
+
+ possible properties:
+
+ strict Device:
+
+ BlueZ remote device object.
+
+ string UUID:
+
+ Profile UUID of the connection.
+
+ uint16 Version:
+
+ Remote profile version.
+
+ uint16 Features:
+
+ Remote profile features.
+
+ string MediaTransportPath:
+
+ Optional. MediaTransport object path.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void Release()
+
+ This method gets called whenever the service daemon
+ unregisters the agent or whenever the Adapter where
+ the TelephonyAgent registers itself is removed.
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [RFC v3 1/6] audio: Move tel drivers to DBus interface
2011-12-01 15:14 ` [RFC v3 1/6] audio: Move tel drivers to DBus interface Frédéric Danis
@ 2011-12-05 9:00 ` Luiz Augusto von Dentz
2011-12-05 13:31 ` Frederic Danis
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2011-12-05 9:00 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
Hi Frédéric,
2011/12/1 Frédéric Danis <frederic.danis@linux.intel.com>:
> ---
> Makefile.am | 13 +-
> audio/headset.c | 614 ++--------------------------------------------
> audio/headset.h | 2 +
> audio/manager.c | 4 +-
> audio/telephony.c | 529 +++++++++++++++++++++++++++++++++++++++
> audio/telephony.h | 25 +--
> doc/assigned-numbers.txt | 1 +
> doc/audio-api.txt | 91 +++++++
> 8 files changed, 648 insertions(+), 631 deletions(-)
> create mode 100644 audio/telephony.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 07b8626..31c1083 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -154,14 +154,8 @@ builtin_sources += audio/main.c \
> audio/unix.h audio/unix.c \
> audio/media.h audio/media.c \
> audio/transport.h audio/transport.c \
> - audio/telephony.h audio/a2dp-codecs.h
> -builtin_nodist += audio/telephony.c
> -
> -noinst_LIBRARIES += audio/libtelephony.a
> -
> -audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
> - audio/telephony-maemo5.c audio/telephony-ofono.c \
> - audio/telephony-maemo6.c
> + audio/telephony.h audio/telephony.c \
> + audio/a2dp-codecs.h
> endif
>
> if SAPPLUGIN
> @@ -476,9 +470,6 @@ MAINTAINERCLEANFILES = Makefile.in \
> src/builtin.h: src/genbuiltin $(builtin_sources)
> $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
>
> -audio/telephony.c: audio/@TELEPHONY_DRIVER@
> - $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
> -
> sap/sap.c: sap/@SAP_DRIVER@
> $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
>
> diff --git a/audio/headset.c b/audio/headset.c
> index 6aef6a8..74eb7a4 100644
> --- a/audio/headset.c
> +++ b/audio/headset.c
> @@ -70,8 +70,6 @@
> #define HEADSET_GAIN_MICROPHONE 'M'
>
> static struct {
> - gboolean telephony_ready; /* Telephony plugin initialized */
> - uint32_t features; /* HFP AG features */
> const struct indicator *indicators; /* Available HFP indicators */
> int er_mode; /* Event reporting mode */
> int er_ind; /* Event reporting for indicators */
> @@ -81,8 +79,6 @@ static struct {
> guint ring_timer; /* For incoming call indication */
> const char *chld; /* Response to AT+CHLD=? */
> } ag = {
> - .telephony_ready = FALSE,
> - .features = 0,
> .er_mode = 3,
> .er_ind = 0,
> .rh = BTRH_NOT_SUPPORTED,
> @@ -236,40 +232,6 @@ static void print_ag_features(uint32_t features)
> g_free(str);
> }
>
> -static void print_hf_features(uint32_t features)
> -{
> - GString *gstr;
> - char *str;
> -
> - if (features == 0) {
> - DBG("HFP HF features: (none)");
> - return;
> - }
> -
> - gstr = g_string_new("HFP HF features: ");
> -
> - if (features & HF_FEATURE_EC_ANDOR_NR)
> - g_string_append(gstr, "\"EC and/or NR function\" ");
> - if (features & HF_FEATURE_CALL_WAITING_AND_3WAY)
> - g_string_append(gstr, "\"Call waiting and 3-way calling\" ");
> - if (features & HF_FEATURE_CLI_PRESENTATION)
> - g_string_append(gstr, "\"CLI presentation capability\" ");
> - if (features & HF_FEATURE_VOICE_RECOGNITION)
> - g_string_append(gstr, "\"Voice recognition activation\" ");
> - if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL)
> - g_string_append(gstr, "\"Remote volume control\" ");
> - if (features & HF_FEATURE_ENHANCED_CALL_STATUS)
> - g_string_append(gstr, "\"Enhanced call status\" ");
> - if (features & HF_FEATURE_ENHANCED_CALL_CONTROL)
> - g_string_append(gstr, "\"Enhanced call control\" ");
> -
> - str = g_string_free(gstr, FALSE);
> -
> - DBG("%s", str);
> -
> - g_free(str);
> -}
> -
> static const char *state2str(headset_state_t state)
> {
> switch (state) {
> @@ -333,97 +295,6 @@ static int __attribute__((format(printf, 2, 3)))
> return ret;
> }
>
> -static int supported_features(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> - int err;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - slc->hf_features = strtoul(&buf[8], NULL, 10);
> -
> - print_hf_features(slc->hf_features);
> -
> - err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
> - if (err < 0)
> - return err;
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> -static char *indicator_ranges(const struct indicator *indicators)
> -{
> - int i;
> - GString *gstr;
> -
> - gstr = g_string_new("\r\n+CIND: ");
> -
> - for (i = 0; indicators[i].desc != NULL; i++) {
> - if (i == 0)
> - g_string_append_printf(gstr, "(\"%s\",(%s))",
> - indicators[i].desc,
> - indicators[i].range);
> - else
> - g_string_append_printf(gstr, ",(\"%s\",(%s))",
> - indicators[i].desc,
> - indicators[i].range);
> - }
> -
> - g_string_append(gstr, "\r\n");
> -
> - return g_string_free(gstr, FALSE);
> -}
> -
> -static char *indicator_values(const struct indicator *indicators)
> -{
> - int i;
> - GString *gstr;
> -
> - gstr = g_string_new("\r\n+CIND: ");
> -
> - for (i = 0; indicators[i].desc != NULL; i++) {
> - if (i == 0)
> - g_string_append_printf(gstr, "%d", indicators[i].val);
> - else
> - g_string_append_printf(gstr, ",%d", indicators[i].val);
> - }
> -
> - g_string_append(gstr, "\r\n");
> -
> - return g_string_free(gstr, FALSE);
> -}
> -
> -static int report_indicators(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - int err;
> - char *str;
> -
> - if (strlen(buf) < 8)
> - return -EINVAL;
> -
> - if (ag.indicators == NULL) {
> - error("HFP AG indicators not initialized");
> - return headset_send(hs, "\r\nERROR\r\n");
> - }
> -
> - if (buf[7] == '=')
> - str = indicator_ranges(ag.indicators);
> - else
> - str = indicator_values(ag.indicators);
> -
> - err = headset_send(hs, "%s", str);
> -
> - g_free(str);
> -
> - if (err < 0)
> - return err;
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
> {
> struct headset *hs = dev->headset;
> @@ -656,7 +527,7 @@ static int hfp_cmp(struct headset *hs)
> return -1;
> }
>
> -static void hfp_slc_complete(struct audio_device *dev)
> +void headset_slc_complete(struct audio_device *dev)
> {
> struct headset *hs = dev->headset;
> struct pending_connect *p = hs->pending;
> @@ -721,73 +592,10 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
> return 0;
>
> if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
> - ag.features & AG_FEATURE_THREE_WAY_CALLING)
> - return 0;
> -
> - hfp_slc_complete(device);
> -
> - return 0;
> -}
> -
> -static int event_reporting(struct audio_device *dev, const char *buf)
> -{
> - char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */
> -
> - if (strlen(buf) < 13)
> - return -EINVAL;
> -
> - tokens = g_strsplit(&buf[8], ",", 5);
> - if (g_strv_length(tokens) < 4) {
> - g_strfreev(tokens);
> - return -EINVAL;
> - }
> -
> - ag.er_mode = atoi(tokens[0]);
> - ag.er_ind = atoi(tokens[3]);
> -
> - g_strfreev(tokens);
> - tokens = NULL;
> -
> - DBG("Event reporting (CMER): mode=%d, ind=%d",
> - ag.er_mode, ag.er_ind);
> -
> - switch (ag.er_ind) {
> - case 0:
> - case 1:
> - telephony_event_reporting_req(dev, ag.er_ind);
> - break;
> - default:
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> -static int call_hold(struct audio_device *dev, const char *buf)
> -{
> - struct headset *hs = dev->headset;
> - int err;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - if (buf[8] != '?') {
> - telephony_call_hold_req(dev, &buf[8]);
> + telephony_get_ag_features() & AG_FEATURE_THREE_WAY_CALLING)
> return 0;
> - }
>
> - err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
> - if (err < 0)
> - return err;
> -
> - err = headset_send(hs, "\r\nOK\r\n");
> - if (err < 0)
> - return err;
> -
> - if (hs->state != HEADSET_STATE_CONNECTING)
> - return 0;
> -
> - hfp_slc_complete(dev);
> + headset_slc_complete(device);
>
> return 0;
> }
> @@ -797,47 +605,11 @@ int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int key_press(struct audio_device *device, const char *buf)
> -{
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - g_dbus_emit_signal(device->conn, device->path,
> - AUDIO_HEADSET_INTERFACE, "AnswerRequested",
> - DBUS_TYPE_INVALID);
> -
> - if (ag.ring_timer) {
> - g_source_remove(ag.ring_timer);
> - ag.ring_timer = 0;
> - }
> -
> - telephony_key_press_req(device, &buf[8]);
> -
> - return 0;
> -}
> -
> int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int answer_call(struct audio_device *device, const char *buf)
> -{
> - if (ag.ring_timer) {
> - g_source_remove(ag.ring_timer);
> - ag.ring_timer = 0;
> - }
> -
> - if (ag.number) {
> - g_free(ag.number);
> - ag.number = NULL;
> - }
> -
> - telephony_answer_call_req(device);
> -
> - return 0;
> -}
> -
> int telephony_terminate_call_rsp(void *telephony_device,
> cme_error_t err)
> {
> @@ -854,99 +626,21 @@ int telephony_terminate_call_rsp(void *telephony_device,
> return headset_send(hs, "\r\nOK\r\n");
> }
>
> -static int terminate_call(struct audio_device *device, const char *buf)
> -{
> - if (ag.number) {
> - g_free(ag.number);
> - ag.number = NULL;
> - }
> -
> - if (ag.ring_timer) {
> - g_source_remove(ag.ring_timer);
> - ag.ring_timer = 0;
> - }
> -
> - telephony_terminate_call_req(device);
> -
> - return 0;
> -}
> -
> -static int cli_notification(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int response_and_hold(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> -
> - if (strlen(buf) < 8)
> - return -EINVAL;
> -
> - if (ag.rh == BTRH_NOT_SUPPORTED)
> - return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED);
> -
> - if (buf[7] == '=') {
> - telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);
> - return 0;
> - }
> -
> - if (ag.rh >= 0)
> - headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int last_dialed_number(struct audio_device *device, const char *buf)
> -{
> - telephony_last_dialed_number_req(device);
> -
> - return 0;
> -}
> -
> int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int dial_number(struct audio_device *device, const char *buf)
> -{
> - char number[BUF_SIZE];
> - size_t buf_len;
> -
> - buf_len = strlen(buf);
> -
> - if (buf[buf_len - 1] != ';') {
> - DBG("Rejecting non-voice call dial request");
> - return -EINVAL;
> - }
> -
> - memset(number, 0, sizeof(number));
> - strncpy(number, &buf[3], buf_len - 4);
> -
> - telephony_dial_number_req(device, number);
> -
> - return 0;
> -}
> -
> static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
> {
> struct headset *hs = device->headset;
> @@ -994,111 +688,21 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
> return 0;
> }
>
> -static int signal_gain_setting(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - dbus_uint16_t gain;
> - int err;
> -
> - if (strlen(buf) < 8) {
> - error("Too short string for Gain setting");
> - return -EINVAL;
> - }
> -
> - gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
> -
> - err = headset_set_gain(device, gain, buf[5]);
> - if (err < 0 && err != -EALREADY)
> - return err;
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int dtmf_tone(struct audio_device *device, const char *buf)
> -{
> - char tone;
> -
> - if (strlen(buf) < 8) {
> - error("Too short string for DTMF tone");
> - return -EINVAL;
> - }
> -
> - tone = buf[7];
> - if (tone >= '#' && tone <= 'D')
> - telephony_transmit_dtmf_req(device, tone);
> - else
> - return -EINVAL;
> -
> - return 0;
> -}
> -
> int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int subscriber_number(struct audio_device *device, const char *buf)
> -{
> - telephony_subscriber_number_req(device);
> -
> - return 0;
> -}
> -
> int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> }
>
> -static int list_current_calls(struct audio_device *device, const char *buf)
> -{
> - telephony_list_current_calls_req(device);
> -
> - return 0;
> -}
> -
> -static int extended_errors(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - if (buf[8] == '1') {
> - slc->cme_enabled = TRUE;
> - DBG("CME errors enabled for headset %p", hs);
> - } else {
> - slc->cme_enabled = FALSE;
> - DBG("CME errors disabled for headset %p", hs);
> - }
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> -static int call_waiting_notify(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - if (buf[8] == '1') {
> - slc->cwa_enabled = TRUE;
> - DBG("Call waiting notification enabled for headset %p", hs);
> - } else {
> - slc->cwa_enabled = FALSE;
> - DBG("Call waiting notification disabled for headset %p", hs);
> - }
> -
> - return headset_send(hs, "\r\nOK\r\n");
> -}
> -
> int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
> {
> return telephony_generic_rsp(telephony_device, err);
> @@ -1146,108 +750,6 @@ int telephony_operator_selection_ind(int mode, const char *oper)
> return 0;
> }
>
> -static int operator_selection(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> -
> - if (strlen(buf) < 8)
> - return -EINVAL;
> -
> - switch (buf[7]) {
> - case '?':
> - telephony_operator_selection_req(device);
> - break;
> - case '=':
> - return headset_send(hs, "\r\nOK\r\n");
> - default:
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> -static int nr_and_ec(struct audio_device *device, const char *buf)
> -{
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - if (buf[8] == '0')
> - slc->nrec_req = FALSE;
> - else
> - slc->nrec_req = TRUE;
> -
> - telephony_nr_and_ec_req(device, slc->nrec_req);
> -
> - return 0;
> -}
> -
> -static int voice_dial(struct audio_device *device, const char *buf)
> -{
> - gboolean enable;
> -
> - if (strlen(buf) < 9)
> - return -EINVAL;
> -
> - if (buf[8] == '0')
> - enable = FALSE;
> - else
> - enable = TRUE;
> -
> - telephony_voice_dial_req(device, enable);
> -
> - return 0;
> -}
> -
> -static int apple_command(struct audio_device *device, const char *buf)
> -{
> - DBG("Got Apple command: %s", buf);
> -
> - return telephony_generic_rsp(device, CME_ERROR_NONE);
> -}
> -
> -static struct event event_callbacks[] = {
> - { "ATA", answer_call },
> - { "ATD", dial_number },
> - { "AT+VG", signal_gain_setting },
> - { "AT+BRSF", supported_features },
> - { "AT+CIND", report_indicators },
> - { "AT+CMER", event_reporting },
> - { "AT+CHLD", call_hold },
> - { "AT+CHUP", terminate_call },
> - { "AT+CKPD", key_press },
> - { "AT+CLIP", cli_notification },
> - { "AT+BTRH", response_and_hold },
> - { "AT+BLDN", last_dialed_number },
> - { "AT+VTS", dtmf_tone },
> - { "AT+CNUM", subscriber_number },
> - { "AT+CLCC", list_current_calls },
> - { "AT+CMEE", extended_errors },
> - { "AT+CCWA", call_waiting_notify },
> - { "AT+COPS", operator_selection },
> - { "AT+NREC", nr_and_ec },
> - { "AT+BVRA", voice_dial },
> - { "AT+XAPL", apple_command },
> - { "AT+IPHONEACCEV", apple_command },
> - { 0 }
> -};
> -
> -static int handle_event(struct audio_device *device, const char *buf)
> -{
> - struct event *ev;
> -
> - DBG("Received %s", buf);
> -
> - for (ev = event_callbacks; ev->cmd; ev++) {
> - if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
> - return ev->callback(device, buf);
> - }
> -
> - return -EINVAL;
> -}
> -
> static void close_sco(struct audio_device *device)
> {
> struct headset *hs = device->headset;
> @@ -1266,94 +768,6 @@ static void close_sco(struct audio_device *device)
> }
> }
>
> -static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
> - struct audio_device *device)
> -{
> - struct headset *hs;
> - struct headset_slc *slc;
> - unsigned char buf[BUF_SIZE];
> - ssize_t bytes_read;
> - size_t free_space;
> - int fd;
> -
> - if (cond & G_IO_NVAL)
> - return FALSE;
> -
> - hs = device->headset;
> - slc = hs->slc;
> -
> - if (cond & (G_IO_ERR | G_IO_HUP)) {
> - DBG("ERR or HUP on RFCOMM socket");
> - goto failed;
> - }
> -
> - fd = g_io_channel_unix_get_fd(chan);
> -
> - bytes_read = read(fd, buf, sizeof(buf) - 1);
> - if (bytes_read < 0)
> - return TRUE;
> -
> - free_space = sizeof(slc->buf) - slc->data_start -
> - slc->data_length - 1;
> -
> - if (free_space < (size_t) bytes_read) {
> - /* Very likely that the HS is sending us garbage so
> - * just ignore the data and disconnect */
> - error("Too much data to fit incomming buffer");
> - goto failed;
> - }
> -
> - memcpy(&slc->buf[slc->data_start], buf, bytes_read);
> - slc->data_length += bytes_read;
> -
> - /* Make sure the data is null terminated so we can use string
> - * functions */
> - slc->buf[slc->data_start + slc->data_length] = '\0';
> -
> - while (slc->data_length > 0) {
> - char *cr;
> - int err;
> - off_t cmd_len;
> -
> - cr = strchr(&slc->buf[slc->data_start], '\r');
> - if (!cr)
> - break;
> -
> - cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
> - *cr = '\0';
> -
> - if (cmd_len > 1)
> - err = handle_event(device, &slc->buf[slc->data_start]);
> - else
> - /* Silently skip empty commands */
> - err = 0;
> -
> - if (err == -EINVAL) {
> - error("Badly formated or unrecognized command: %s",
> - &slc->buf[slc->data_start]);
> - err = headset_send(hs, "\r\nERROR\r\n");
> - if (err < 0)
> - goto failed;
> - } else if (err < 0)
> - error("Error handling command %s: %s (%d)",
> - &slc->buf[slc->data_start],
> - strerror(-err), -err);
> -
> - slc->data_start += cmd_len;
> - slc->data_length -= cmd_len;
> -
> - if (!slc->data_length)
> - slc->data_start = 0;
> - }
> -
> - return TRUE;
> -
> -failed:
> - headset_set_state(device, HEADSET_STATE_DISCONNECTED);
> -
> - return FALSE;
> -}
> -
> static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
> struct audio_device *device)
> {
> @@ -1381,7 +795,7 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
> }
>
> /* For HFP telephony isn't ready just disconnect */
> - if (hs->hfp_active && !ag.telephony_ready) {
> + if (hs->hfp_active && !telephony_get_ready_state()) {
> error("Unable to accept HFP connection since the telephony "
> "subsystem isn't initialized");
> goto failed;
> @@ -1397,8 +811,7 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
> else
> hs->auto_dc = FALSE;
>
> - g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
> - (GIOFunc) rfcomm_io_cb, dev);
> + hs->slc = telephony_device_connecting(chan, dev);
>
> DBG("%s: Connected to %s", dev->path, hs_address);
>
> @@ -1740,7 +1153,7 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
> else if (hs->state > HEADSET_STATE_CONNECTING)
> return btd_error_already_connected(msg);
>
> - if (hs->hfp_handle && !ag.telephony_ready)
> + if (hs->hfp_handle && !telephony_get_ready_state())
> return btd_error_not_ready(msg);
>
> device->auto_connect = FALSE;
> @@ -2245,7 +1658,7 @@ uint32_t headset_config_init(GKeyFile *config)
>
> /* Use the default values if there is no config file */
> if (config == NULL)
> - return ag.features;
> + return telephony_get_ag_features();
>
> str = g_key_file_get_string(config, "General", "SCORouting",
> &err);
> @@ -2275,7 +1688,7 @@ uint32_t headset_config_init(GKeyFile *config)
> g_free(str);
> }
>
> - return ag.features;
> + return telephony_get_ag_features();
> }
>
> static gboolean hs_dc_timeout(struct audio_device *dev)
> @@ -2518,6 +1931,10 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
> case HEADSET_STATE_DISCONNECTED:
> value = FALSE;
> close_sco(dev);
> +
> + if (dev->headset->slc)
> + telephony_device_disconnect(dev->headset->slc);
> +
> headset_close_rfcomm(dev);
> emit_property_changed(dev->conn, dev->path,
> AUDIO_HEADSET_INTERFACE, "State",
> @@ -2546,7 +1963,8 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
> AUDIO_HEADSET_INTERFACE, "State",
> DBUS_TYPE_STRING, &state_str);
> if (hs->state < state) {
> - if (ag.features & AG_FEATURE_INBAND_RINGTONE)
> + if (telephony_get_ag_features() &
> + AG_FEATURE_INBAND_RINGTONE)
> slc->inband_ring = TRUE;
> else
> slc->inband_ring = FALSE;
> @@ -2880,15 +2298,13 @@ int telephony_ready_ind(uint32_t features,
> const struct indicator *indicators, int rh,
> const char *chld)
> {
> - ag.telephony_ready = TRUE;
> - ag.features = features;
> ag.indicators = indicators;
> ag.rh = rh;
> ag.chld = chld;
>
> DBG("Telephony plugin initialized");
>
> - print_ag_features(ag.features);
> + print_ag_features(telephony_get_ag_features());
>
> return 0;
> }
> diff --git a/audio/headset.h b/audio/headset.h
> index 99eeca8..d43952f 100644
> --- a/audio/headset.h
> +++ b/audio/headset.h
> @@ -111,3 +111,5 @@ gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
> gboolean headset_suspend(struct audio_device *dev, void *data);
> gboolean headset_play(struct audio_device *dev, void *data);
> void headset_shutdown(struct audio_device *dev);
> +
> +void headset_slc_complete(struct audio_device *dev);
> diff --git a/audio/manager.c b/audio/manager.c
> index 8de5515..4624552 100644
> --- a/audio/manager.c
> +++ b/audio/manager.c
> @@ -880,7 +880,7 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
> /* telephony driver already initialized*/
> if (telephony == TRUE)
> return;
> - telephony_init();
> + telephony_init(adapter);
> telephony = TRUE;
> return;
> }
> @@ -896,7 +896,7 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
> return;
> }
>
> - telephony_exit();
> + telephony_exit(adapter);
> telephony = FALSE;
> }
>
> diff --git a/audio/telephony.c b/audio/telephony.c
> new file mode 100644
> index 0000000..4aa3892
> --- /dev/null
> +++ b/audio/telephony.c
> @@ -0,0 +1,529 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2011 Intel Corporation
> + * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
> + * Copyright (C) 2011 Frederic Danis <frederic.danis@intel.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdlib.h>
> +
> +#include <dbus/dbus.h>
> +#include <gdbus.h>
> +
> +#include <bluetooth/bluetooth.h>
> +#include <bluetooth/sdp.h>
> +#include <bluetooth/sdp_lib.h>
> +
> +#include "btio.h"
> +#include "log.h"
> +#include "device.h"
> +#include "error.h"
> +#include "glib-helper.h"
> +#include "sdp-client.h"
> +#include "headset.h"
> +#include "telephony.h"
> +#include "dbus-common.h"
> +#include "../src/adapter.h"
> +#include "../src/device.h"
> +
> +#define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
> +
> +#define DEFAULT_HS_HS_CHANNEL 6
> +#define DEFAULT_HF_HS_CHANNEL 7
> +
> +struct telsrv {
> + GSList *servers; /* server list */
> +};
> +
> +struct tel_device {
> + struct tel_agent *agent;
> + struct audio_device *au_dev;
> + GIOChannel *rfcomm;
> + uint16_t version;
> + uint16_t features;
> +};
> +
> +struct default_agent {
> + char *uuid; /* agent property UUID */
> + uint8_t channel;
> + const char *r_uuid;
> + uint16_t r_class;
> + uint16_t r_profile;
> +};
> +
> +struct tel_agent {
> + char *name; /* agent DBus bus id */
> + char *path; /* agent object path */
> + uint16_t version;
> + uint16_t features;
> + struct default_agent *properties;
> +};
> +
> +static DBusConnection *connection = NULL;
> +
> +struct telsrv telsrv;
> +
> +static void free_agent(struct tel_agent *agent)
> +{
> + if (agent->name)
> + g_free(agent->name);
> +
> + if (agent->path)
> + g_free(agent->path);
You can call g_free directly.
> + g_free(agent);
> +}
> +
> +static struct tel_agent *find_agent(const char *sender, const char *path,
> + const char *uuid)
> +{
> + GSList *l;
> +
> + for (l = telsrv.servers; l; l = l->next) {
> + struct tel_agent *agent = l->data;
> +
> + if (sender && g_strcmp0(agent->name, sender) != 0)
> + continue;
> +
> + if (path && g_strcmp0(agent->path, path) != 0)
> + continue;
> +
> + if (uuid && g_strcmp0(agent->properties->uuid, uuid) != 0)
> + continue;
> +
> + return agent;
> + }
> +
> + return NULL;
> +}
> +
> +static int parse_properties(DBusMessageIter *props, const char **uuid,
> + uint16_t *version, uint16_t *features)
> +{
> + gboolean has_uuid = FALSE;
> +
> + while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
> + const char *key;
> + DBusMessageIter value, entry;
> + int var;
> +
> + dbus_message_iter_recurse(props, &entry);
> + dbus_message_iter_get_basic(&entry, &key);
> +
> + dbus_message_iter_next(&entry);
> + dbus_message_iter_recurse(&entry, &value);
> +
> + var = dbus_message_iter_get_arg_type(&value);
> + if (strcasecmp(key, "UUID") == 0) {
> + if (var != DBUS_TYPE_STRING)
> + return -EINVAL;
> + dbus_message_iter_get_basic(&value, uuid);
> + has_uuid = TRUE;
> + } else if (strcasecmp(key, "Version") == 0) {
> + if (var != DBUS_TYPE_UINT16)
> + return -EINVAL;
> + dbus_message_iter_get_basic(&value, version);
> + } else if (strcasecmp(key, "Features") == 0) {
> + if (var != DBUS_TYPE_UINT16)
> + return -EINVAL;
> + dbus_message_iter_get_basic(&value, features);
> + }
> +
> + dbus_message_iter_next(props);
> + }
> +
> + return (has_uuid) ? 0 : -EINVAL;
> +}
> +
> +static int dev_close(struct tel_device *dev)
> +{
> + int sock;
> +
> + if (dev->rfcomm) {
> + sock = g_io_channel_unix_get_fd(dev->rfcomm);
> + shutdown(sock, SHUT_RDWR);
> + }
> +
> + return 0;
> +}
> +
> +static gboolean agent_sendfd(struct tel_device *dev, int fd,
> + DBusPendingCallNotifyFunction notify)
> +{
> + struct tel_agent *agent = dev->agent;
> + DBusMessage *msg;
> + DBusMessageIter iter, dict;
> + char *str;
> + DBusPendingCall *call;
> +
> + msg = dbus_message_new_method_call(agent->name, agent->path,
> + "org.bluez.TelephonyAgent", "NewConnection");
> +
> + dbus_message_iter_init_append(msg, &iter);
> +
> + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
> +
> + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
> + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
> +
> + str = g_strdup(agent->properties->uuid);
> + dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &str);
> + g_free(str);
> +
> + dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16, &dev->version);
> +
> + if (dev->features != 0xFFFF)
> + dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
> + &dev->features);
> +
> + dbus_message_iter_close_container(&iter, &dict);
> +
> + if (dbus_connection_send_with_reply(connection, msg, &call, -1) == FALSE)
> + return FALSE;
> +
> + dbus_pending_call_set_notify(call, notify, dev, NULL);
> + dbus_pending_call_unref(call);
> + dbus_message_unref(msg);
> +
> + return TRUE;
> +}
> +
> +static gboolean agent_disconnect_cb(GIOChannel *chan, GIOCondition cond,
> + struct tel_device *dev)
> +{
> + if (cond & G_IO_NVAL)
> + return FALSE;
> +
> + headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
> +
> + return FALSE;
> +}
> +
> +static void newconnection_reply(DBusPendingCall *call, void *user_data)
> +{
> + struct tel_device *dev = user_data;
> + DBusMessage *reply = dbus_pending_call_steal_reply(call);
> + DBusError derr;
> +
> + if (!dev->rfcomm) {
> + DBG("RFCOMM disconnected from server before agent reply");
> + goto done;
> + }
> +
> + dbus_error_init(&derr);
> + if (!dbus_set_error_from_message(&derr, reply)) {
> + DBG("Agent reply: file descriptor passed successfully");
> + g_io_add_watch(dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
> + (GIOFunc) agent_disconnect_cb, dev);
> + headset_slc_complete(dev->au_dev);
> + goto done;
> + }
> +
> + DBG("Agent reply: %s", derr.message);
> +
> + dbus_error_free(&derr);
> + dev_close(dev);
> + headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
> +
> +done:
> + dbus_message_unref(reply);
> +}
> +
> +static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
> +{
> + struct tel_device *dev = user_data;
> + sdp_data_t *sdpdata;
> + uuid_t uuid;
> + sdp_list_t *profiles;
> + sdp_profile_desc_t *desc;
> + int sk, ret;
> +
> + if (err < 0) {
> + error("Unable to get service record: %s (%d)", strerror(-err),
> + -err);
> + goto failed;
> + }
> +
> + if (!recs || !recs->data) {
> + error("No records found");
> + goto failed;
> + }
> +
> + sdpdata = sdp_data_get(recs->data, SDP_ATTR_SUPPORTED_FEATURES);
> + if (sdpdata && sdpdata->dtd == SDP_UINT16)
> + dev->features = sdpdata->val.uint16;
> +
> + sdp_uuid16_create(&uuid, dev->agent->properties->r_profile);
> +
> + sdp_get_profile_descs(recs->data, &profiles);
> + if (profiles == NULL)
> + goto failed;
> +
> + desc = profiles->data;
> +
> + if (sdp_uuid16_cmp(&desc->uuid, &uuid) == 0)
> + dev->version = desc->version;
> +
> + sdp_list_free(profiles, free);
> +
> + sk = g_io_channel_unix_get_fd(dev->rfcomm);
> +
> + ret = agent_sendfd(dev, sk, newconnection_reply);
> +
> + return;
> +
> +failed:
> + headset_set_state(dev->au_dev, HEADSET_STATE_DISCONNECTED);
> +}
> +
> +void *telephony_device_connecting(GIOChannel *io, void *telephony_device)
> +{
> + struct audio_device *device = telephony_device;
> + struct tel_device *dev;
> + const char *agent_uuid;
> + struct tel_agent *agent;
> + uuid_t uuid;
> + int err;
> +
> + /*TODO: check for HS roles */
> + if (headset_get_hfp_active(device))
> + agent_uuid = HFP_AG_UUID;
> + else
> + agent_uuid = HSP_AG_UUID;
> +
> + agent = find_agent(NULL, NULL, agent_uuid);
> + if (agent == NULL) {
> + error("No agent registered for %s", agent_uuid);
> + return NULL;
> + }
> +
> + dev = g_new0(struct tel_device, 1);
> + dev->agent = agent;
> + dev->au_dev = telephony_device;
> + dev->rfcomm = io;
> + dev->features = 0xFFFF;
> +
> + sdp_uuid16_create(&uuid, agent->properties->r_class);
> +
> + err = bt_search_service(&device->src, &device->dst, &uuid,
> + get_record_cb, dev, NULL);
> + if (err < 0) {
> + g_free(dev);
> + return NULL;
> + }
> +
> + return dev;
> +}
> +
> +void telephony_device_connected(void *telephony_device)
> +{
> + DBG("telephony-dbus: device %p connected", telephony_device);
> +}
> +
> +void telephony_device_disconnect(void *slc)
> +{
> + struct tel_device *dev = slc;
> +
> + dev_close(dev);
> +}
> +
> +void telephony_device_disconnected(void *telephony_device)
> +{
> + DBG("telephony-dbus: device %p disconnected", telephony_device);
> +}
> +
> +gboolean telephony_get_ready_state(void)
> +{
> + return find_agent(NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
> +}
> +
> +uint32_t telephony_get_ag_features(void)
> +{
> + return 0;
> +}
> +
> +static struct default_agent default_properties[] = {
> + {HSP_HS_UUID,
> + DEFAULT_HS_HS_CHANNEL,
> + HSP_AG_UUID,
> + HEADSET_AGW_SVCLASS_ID,
> + HEADSET_PROFILE_ID},
> + {HSP_AG_UUID,
> + DEFAULT_HS_AG_CHANNEL,
> + HSP_HS_UUID,
> + HEADSET_SVCLASS_ID,
> + HEADSET_PROFILE_ID},
> + {HFP_HS_UUID,
> + DEFAULT_HF_HS_CHANNEL,
> + HFP_AG_UUID,
> + HANDSFREE_AGW_SVCLASS_ID,
> + HANDSFREE_PROFILE_ID},
> + {HFP_AG_UUID,
> + DEFAULT_HF_AG_CHANNEL,
> + HFP_HS_UUID,
> + HANDSFREE_SVCLASS_ID,
> + HANDSFREE_PROFILE_ID}
> +};
> +
> +static DBusMessage *register_agent(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + DBusMessageIter args, props;
> + const char *sender, *path, *uuid;
> + uint16_t version = 0;
> + uint16_t features = 0xFFFF;
> + struct tel_agent *agent;
> + int i;
> +
> + sender = dbus_message_get_sender(msg);
> +
> + dbus_message_iter_init(msg, &args);
> +
> + dbus_message_iter_get_basic(&args, &path);
> + dbus_message_iter_next(&args);
> +
> + if (find_agent(sender, path, NULL) != NULL)
> + return btd_error_already_exists(msg);
> +
> + dbus_message_iter_recurse(&args, &props);
> + if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
> + return btd_error_invalid_args(msg);
> +
> + if (parse_properties(&props, &uuid, &version, &features) < 0)
> + return btd_error_invalid_args(msg);
> +
> + if (find_agent(NULL, NULL, uuid) != NULL)
> + return btd_error_already_exists(msg);
> +
> + /* initialize agent properties */
> + for (i=0 ; i<4; i++) {
> + if (strcasecmp(uuid, default_properties[i].uuid) == 0) {
> + agent = g_new0(struct tel_agent, 1);
> + agent->properties = &default_properties[i];
> + agent->name = g_strdup(sender);
> + agent->path = g_strdup(path);
> + agent->version = version;
> + agent->features = features;
> + break;
> + }
> + }
> +
> + if (i == 4)
> + return btd_error_invalid_args(msg);
I guess you can use sizeof(default_properties)/sizeof(struct
default_agent) to calculate the size of the array, anyway I would
probably split this part in a separate function e.g. agent_new.
> + DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
> + sender, path, uuid, version, features);
> +
> + telsrv.servers = g_slist_append(telsrv.servers, agent);
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static DBusMessage *unregister_agent(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + const char *sender, *path;
> + struct tel_agent *agent;
> +
> + if (!dbus_message_get_args(msg, NULL,
> + DBUS_TYPE_OBJECT_PATH, &path,
> + DBUS_TYPE_INVALID))
> + return NULL;
> +
> + sender = dbus_message_get_sender(msg);
> +
> + agent = find_agent(sender, path, NULL);
> + if (agent == NULL)
> + return btd_error_does_not_exist(msg);
> +
> + telsrv.servers = g_slist_remove(telsrv.servers, agent);
> +
> + DBG("Unregister agent : %s%s", sender, path);
> +
> + free_agent(agent);
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static GDBusMethodTable telsrv_methods[] = {
> + { "RegisterAgent", "oa{sv}", "", register_agent },
> + { "UnregisterAgent", "o", "", unregister_agent },
> + { NULL, NULL, NULL, NULL }
> +};
> +
> +static void path_unregister(void *data)
> +{
> + DBG("Unregistered interface %s", AUDIO_TELEPHONY_INTERFACE);
> +}
> +
> +static int register_interface(void *adapter)
> +{
> + const char *path;
> +
> + if (DBUS_TYPE_UNIX_FD < 0)
> + return -1;
> +
> + path = adapter_get_path(adapter);
> +
> + if (!g_dbus_register_interface(connection, path,
> + AUDIO_TELEPHONY_INTERFACE,
> + telsrv_methods, NULL,
> + NULL, adapter, path_unregister)) {
> + error("D-Bus failed to register %s interface",
> + AUDIO_TELEPHONY_INTERFACE);
> + return -1;
> + }
> +
> + DBG("Registered interface %s", AUDIO_TELEPHONY_INTERFACE);
> +
> + return 0;
> +}
> +
> +static void unregister_interface(void *adapter)
> +{
> + g_dbus_unregister_interface(connection, adapter_get_path(adapter),
> + AUDIO_TELEPHONY_INTERFACE);
> +}
> +
> +int telephony_init(void *adapter)
> +{
> + DBG("");
> +
> + connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
> +
> + return register_interface(adapter);
> +}
> +
> +void telephony_exit(void *adapter)
> +{
> + DBG("");
> +
> + unregister_interface(adapter);
> +
> + dbus_connection_unref(connection);
> + connection = NULL;
> +}
> diff --git a/audio/telephony.h b/audio/telephony.h
> index 73b390c..7d1d337 100644
> --- a/audio/telephony.h
> +++ b/audio/telephony.h
> @@ -144,26 +144,13 @@ struct indicator {
> /* Notify telephony-*.c of connected/disconnected devices. Implemented by
> * telephony-*.c
> */
> +void *telephony_device_connecting(GIOChannel *io, void *telephony_device);
> void telephony_device_connected(void *telephony_device);
> +void telephony_device_disconnect(void *slc);
> void telephony_device_disconnected(void *telephony_device);
>
> -/* HF requests (sent by the handsfree device). These are implemented by
> - * telephony-*.c
> - */
> -void telephony_event_reporting_req(void *telephony_device, int ind);
> -void telephony_response_and_hold_req(void *telephony_device, int rh);
> -void telephony_last_dialed_number_req(void *telephony_device);
> -void telephony_terminate_call_req(void *telephony_device);
> -void telephony_answer_call_req(void *telephony_device);
> -void telephony_dial_number_req(void *telephony_device, const char *number);
> -void telephony_transmit_dtmf_req(void *telephony_device, char tone);
> -void telephony_subscriber_number_req(void *telephony_device);
> -void telephony_list_current_calls_req(void *telephony_device);
> -void telephony_operator_selection_req(void *telephony_device);
> -void telephony_call_hold_req(void *telephony_device, const char *cmd);
> -void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
> -void telephony_voice_dial_req(void *telephony_device, gboolean enable);
> -void telephony_key_press_req(void *telephony_device, const char *keys);
> +gboolean telephony_get_ready_state(void);
> +uint32_t telephony_get_ag_features(void);
>
> /* AG responses to HF requests. These are implemented by headset.c */
> int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
> @@ -240,5 +227,5 @@ static inline int telephony_get_indicator(const struct indicator *indicators,
> return -ENOENT;
> }
>
> -int telephony_init(void);
> -void telephony_exit(void);
> +int telephony_init(void *adapter);
> +void telephony_exit(void *adapter);
> diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
> index cda934c..120d7ea 100644
> --- a/doc/assigned-numbers.txt
> +++ b/doc/assigned-numbers.txt
> @@ -8,6 +8,7 @@ avoid conflicts.
> Profile Channel
> -----------------------
> DUN 1
> +HSP HS 6
Why not HFP HS?
> HFP HF 7
> OPP 9
> FTP 10
> diff --git a/doc/audio-api.txt b/doc/audio-api.txt
> index b85400b..73d87cc 100644
> --- a/doc/audio-api.txt
> +++ b/doc/audio-api.txt
> @@ -456,3 +456,94 @@ properties boolean Connected [readonly]
> uint16 MicrophoneGain [readonly]
>
> The speaker gain when available.
> +
> +
> +Telephony hierarchy [experiemental]
> +===================
> +
> +Service org.bluez
> +Interface org.bluez.Telephony
> +Object path [variable prefix]/{hci0,hci1,...}
> +
> +Methods void RegisterAgent(object path, dict properties)
> +
> + Register a TelephonyAgent to sender, the sender can
> + register as many agents as it likes.
> +
> + Note: If the sender disconnects its agents are
> + automatically unregistered.
> +
> + possible properties:
> +
> + string UUID:
> +
> + UUID of the profile which the agent is
> + for.
> +
> + uint16 Version:
> +
> + Version of the profile which the agent
> + implements.
> +
> + uint16 Features:
> +
> + Agent supported features as defined in
> + profile spec e.g. HFP.
> +
> + Possible Errors: org.bluez.Error.InvalidArguments
> +
> +
> + void UnregisterAgent(object path)
> +
> + Unregister sender agent.
> +
> +TelephonyAgent hierarchy
> +========================
> +
> +Service unique name
> +Interface org.bluez.TelephonyAgent
> +Object path freely definable
> +
> +Methods void NewConnection(filedescriptor fd, dict properties)
> +
> + This method gets called whenever a new connection
> + has been established. This method assumes that DBus
> + daemon with file descriptor passing capability is
> + being used.
> +
> + The agent should only return successfully once the
> + establishment of the service level connection (SLC)
> + has been completed. In the case of Handsfree this
> + means that BRSF exchange has been performed and
> + necessary initialization has been done.
> +
> + possible properties:
> +
> + strict Device:
> +
> + BlueZ remote device object.
> +
> + string UUID:
> +
> + Profile UUID of the connection.
> +
> + uint16 Version:
> +
> + Remote profile version.
> +
> + uint16 Features:
> +
> + Remote profile features.
> +
> + string MediaTransportPath:
> +
> + Optional. MediaTransport object path.
> +
> + Possible Errors: org.bluez.Error.InvalidArguments
> + org.bluez.Error.Failed
> +
> + void Release()
> +
> + This method gets called whenever the service daemon
> + unregisters the agent or whenever the Adapter where
> + the TelephonyAgent registers itself is removed.
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC v3 1/6] audio: Move tel drivers to DBus interface
2011-12-05 9:00 ` Luiz Augusto von Dentz
@ 2011-12-05 13:31 ` Frederic Danis
0 siblings, 0 replies; 9+ messages in thread
From: Frederic Danis @ 2011-12-05 13:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
Hello Luiz,
Le 05/12/2011 10:00, Luiz Augusto von Dentz a écrit :
> Hi Frédéric,
>
> 2011/12/1 Frédéric Danis<frederic.danis@linux.intel.com>:
>> +static void free_agent(struct tel_agent *agent)
>> +{
>> + if (agent->name)
>> + g_free(agent->name);
>> +
>> + if (agent->path)
>> + g_free(agent->path);
>
> You can call g_free directly.
OK
>> + g_free(agent);
>> +}
>> +
>> + if (find_agent(NULL, NULL, uuid) != NULL)
>> + return btd_error_already_exists(msg);
>> +
>> + /* initialize agent properties */
>> + for (i=0 ; i<4; i++) {
>> + if (strcasecmp(uuid, default_properties[i].uuid) == 0) {
>> + agent = g_new0(struct tel_agent, 1);
>> + agent->properties =&default_properties[i];
>> + agent->name = g_strdup(sender);
>> + agent->path = g_strdup(path);
>> + agent->version = version;
>> + agent->features = features;
>> + break;
>> + }
>> + }
>> +
>> + if (i == 4)
>> + return btd_error_invalid_args(msg);
>
> I guess you can use sizeof(default_properties)/sizeof(struct
> default_agent) to calculate the size of the array, anyway I would
> probably split this part in a separate function e.g. agent_new.
OK
>> + DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
>> + sender, path, uuid, version, features);
>> +
>> + telsrv.servers = g_slist_append(telsrv.servers, agent);
>> +
>> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
>> +}
>> +
>> diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
>> index cda934c..120d7ea 100644
>> --- a/doc/assigned-numbers.txt
>> +++ b/doc/assigned-numbers.txt
>> @@ -8,6 +8,7 @@ avoid conflicts.
>> Profile Channel
>> -----------------------
>> DUN 1
>> +HSP HS 6
>
> Why not HFP HS?
>
>> HFP HF 7
>> OPP 9
>> FTP 10
I am not sure to understand your comment as I do not touch HFP assigned
numbers. In HFP specification, roles are Hands-Free unit (HFP HF) and
Audio Gateway (HFP AG).
Regards
Fred
--
Frederic Danis Open Source Technology Centre
frederic.danis@intel.com Intel Corporation
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC v3 2/6] audio: Remove tel drivers
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
2011-12-01 15:14 ` [RFC v3 1/6] audio: Move tel drivers to DBus interface Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
2011-12-01 15:14 ` [RFC v3 3/6] audio: Remove maemo5 tel driver Frédéric Danis
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
Makefile.am | 4 +-
audio/headset.c | 913 +--------------------------
audio/headset.h | 5 -
audio/telephony-dummy.c | 433 -------------
audio/telephony-ofono.c | 1638 -----------------------------------------------
audio/telephony.h | 171 -----
audio/transport.c | 10 +
audio/unix.c | 2 +
8 files changed, 16 insertions(+), 3160 deletions(-)
delete mode 100644 audio/telephony-dummy.c
delete mode 100644 audio/telephony-ofono.c
diff --git a/Makefile.am b/Makefile.am
index 31c1083..9a29eb1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -335,9 +335,7 @@ endif
EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
src/main.conf network/network.conf \
input/input.conf serial/serial.conf \
- audio/audio.conf audio/telephony-dummy.c \
- audio/telephony-maemo5.c audio/telephony-ofono.c \
- audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
+ audio/audio.conf sap/sap-dummy.c sap/sap-u8500.c \
proximity/proximity.conf
if ALSA
diff --git a/audio/headset.c b/audio/headset.c
index 74eb7a4..028df16 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -62,35 +62,7 @@
#define DC_TIMEOUT 3
-#define RING_INTERVAL 3
-
-#define BUF_SIZE 1024
-
-#define HEADSET_GAIN_SPEAKER 'S'
-#define HEADSET_GAIN_MICROPHONE 'M'
-
-static struct {
- const struct indicator *indicators; /* Available HFP indicators */
- int er_mode; /* Event reporting mode */
- int er_ind; /* Event reporting for indicators */
- int rh; /* Response and Hold state */
- char *number; /* Incoming phone number */
- int number_type; /* Incoming number type */
- guint ring_timer; /* For incoming call indication */
- const char *chld; /* Response to AT+CHLD=? */
-} ag = {
- .er_mode = 3,
- .er_ind = 0,
- .rh = BTRH_NOT_SUPPORTED,
- .number = NULL,
- .number_type = 0,
- .ring_timer = 0,
-};
-
static gboolean sco_hci = TRUE;
-static gboolean fast_connectable = FALSE;
-
-static GSList *active_devices = NULL;
static char *str_state[] = {
"HEADSET_STATE_DISCONNECTED",
@@ -128,25 +100,6 @@ struct pending_connect {
uint16_t svclass;
};
-struct headset_slc {
- char buf[BUF_SIZE];
- int data_start;
- int data_length;
-
- gboolean cli_active;
- gboolean cme_enabled;
- gboolean cwa_enabled;
- gboolean pending_ring;
- gboolean inband_ring;
- gboolean nrec;
- gboolean nrec_req;
-
- int sp_gain;
- int mic_gain;
-
- unsigned int hf_features;
-};
-
struct headset {
uint32_t hsp_handle;
uint32_t hfp_handle;
@@ -170,15 +123,10 @@ struct headset {
struct pending_connect *pending;
headset_lock_t lock;
- struct headset_slc *slc;
+ void *slc;
GSList *nrec_cbs;
};
-struct event {
- const char *cmd;
- int (*callback) (struct audio_device *device, const char *buf);
-};
-
static GSList *headset_callbacks = NULL;
static void error_connect_failed(DBusConnection *conn, DBusMessage *msg,
@@ -194,44 +142,6 @@ static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
static int get_records(struct audio_device *device, headset_stream_cb_t cb,
void *user_data, unsigned int *cb_id);
-static void print_ag_features(uint32_t features)
-{
- GString *gstr;
- char *str;
-
- if (features == 0) {
- DBG("HFP AG features: (none)");
- return;
- }
-
- gstr = g_string_new("HFP AG features: ");
-
- if (features & AG_FEATURE_THREE_WAY_CALLING)
- g_string_append(gstr, "\"Three-way calling\" ");
- if (features & AG_FEATURE_EC_ANDOR_NR)
- g_string_append(gstr, "\"EC and/or NR function\" ");
- if (features & AG_FEATURE_VOICE_RECOGNITION)
- g_string_append(gstr, "\"Voice recognition function\" ");
- if (features & AG_FEATURE_INBAND_RINGTONE)
- g_string_append(gstr, "\"In-band ring tone capability\" ");
- if (features & AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG)
- g_string_append(gstr, "\"Attach a number to a voice tag\" ");
- if (features & AG_FEATURE_REJECT_A_CALL)
- g_string_append(gstr, "\"Ability to reject a call\" ");
- if (features & AG_FEATURE_ENHANCED_CALL_STATUS)
- g_string_append(gstr, "\"Enhanced call status\" ");
- if (features & AG_FEATURE_ENHANCED_CALL_CONTROL)
- g_string_append(gstr, "\"Enhanced call control\" ");
- if (features & AG_FEATURE_EXTENDED_ERROR_RESULT_CODES)
- g_string_append(gstr, "\"Extended Error Result Codes\" ");
-
- str = g_string_free(gstr, FALSE);
-
- DBG("%s", str);
-
- g_free(str);
-}
-
static const char *state2str(headset_state_t state)
{
switch (state) {
@@ -249,52 +159,6 @@ static const char *state2str(headset_state_t state)
return NULL;
}
-static int headset_send_valist(struct headset *hs, char *format, va_list ap)
-{
- char rsp[BUF_SIZE];
- ssize_t total_written, count;
- int fd;
-
- count = vsnprintf(rsp, sizeof(rsp), format, ap);
-
- if (count < 0)
- return -EINVAL;
-
- if (!hs->rfcomm) {
- error("headset_send: the headset is not connected");
- return -EIO;
- }
-
- total_written = 0;
- fd = g_io_channel_unix_get_fd(hs->rfcomm);
-
- while (total_written < count) {
- ssize_t written;
-
- written = write(fd, rsp + total_written,
- count - total_written);
- if (written < 0)
- return -errno;
-
- total_written += written;
- }
-
- return 0;
-}
-
-static int __attribute__((format(printf, 2, 3)))
- headset_send(struct headset *hs, char *format, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, format);
- ret = headset_send_valist(hs, format, ap);
- va_end(ap);
-
- return ret;
-}
-
static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -375,64 +239,11 @@ static unsigned int connect_cb_new(struct headset *hs,
return cb->id;
}
-static void __attribute__((format(printf, 3, 4)))
- send_foreach_headset(GSList *devices,
- int (*cmp) (struct headset *hs),
- char *format, ...)
-{
- GSList *l;
- va_list ap;
-
- for (l = devices; l != NULL; l = l->next) {
- struct audio_device *device = l->data;
- struct headset *hs = device->headset;
- int ret;
-
- assert(hs != NULL);
-
- if (cmp && cmp(hs) != 0)
- continue;
-
- va_start(ap, format);
- ret = headset_send_valist(hs, format, ap);
- if (ret < 0)
- error("Failed to send to headset: %s (%d)",
- strerror(-ret), -ret);
- va_end(ap);
- }
-}
-
-static int cli_cmp(struct headset *hs)
-{
- struct headset_slc *slc = hs->slc;
-
- if (!hs->hfp_active)
- return -1;
-
- if (slc->cli_active)
- return 0;
- else
- return -1;
-}
-
-static gboolean ring_timer_cb(gpointer data)
-{
- send_foreach_headset(active_devices, NULL, "\r\nRING\r\n");
-
- if (ag.number)
- send_foreach_headset(active_devices, cli_cmp,
- "\r\n+CLIP: \"%s\",%d\r\n",
- ag.number, ag.number_type);
-
- return TRUE;
-}
-
static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
int sk;
struct audio_device *dev = user_data;
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
struct pending_connect *p = hs->pending;
if (err) {
@@ -473,14 +284,6 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
fcntl(sk, F_SETFL, 0);
headset_set_state(dev, HEADSET_STATE_PLAYING);
-
- if (slc->pending_ring) {
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
- ring_timer_cb,
- NULL);
- slc->pending_ring = FALSE;
- }
}
static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
@@ -519,14 +322,6 @@ static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
return 0;
}
-static int hfp_cmp(struct headset *hs)
-{
- if (hs->hfp_active)
- return 0;
- else
- return -1;
-}
-
void headset_slc_complete(struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -556,200 +351,6 @@ void headset_slc_complete(struct audio_device *dev)
}
}
-static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if ((err != CME_ERROR_NONE) && slc->cme_enabled)
- return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
-
- switch (err) {
- case CME_ERROR_NONE:
- return headset_send(hs, "\r\nOK\r\n");
- case CME_ERROR_NO_NETWORK_SERVICE:
- return headset_send(hs, "\r\nNO CARRIER\r\n");
- default:
- return headset_send(hs, "\r\nERROR\r\n");
- }
-}
-
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- int ret;
-
- if (err != CME_ERROR_NONE)
- return telephony_generic_rsp(telephony_device, err);
-
- ret = headset_send(hs, "\r\nOK\r\n");
- if (ret < 0)
- return ret;
-
- if (hs->state != HEADSET_STATE_CONNECTING)
- return 0;
-
- if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
- telephony_get_ag_features() & AG_FEATURE_THREE_WAY_CALLING)
- return 0;
-
- headset_slc_complete(device);
-
- return 0;
-}
-
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_terminate_call_rsp(void *telephony_device,
- cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
-
- if (err != CME_ERROR_NONE)
- return telephony_generic_rsp(telephony_device, err);
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, "CallTerminated",
- DBUS_TYPE_INVALID);
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- const char *name, *property;
-
- if (gain > 15) {
- error("Invalid gain value: %u", gain);
- return -EINVAL;
- }
-
- switch (type) {
- case HEADSET_GAIN_SPEAKER:
- if (slc->sp_gain == gain) {
- DBG("Ignoring no-change in speaker gain");
- return -EALREADY;
- }
- name = "SpeakerGainChanged";
- property = "SpeakerGain";
- slc->sp_gain = gain;
- break;
- case HEADSET_GAIN_MICROPHONE:
- if (slc->mic_gain == gain) {
- DBG("Ignoring no-change in microphone gain");
- return -EALREADY;
- }
- name = "MicrophoneGainChanged";
- property = "MicrophoneGain";
- slc->mic_gain = gain;
- break;
- default:
- error("Unknown gain setting");
- return -EINVAL;
- }
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, name,
- DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- emit_property_changed(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, property,
- DBUS_TYPE_UINT16, &gain);
-
- return 0;
-}
-
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (err == CME_ERROR_NONE) {
- GSList *l;
-
- for (l = hs->nrec_cbs; l; l = l->next) {
- struct headset_nrec_callback *nrec_cb = l->data;
-
- nrec_cb->cb(device, slc->nrec_req, nrec_cb->user_data);
- }
-
- slc->nrec = hs->slc->nrec_req;
- }
-
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_ind(int mode, const char *oper)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+COPS: %d,0,\"%s\"\r\n",
- mode, oper);
- return 0;
-}
-
static void close_sco(struct audio_device *device)
{
struct headset *hs = device->headset;
@@ -815,11 +416,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
DBG("%s: Connected to %s", dev->path, hs_address);
- hs->slc = g_new0(struct headset_slc, 1);
- hs->slc->sp_gain = 15;
- hs->slc->mic_gain = 15;
- hs->slc->nrec = TRUE;
-
/* In HFP mode wait for Service Level Connection */
if (hs->hfp_active)
return;
@@ -1169,63 +765,6 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
-static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply = NULL;
- int err;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (ag.ring_timer) {
- DBG("IndicateCall received when already indicating");
- return reply;
- }
-
- err = headset_send(hs, "\r\nRING\r\n");
- if (err < 0) {
- dbus_message_unref(reply);
- return btd_error_failed(msg, strerror(-err));
- }
-
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
- NULL);
-
- return reply;
-}
-
-static DBusMessage *hs_cancel_call(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply = NULL;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- } else
- DBG("Got CancelCall method call but no call is active");
-
- return reply;
-}
-
static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1265,114 +804,6 @@ static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
-static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->sp_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->mic_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *hs_set_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data, uint16_t gain,
- char type)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply;
- int err;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- err = headset_set_gain(device, gain, type);
- if (err < 0)
- return btd_error_invalid_args(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (hs->state == HEADSET_STATE_PLAYING) {
- err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
- if (err < 0) {
- dbus_message_unref(reply);
- return btd_error_failed(msg, strerror(-err));
- }
- }
-
- return reply;
-}
-
-static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
-}
-
-static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
-}
-
static DBusMessage *hs_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1408,20 +839,6 @@ static DBusMessage *hs_get_properties(DBusConnection *conn,
value = (device->headset->state >= HEADSET_STATE_CONNECTED);
dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
- if (!value)
- goto done;
-
- /* SpeakerGain */
- dict_append_entry(&dict, "SpeakerGain",
- DBUS_TYPE_UINT16,
- &device->headset->slc->sp_gain);
-
- /* MicrophoneGain */
- dict_append_entry(&dict, "MicrophoneGain",
- DBUS_TYPE_UINT16,
- &device->headset->slc->mic_gain);
-
-done:
dbus_message_iter_close_container(&iter, &dict);
return reply;
@@ -1433,7 +850,8 @@ static DBusMessage *hs_set_property(DBusConnection *conn,
const char *property;
DBusMessageIter iter;
DBusMessageIter sub;
- uint16_t gain;
+
+ //TODO: Should be removed ?
if (!dbus_message_iter_init(msg, &iter))
return btd_error_invalid_args(msg);
@@ -1448,22 +866,6 @@ static DBusMessage *hs_set_property(DBusConnection *conn,
return btd_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &sub);
- if (g_str_equal("SpeakerGain", property)) {
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &gain);
- return hs_set_gain(conn, msg, data, gain,
- HEADSET_GAIN_SPEAKER);
- } else if (g_str_equal("MicrophoneGain", property)) {
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &gain);
- return hs_set_gain(conn, msg, data, gain,
- HEADSET_GAIN_MICROPHONE);
- }
-
return btd_error_invalid_args(msg);
}
@@ -1472,36 +874,18 @@ static GDBusMethodTable headset_methods[] = {
G_DBUS_METHOD_FLAG_ASYNC },
{ "Disconnect", "", "", hs_disconnect },
{ "IsConnected", "", "b", hs_is_connected },
- { "IndicateCall", "", "", hs_ring },
- { "CancelCall", "", "", hs_cancel_call },
{ "Play", "", "", hs_play,
G_DBUS_METHOD_FLAG_ASYNC |
G_DBUS_METHOD_FLAG_DEPRECATED },
{ "Stop", "", "", hs_stop },
{ "IsPlaying", "", "b", hs_is_playing,
G_DBUS_METHOD_FLAG_DEPRECATED },
- { "GetSpeakerGain", "", "q", hs_get_speaker_gain,
- G_DBUS_METHOD_FLAG_DEPRECATED },
- { "GetMicrophoneGain", "", "q", hs_get_mic_gain,
- G_DBUS_METHOD_FLAG_DEPRECATED },
- { "SetSpeakerGain", "q", "", hs_set_speaker_gain,
- G_DBUS_METHOD_FLAG_DEPRECATED },
- { "SetMicrophoneGain", "q", "", hs_set_mic_gain,
- G_DBUS_METHOD_FLAG_DEPRECATED },
{ "GetProperties", "", "a{sv}",hs_get_properties },
{ "SetProperty", "sv", "", hs_set_property },
{ NULL, NULL, NULL, NULL }
};
static GDBusSignalTable headset_signals[] = {
- { "Connected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "Disconnected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "AnswerRequested", "" },
- { "Stopped", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "Playing", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "SpeakerGainChanged", "q", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "MicrophoneGainChanged", "q", G_DBUS_SIGNAL_FLAG_DEPRECATED },
- { "CallTerminated", "" },
{ "PropertyChanged", "sv" },
{ NULL, NULL }
};
@@ -1675,19 +1059,6 @@ uint32_t headset_config_init(GKeyFile *config)
g_free(str);
}
- /* Init fast connectable option */
- str = g_key_file_get_string(config, "Headset", "FastConnectable",
- &err);
- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- fast_connectable = strcmp(str, "true") == 0;
- if (fast_connectable)
- manager_set_fast_connectable(FALSE);
- g_free(str);
- }
-
return telephony_get_ag_features();
}
@@ -1895,28 +1266,18 @@ int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
{
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
if (hs->sco)
return -EISCONN;
hs->sco = g_io_channel_ref(io);
- if (slc->pending_ring) {
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
- ring_timer_cb,
- NULL);
- slc->pending_ring = FALSE;
- }
-
return 0;
}
void headset_set_state(struct audio_device *dev, headset_state_t state)
{
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
gboolean value;
const char *state_str;
headset_state_t old_state = hs->state;
@@ -1939,17 +1300,12 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Disconnected",
- DBUS_TYPE_INVALID);
if (hs->state > HEADSET_STATE_CONNECTING) {
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "Connected",
DBUS_TYPE_BOOLEAN, &value);
telephony_device_disconnected(dev);
}
- active_devices = g_slist_remove(active_devices, dev);
break;
case HEADSET_STATE_CONNECTING:
emit_property_changed(dev->conn, dev->path,
@@ -1963,28 +1319,14 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
if (hs->state < state) {
- if (telephony_get_ag_features() &
- AG_FEATURE_INBAND_RINGTONE)
- slc->inband_ring = TRUE;
- else
- slc->inband_ring = FALSE;
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Connected",
- DBUS_TYPE_INVALID);
value = TRUE;
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE,
"Connected",
DBUS_TYPE_BOOLEAN, &value);
- active_devices = g_slist_append(active_devices, dev);
telephony_device_connected(dev);
} else if (hs->state == HEADSET_STATE_PLAYING) {
value = FALSE;
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Stopped",
- DBUS_TYPE_INVALID);
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE,
"Playing",
@@ -2005,17 +1347,9 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
G_IO_ERR | G_IO_NVAL,
(GIOFunc) sco_cb, dev);
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE, "Playing",
- DBUS_TYPE_INVALID);
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "Playing",
DBUS_TYPE_BOOLEAN, &value);
-
- if (slc->sp_gain >= 0)
- headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain);
- if (slc->mic_gain >= 0)
- headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain);
break;
}
@@ -2120,60 +1454,6 @@ int headset_get_sco_fd(struct audio_device *dev)
return g_io_channel_unix_get_fd(hs->sco);
}
-gboolean headset_get_nrec(struct audio_device *dev)
-{
- struct headset *hs = dev->headset;
-
- if (!hs->slc)
- return TRUE;
-
- return hs->slc->nrec;
-}
-
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
- headset_nrec_cb cb, void *user_data)
-{
- struct headset *hs = dev->headset;
- struct headset_nrec_callback *nrec_cb;
- static unsigned int id = 0;
-
- nrec_cb = g_new(struct headset_nrec_callback, 1);
- nrec_cb->cb = cb;
- nrec_cb->user_data = user_data;
- nrec_cb->id = ++id;
-
- hs->nrec_cbs = g_slist_prepend(hs->nrec_cbs, nrec_cb);
-
- return nrec_cb->id;
-}
-
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id)
-{
- struct headset *hs = dev->headset;
- GSList *l;
-
- for (l = hs->nrec_cbs; l != NULL; l = l->next) {
- struct headset_nrec_callback *cb = l->data;
- if (cb && cb->id == id) {
- hs->nrec_cbs = g_slist_remove(hs->nrec_cbs, cb);
- g_free(cb);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-gboolean headset_get_inband(struct audio_device *dev)
-{
- struct headset *hs = dev->headset;
-
- if (!hs->slc)
- return TRUE;
-
- return hs->slc->inband_ring;
-}
-
gboolean headset_get_sco_hci(struct audio_device *dev)
{
return sco_hci;
@@ -2190,193 +1470,6 @@ void headset_shutdown(struct audio_device *dev)
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
}
-int telephony_event_ind(int index)
-{
- if (!active_devices)
- return -ENODEV;
-
- if (!ag.er_ind) {
- DBG("telephony_report_event called but events are disabled");
- return -EINVAL;
- }
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CIEV: %d,%d\r\n", index + 1,
- ag.indicators[index].val);
-
- return 0;
-}
-
-int telephony_response_and_hold_ind(int rh)
-{
- if (!active_devices)
- return -ENODEV;
-
- ag.rh = rh;
-
- /* If we aren't in any response and hold state don't send anything */
- if (ag.rh < 0)
- return 0;
-
- send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n",
- ag.rh);
-
- return 0;
-}
-
-int telephony_incoming_call_ind(const char *number, int type)
-{
- struct audio_device *dev;
- struct headset *hs;
- struct headset_slc *slc;
-
- if (fast_connectable)
- manager_set_fast_connectable(TRUE);
-
- if (!active_devices)
- return -ENODEV;
-
- /* Get the latest connected device */
- dev = active_devices->data;
- hs = dev->headset;
- slc = hs->slc;
-
- if (ag.ring_timer) {
- DBG("telephony_incoming_call_ind: already calling");
- return -EBUSY;
- }
-
- /* With HSP 1.2 the RING messages should *not* be sent if inband
- * ringtone is being used */
- if (!hs->hfp_active && slc->inband_ring)
- return 0;
-
- g_free(ag.number);
- ag.number = g_strdup(number);
- ag.number_type = type;
-
- if (slc->inband_ring && hs->hfp_active &&
- hs->state != HEADSET_STATE_PLAYING) {
- slc->pending_ring = TRUE;
- return 0;
- }
-
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
- NULL);
-
- return 0;
-}
-
-int telephony_calling_stopped_ind(void)
-{
- struct audio_device *dev;
-
- if (fast_connectable)
- manager_set_fast_connectable(FALSE);
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- if (!active_devices)
- return 0;
-
- /* In case SCO isn't fully up yet */
- dev = active_devices->data;
-
- if (!dev->headset->slc->pending_ring && !ag.ring_timer)
- return -EINVAL;
-
- dev->headset->slc->pending_ring = FALSE;
-
- return 0;
-}
-
-int telephony_ready_ind(uint32_t features,
- const struct indicator *indicators, int rh,
- const char *chld)
-{
- ag.indicators = indicators;
- ag.rh = rh;
- ag.chld = chld;
-
- DBG("Telephony plugin initialized");
-
- print_ag_features(telephony_get_ag_features());
-
- return 0;
-}
-
-int telephony_deinit(void)
-{
- g_free(ag.number);
-
- memset(&ag, 0, sizeof(ag));
-
- ag.er_mode = 3;
- ag.rh = BTRH_NOT_SUPPORTED;
-
- DBG("Telephony deinitialized");
-
- return 0;
-}
-
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
- int mprty, const char *number,
- int type)
-{
- if (!active_devices)
- return -ENODEV;
-
- if (number && strlen(number) > 0)
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
- idx, dir, status, mode, mprty, number, type);
- else
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CLCC: %d,%d,%d,%d,%d\r\n",
- idx, dir, status, mode, mprty);
-
- return 0;
-}
-
-int telephony_subscriber_number_ind(const char *number, int type, int service)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CNUM: ,%s,%d,,%d\r\n",
- number, type, service);
-
- return 0;
-}
-
-static int cwa_cmp(struct headset *hs)
-{
- if (!hs->hfp_active)
- return -1;
-
- if (hs->slc->cwa_enabled)
- return 0;
- else
- return -1;
-}
-
-int telephony_call_waiting_ind(const char *number, int type)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, cwa_cmp,
- "\r\n+CCWA: \"%s\",%d\r\n",
- number, type);
-
- return 0;
-}
-
unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data)
{
struct headset_state_callback *state_cb;
diff --git a/audio/headset.h b/audio/headset.h
index d43952f..6bf352c 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -96,11 +96,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state);
int headset_get_channel(struct audio_device *dev);
int headset_get_sco_fd(struct audio_device *dev);
-gboolean headset_get_nrec(struct audio_device *dev);
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
- headset_nrec_cb cb, void *user_data);
-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);
gboolean headset_is_active(struct audio_device *dev);
diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
deleted file mode 100644
index 1f89079..0000000
--- a/audio/telephony-dummy.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2006-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-#define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
-#define TELEPHONY_DUMMY_PATH "/org/bluez/test"
-
-static DBusConnection *connection = NULL;
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-static char *active_call_number = NULL;
-static int active_call_status = 0;
-static int active_call_dir = 0;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator dummy_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 5, TRUE },
- { "service", "0,1", 1, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-void telephony_device_connected(void *telephony_device)
-{
- DBG("telephony-dummy: device %p connected", telephony_device);
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-dummy: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
-
- /* Notify outgoing call set-up successfully initiated */
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- g_free(active_call_number);
- active_call_number = NULL;
-
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-
- if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- else
- telephony_update_indicator(dummy_indicators, "call",
- EV_CALL_INACTIVE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-
- telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
-
- active_call_status = CALL_STATUS_ACTIVE;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- DBG("telephony-dummy: dial request to %s", active_call_number);
-
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
- /* Notify outgoing call set-up successfully initiated */
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- DBG("telephony-dummy: transmit dtmf: %c", tone);
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-dummy: subscriber number request");
- if (subscriber_number)
- telephony_subscriber_number_ind(subscriber_number,
- NUMBER_TYPE_TELEPHONY,
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- DBG("telephony-dummy: list current calls request");
- if (active_call_number)
- telephony_list_current_call_ind(1, active_call_dir,
- active_call_status,
- CALL_MODE_VOICE,
- CALL_MULTIPARTY_NO,
- active_call_number,
- NUMBER_TYPE_TELEPHONY);
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- DBG("telephony-dymmy: got call hold request %s", cmd);
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-dummy: got %s NR and EC request",
- enable ? "enable" : "disable");
-
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-dummy: got %s voice dial request",
- enable ? "enable" : "disable");
-
- g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE, "VoiceDial",
- DBUS_TYPE_INVALID);
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- DBG("telephony-dummy: got key press request for %s", keys);
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-/* D-Bus method handlers */
-static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- DBG("telephony-dummy: outgoing call to %s", number);
-
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- DBG("telephony-dummy: incoming call to %s", number);
-
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
-
- active_call_status = CALL_STATUS_INCOMING;
- active_call_dir = CALL_DIR_INCOMING;
-
- telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- DBG("telephony-dummy: cancel call");
-
- g_free(active_call_number);
- active_call_number = NULL;
-
- if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- telephony_calling_stopped_ind();
- }
-
- if (telephony_get_indicator(dummy_indicators, "call") > 0)
- telephony_update_indicator(dummy_indicators, "call",
- EV_CALL_INACTIVE);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_uint32_t strength;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- if (strength > 5)
- return btd_error_invalid_args(msg);
-
- telephony_update_indicator(dummy_indicators, "signal", strength);
-
- DBG("telephony-dummy: signal strength set to %u", strength);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_uint32_t level;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- if (level > 5)
- return btd_error_invalid_args(msg);
-
- telephony_update_indicator(dummy_indicators, "battchg", level);
-
- DBG("telephony-dummy: battery level set to %u", level);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_bool_t roaming;
- int val;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
-
- telephony_update_indicator(dummy_indicators, "roam", val);
-
- DBG("telephony-dummy: roaming status set to %d", val);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_bool_t registration;
- int val;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, ®istration,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
-
- telephony_update_indicator(dummy_indicators, "service", val);
-
- DBG("telephony-dummy: registration status set to %d", val);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_subscriber_number(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- g_free(subscriber_number);
- subscriber_number = g_strdup(number);
-
- DBG("telephony-dummy: subscriber number set to %s", number);
-
- return dbus_message_new_method_return(msg);
-}
-
-static GDBusMethodTable dummy_methods[] = {
- { "OutgoingCall", "s", "", outgoing_call },
- { "IncomingCall", "s", "", incoming_call },
- { "CancelCall", "", "", cancel_call },
- { "SignalStrength", "u", "", signal_strength },
- { "BatteryLevel", "u", "", battery_level },
- { "RoamingStatus", "b", "", roaming_status },
- { "RegistrationStatus", "b", "", registration_status },
- { "SetSubscriberNumber","s", "", set_subscriber_number },
- { }
-};
-
-static GDBusSignalTable dummy_signals[] = {
- { "VoiceDial", "" },
- { }
-};
-
-int telephony_init(void)
-{
- uint32_t features = AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
-
- DBG("");
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE,
- dummy_methods, dummy_signals,
- NULL, NULL, NULL) == FALSE) {
- error("telephony-dummy interface %s init failed on path %s",
- TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
- return -1;
- }
-
- telephony_ready_ind(features, dummy_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
-
- return 0;
-}
-
-void telephony_exit(void)
-{
- DBG("");
-
- g_dbus_unregister_interface(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE);
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
deleted file mode 100644
index 3607d7f..0000000
--- a/audio/telephony-ofono.c
+++ /dev/null
@@ -1,1638 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Intel Corporation
- * Copyright (C) 2006-2009 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "glib-compat.h"
-#include "log.h"
-#include "telephony.h"
-
-enum net_registration_status {
- NETWORK_REG_STATUS_HOME = 0x00,
- NETWORK_REG_STATUS_ROAM,
- NETWORK_REG_STATUS_NOSERV
-};
-
-struct voice_call {
- char *obj_path;
- int status;
- gboolean originating;
- gboolean conference;
- char *number;
- guint watch;
-};
-
-static DBusConnection *connection = NULL;
-static char *modem_obj_path = NULL;
-static char *last_dialed_number = NULL;
-static GSList *calls = NULL;
-static GSList *watches = NULL;
-static GSList *pending = NULL;
-
-#define OFONO_BUS_NAME "org.ofono"
-#define OFONO_PATH "/"
-#define OFONO_MODEM_INTERFACE "org.ofono.Modem"
-#define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
-#define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
-#define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
-#define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1; /* "battery.charge_level.current" */
-static int battchg_last = -1; /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static struct {
- uint8_t status;
- uint32_t signals_bar;
- char *operator_name;
-} net = {
- .status = NETWORK_REG_STATUS_NOSERV,
- .signals_bar = 0,
- .operator_name = NULL,
-};
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator ofono_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 5, TRUE },
- { "service", "0,1", 1, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-static struct voice_call *find_vc(const char *path)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct voice_call *vc = l->data;
-
- if (g_str_equal(vc->obj_path, path))
- return vc;
- }
-
- return NULL;
-}
-
-static struct voice_call *find_vc_with_status(int status)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct voice_call *vc = l->data;
-
- if (vc->status == status)
- return vc;
- }
-
- return NULL;
-}
-
-static struct voice_call *find_vc_without_status(int status)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct voice_call *call = l->data;
-
- if (call->status != status)
- return call;
- }
-
- return NULL;
-}
-
-static int number_type(const char *number)
-{
- if (number == NULL)
- return NUMBER_TYPE_TELEPHONY;
-
- if (number[0] == '+' || strncmp(number, "00", 2) == 0)
- return NUMBER_TYPE_INTERNATIONAL;
-
- return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
- struct voice_call *coming;
-
- DBG("telephony-ofono: device %p connected", telephony_device);
-
- coming = find_vc_with_status(CALL_STATUS_ALERTING);
- if (coming) {
- if (find_vc_with_status(CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(coming->number,
- number_type(coming->number));
- else
- telephony_incoming_call_ind(coming->number,
- number_type(coming->number));
- }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-ofono: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- DBG("telephony-ofono: last dialed number request");
-
- if (last_dialed_number)
- telephony_dial_number_req(telephony_device, last_dialed_number);
- else
- telephony_last_dialed_number_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
-}
-
-static int send_method_call(const char *dest, const char *path,
- const char *interface, const char *method,
- DBusPendingCallNotifyFunction cb,
- void *user_data, int type, ...)
-{
- DBusMessage *msg;
- DBusPendingCall *call;
- va_list args;
-
- msg = dbus_message_new_method_call(dest, path, interface, method);
- if (!msg) {
- error("Unable to allocate new D-Bus %s message", method);
- return -ENOMEM;
- }
-
- va_start(args, type);
-
- if (!dbus_message_append_args_valist(msg, type, args)) {
- dbus_message_unref(msg);
- va_end(args);
- return -EIO;
- }
-
- va_end(args);
-
- if (!cb) {
- g_dbus_send_message(connection, msg);
- return 0;
- }
-
- if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
- error("Sending %s failed", method);
- dbus_message_unref(msg);
- return -EIO;
- }
-
- dbus_pending_call_set_notify(call, cb, user_data, NULL);
- pending = g_slist_prepend(pending, call);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static int answer_call(struct voice_call *vc)
-{
- DBG("%s", vc->number);
- return send_method_call(OFONO_BUS_NAME, vc->obj_path,
- OFONO_VC_INTERFACE, "Answer",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_call(struct voice_call *vc)
-{
- DBG("%s", vc->number);
- return send_method_call(OFONO_BUS_NAME, vc->obj_path,
- OFONO_VC_INTERFACE, "Hangup",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_answer_calls(void)
-{
- DBG("");
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "ReleaseAndAnswer",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int split_call(struct voice_call *call)
-{
- DBG("%s", call->number);
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "PrivateChat",
- NULL, NULL,
- DBUS_TYPE_OBJECT_PATH,
- call->obj_path,
- DBUS_TYPE_INVALID);
- return -1;
-}
-
-static int swap_calls(void)
-{
- DBG("");
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "SwapCalls",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int create_conference(void)
-{
- DBG("");
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "CreateMultiparty",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_conference(void)
-{
- DBG("");
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "HangupMultiparty",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int call_transfer(void)
-{
- DBG("");
- return send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "Transfer",
- NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- struct voice_call *call;
- struct voice_call *alerting;
- int err;
-
- call = find_vc_with_status(CALL_STATUS_ACTIVE);
- if (!call)
- call = calls->data;
-
- if (!call) {
- error("No active call");
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- alerting = find_vc_with_status(CALL_STATUS_ALERTING);
- if (call->status == CALL_STATUS_HELD && alerting)
- err = release_call(alerting);
- else if (call->conference)
- err = release_conference();
- else
- err = release_call(call);
-
- if (err < 0)
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- struct voice_call *vc;
- int ret;
-
- vc = find_vc_with_status(CALL_STATUS_INCOMING);
- if (!vc)
- vc = find_vc_with_status(CALL_STATUS_ALERTING);
-
- if (!vc)
- vc = find_vc_with_status(CALL_STATUS_WAITING);
-
- if (!vc) {
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- ret = answer_call(vc);
- if (ret < 0) {
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- const char *clir;
- int ret;
-
- DBG("telephony-ofono: dial request to %s", number);
-
- if (!modem_obj_path) {
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- if (!strncmp(number, "*31#", 4)) {
- number += 4;
- clir = "enabled";
- } else if (!strncmp(number, "#31#", 4)) {
- number += 4;
- clir = "disabled";
- } else
- clir = "default";
-
- ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "Dial", NULL, NULL,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_STRING, &clir,
- DBUS_TYPE_INVALID);
-
- if (ret < 0)
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- char *tone_string;
- int ret;
-
- DBG("telephony-ofono: transmit dtmf: %c", tone);
-
- if (!modem_obj_path) {
- telephony_transmit_dtmf_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- tone_string = g_strdup_printf("%c", tone);
- ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE,
- "SendTones", NULL, NULL,
- DBUS_TYPE_STRING, &tone_string,
- DBUS_TYPE_INVALID);
- g_free(tone_string);
-
- if (ret < 0)
- telephony_transmit_dtmf_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-ofono: subscriber number request");
-
- if (subscriber_number)
- telephony_subscriber_number_ind(subscriber_number,
- NUMBER_TYPE_TELEPHONY,
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- GSList *l;
- int i;
-
- DBG("telephony-ofono: list current calls request");
-
- for (l = calls, i = 1; l != NULL; l = l->next, i++) {
- struct voice_call *vc = l->data;
- int direction, multiparty;
-
- direction = vc->originating ?
- CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
- multiparty = vc->conference ?
- CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
- DBG("call %s direction %d multiparty %d", vc->number,
- direction, multiparty);
-
- telephony_list_current_call_ind(i, direction, vc->status,
- CALL_MODE_VOICE, multiparty,
- vc->number, number_type(vc->number));
- }
-
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- DBG("telephony-ofono: operator selection request");
-
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
- net.operator_name ? net.operator_name : "");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_vc_with_status(int status,
- int (*func)(struct voice_call *vc))
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct voice_call *call = l->data;
-
- if (call->status == status)
- func(call);
- }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- const char *idx;
- struct voice_call *call;
- int err = 0;
-
- DBG("telephony-ofono: got call hold request %s", cmd);
-
- if (strlen(cmd) > 1)
- idx = &cmd[1];
- else
- idx = NULL;
-
- if (idx)
- call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
- else
- call = NULL;
-
- switch (cmd[0]) {
- case '0':
- if (find_vc_with_status(CALL_STATUS_WAITING))
- foreach_vc_with_status(CALL_STATUS_WAITING,
- release_call);
- else
- foreach_vc_with_status(CALL_STATUS_HELD, release_call);
- break;
- case '1':
- if (idx) {
- if (call)
- err = release_call(call);
- break;
- }
- err = release_answer_calls();
- break;
- case '2':
- if (idx) {
- if (call)
- err = split_call(call);
- } else {
- call = find_vc_with_status(CALL_STATUS_WAITING);
-
- if (call)
- err = answer_call(call);
- else
- err = swap_calls();
- }
- break;
- case '3':
- if (find_vc_with_status(CALL_STATUS_HELD) ||
- find_vc_with_status(CALL_STATUS_WAITING))
- err = create_conference();
- break;
- case '4':
- err = call_transfer();
- break;
- default:
- DBG("Unknown call hold request");
- break;
- }
-
- if (err)
- telephony_call_hold_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-ofono: got %s NR and EC request",
- enable ? "enable" : "disable");
-
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- struct voice_call *active, *incoming;
- int err;
-
- DBG("telephony-ofono: got key press request for %s", keys);
-
- incoming = find_vc_with_status(CALL_STATUS_INCOMING);
-
- active = find_vc_with_status(CALL_STATUS_ACTIVE);
-
- if (incoming)
- err = answer_call(incoming);
- else if (active)
- err = release_call(active);
- else
- err = 0;
-
- if (err < 0)
- telephony_key_press_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-ofono: got %s voice dial request",
- enable ? "enable" : "disable");
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
- int first_arg_type, ...)
-{
- int type;
- va_list ap;
-
- va_start(ap, first_arg_type);
-
- for (type = first_arg_type; type != DBUS_TYPE_INVALID;
- type = va_arg(ap, int)) {
- void *value = va_arg(ap, void *);
- int real_type = dbus_message_iter_get_arg_type(iter);
-
- if (real_type != type) {
- error("iter_get_basic_args: expected %c but got %c",
- (char) type, (char) real_type);
- break;
- }
-
- dbus_message_iter_get_basic(iter, value);
- dbus_message_iter_next(iter);
- }
-
- va_end(ap);
-
- return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void call_free(void *data)
-{
- struct voice_call *vc = data;
-
- DBG("%s", vc->obj_path);
-
- if (vc->status == CALL_STATUS_ACTIVE)
- telephony_update_indicator(ofono_indicators, "call",
- EV_CALL_INACTIVE);
- else
- telephony_update_indicator(ofono_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
-
- if (vc->status == CALL_STATUS_INCOMING)
- telephony_calling_stopped_ind();
-
- g_dbus_remove_watch(connection, vc->watch);
- g_free(vc->obj_path);
- g_free(vc->number);
- g_free(vc);
-}
-
-static gboolean handle_vc_property_changed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct voice_call *vc = data;
- const char *obj_path = dbus_message_get_path(msg);
- DBusMessageIter iter, sub;
- const char *property, *state;
-
- DBG("path %s", obj_path);
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
- error("Unexpected signature in vc PropertyChanged signal");
- return TRUE;
- }
-
- dbus_message_iter_get_basic(&iter, &property);
- DBG("property %s", property);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &sub);
- if (g_str_equal(property, "State")) {
- dbus_message_iter_get_basic(&sub, &state);
- DBG("State %s", state);
- if (g_str_equal(state, "disconnected")) {
- calls = g_slist_remove(calls, vc);
- call_free(vc);
- } else if (g_str_equal(state, "active")) {
- telephony_update_indicator(ofono_indicators,
- "call", EV_CALL_ACTIVE);
- telephony_update_indicator(ofono_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (vc->status == CALL_STATUS_INCOMING)
- telephony_calling_stopped_ind();
- vc->status = CALL_STATUS_ACTIVE;
- } else if (g_str_equal(state, "alerting")) {
- telephony_update_indicator(ofono_indicators,
- "callsetup", EV_CALLSETUP_ALERTING);
- vc->status = CALL_STATUS_ALERTING;
- vc->originating = TRUE;
- } else if (g_str_equal(state, "incoming")) {
- /* state change from waiting to incoming */
- telephony_update_indicator(ofono_indicators,
- "callsetup", EV_CALLSETUP_INCOMING);
- telephony_incoming_call_ind(vc->number,
- NUMBER_TYPE_TELEPHONY);
- vc->status = CALL_STATUS_INCOMING;
- vc->originating = FALSE;
- } else if (g_str_equal(state, "held")) {
- vc->status = CALL_STATUS_HELD;
- if (find_vc_without_status(CALL_STATUS_HELD))
- telephony_update_indicator(ofono_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(ofono_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- }
- } else if (g_str_equal(property, "Multiparty")) {
- dbus_bool_t multiparty;
-
- dbus_message_iter_get_basic(&sub, &multiparty);
- DBG("Multiparty %s", multiparty ? "True" : "False");
- vc->conference = multiparty;
- }
-
- return TRUE;
-}
-
-static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
-{
- struct voice_call *vc;
-
- DBG("%s", path);
-
- vc = g_new0(struct voice_call, 1);
- vc->obj_path = g_strdup(path);
- vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
- OFONO_VC_INTERFACE, "PropertyChanged",
- handle_vc_property_changed, vc, NULL);
-
- while (dbus_message_iter_get_arg_type(properties)
- == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry, value;
- const char *property, *cli, *state;
- dbus_bool_t multiparty;
-
- dbus_message_iter_recurse(properties, &entry);
- dbus_message_iter_get_basic(&entry, &property);
-
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
-
- if (g_str_equal(property, "LineIdentification")) {
- dbus_message_iter_get_basic(&value, &cli);
- DBG("cli %s", cli);
- vc->number = g_strdup(cli);
- } else if (g_str_equal(property, "State")) {
- dbus_message_iter_get_basic(&value, &state);
- DBG("state %s", state);
- if (g_str_equal(state, "incoming"))
- vc->status = CALL_STATUS_INCOMING;
- else if (g_str_equal(state, "dialing"))
- vc->status = CALL_STATUS_DIALING;
- else if (g_str_equal(state, "alerting"))
- vc->status = CALL_STATUS_ALERTING;
- else if (g_str_equal(state, "waiting"))
- vc->status = CALL_STATUS_WAITING;
- else if (g_str_equal(state, "held"))
- vc->status = CALL_STATUS_HELD;
- } else if (g_str_equal(property, "Multiparty")) {
- dbus_message_iter_get_basic(&value, &multiparty);
- DBG("Multipary %s", multiparty ? "True" : "False");
- vc->conference = multiparty;
- }
-
- dbus_message_iter_next(properties);
- }
-
- switch (vc->status) {
- case CALL_STATUS_INCOMING:
- DBG("CALL_STATUS_INCOMING");
- vc->originating = FALSE;
- telephony_update_indicator(ofono_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
- telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
- break;
- case CALL_STATUS_DIALING:
- DBG("CALL_STATUS_DIALING");
- vc->originating = TRUE;
- g_free(last_dialed_number);
- last_dialed_number = g_strdup(vc->number);
- telephony_update_indicator(ofono_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- break;
- case CALL_STATUS_ALERTING:
- DBG("CALL_STATUS_ALERTING");
- vc->originating = TRUE;
- g_free(last_dialed_number);
- last_dialed_number = g_strdup(vc->number);
- telephony_update_indicator(ofono_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
- break;
- case CALL_STATUS_WAITING:
- DBG("CALL_STATUS_WAITING");
- vc->originating = FALSE;
- telephony_update_indicator(ofono_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
- telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
- break;
- }
-
- return vc;
-}
-
-static void remove_pending(DBusPendingCall *call)
-{
- pending = g_slist_remove(pending, call);
- dbus_pending_call_unref(call);
-}
-
-static void call_added(const char *path, DBusMessageIter *properties)
-{
- struct voice_call *vc;
-
- DBG("%s", path);
-
- vc = find_vc(path);
- if (vc)
- return;
-
- vc = call_new(path, properties);
- calls = g_slist_prepend(calls, vc);
-}
-
-static void get_calls_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, entry;
-
- DBG("");
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("ofono replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &entry);
-
- while (dbus_message_iter_get_arg_type(&entry)
- == DBUS_TYPE_STRUCT) {
- const char *path;
- DBusMessageIter value, properties;
-
- dbus_message_iter_recurse(&entry, &value);
- dbus_message_iter_get_basic(&value, &path);
-
- dbus_message_iter_next(&value);
- dbus_message_iter_recurse(&value, &properties);
-
- call_added(path, &properties);
-
- dbus_message_iter_next(&entry);
- }
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void handle_network_property(const char *property, DBusMessageIter *variant)
-{
- const char *status, *operator;
- unsigned int signals_bar;
-
- if (g_str_equal(property, "Status")) {
- dbus_message_iter_get_basic(variant, &status);
- DBG("Status is %s", status);
- if (g_str_equal(status, "registered")) {
- net.status = NETWORK_REG_STATUS_HOME;
- telephony_update_indicator(ofono_indicators,
- "roam", EV_ROAM_INACTIVE);
- telephony_update_indicator(ofono_indicators,
- "service", EV_SERVICE_PRESENT);
- } else if (g_str_equal(status, "roaming")) {
- net.status = NETWORK_REG_STATUS_ROAM;
- telephony_update_indicator(ofono_indicators,
- "roam", EV_ROAM_ACTIVE);
- telephony_update_indicator(ofono_indicators,
- "service", EV_SERVICE_PRESENT);
- } else {
- net.status = NETWORK_REG_STATUS_NOSERV;
- telephony_update_indicator(ofono_indicators,
- "roam", EV_ROAM_INACTIVE);
- telephony_update_indicator(ofono_indicators,
- "service", EV_SERVICE_NONE);
- }
- } else if (g_str_equal(property, "Name")) {
- dbus_message_iter_get_basic(variant, &operator);
- DBG("Operator is %s", operator);
- g_free(net.operator_name);
- net.operator_name = g_strdup(operator);
- } else if (g_str_equal(property, "SignalStrength")) {
- dbus_message_iter_get_basic(variant, &signals_bar);
- DBG("SignalStrength is %d", signals_bar);
- net.signals_bar = signals_bar;
- telephony_update_indicator(ofono_indicators, "signal",
- (signals_bar + 20) / 21);
- }
-}
-
-static int parse_network_properties(DBusMessageIter *properties)
-{
- int i;
-
- /* Reset indicators */
- for (i = 0; ofono_indicators[i].desc != NULL; i++) {
- if (g_str_equal(ofono_indicators[i].desc, "battchg"))
- ofono_indicators[i].val = 5;
- else
- ofono_indicators[i].val = 0;
- }
-
- while (dbus_message_iter_get_arg_type(properties)
- == DBUS_TYPE_DICT_ENTRY) {
- const char *key;
- DBusMessageIter value, entry;
-
- dbus_message_iter_recurse(properties, &entry);
- dbus_message_iter_get_basic(&entry, &key);
-
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
-
- handle_network_property(key, &value);
-
- dbus_message_iter_next(properties);
- }
-
- return 0;
-}
-
-static void get_properties_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, properties;
- int ret = 0;
-
- DBG("");
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("ofono replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &properties);
-
- ret = parse_network_properties(&properties);
- if (ret < 0) {
- error("Unable to parse %s.GetProperty reply",
- OFONO_NETWORKREG_INTERFACE);
- goto done;
- }
-
- ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
- OFONO_VCMANAGER_INTERFACE, "GetCalls",
- get_calls_reply, NULL, DBUS_TYPE_INVALID);
- if (ret < 0)
- error("Unable to send %s.GetCalls",
- OFONO_VCMANAGER_INTERFACE);
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void network_found(const char *path)
-{
- int ret;
-
- DBG("%s", path);
-
- modem_obj_path = g_strdup(path);
-
- ret = send_method_call(OFONO_BUS_NAME, path,
- OFONO_NETWORKREG_INTERFACE, "GetProperties",
- get_properties_reply, NULL, DBUS_TYPE_INVALID);
- if (ret < 0)
- error("Unable to send %s.GetProperties",
- OFONO_NETWORKREG_INTERFACE);
-}
-
-static void modem_removed(const char *path)
-{
- if (g_strcmp0(modem_obj_path, path) != 0)
- return;
-
- DBG("%s", path);
-
- g_slist_free_full(calls, call_free);
- calls = NULL;
-
- g_free(net.operator_name);
- net.operator_name = NULL;
- net.status = NETWORK_REG_STATUS_NOSERV;
- net.signals_bar = 0;
-
- g_free(modem_obj_path);
- modem_obj_path = NULL;
-}
-
-static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
-{
- DBG("%s", path);
-
- while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
- const char *iface;
-
- dbus_message_iter_get_basic(ifaces, &iface);
-
- if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
- network_found(path);
- return;
- }
-
- dbus_message_iter_next(ifaces);
- }
-
- modem_removed(path);
-}
-
-static void modem_added(const char *path, DBusMessageIter *properties)
-{
- if (modem_obj_path != NULL) {
- DBG("Ignoring, modem already exist");
- return;
- }
-
- DBG("%s", path);
-
- while (dbus_message_iter_get_arg_type(properties)
- == DBUS_TYPE_DICT_ENTRY) {
- const char *key;
- DBusMessageIter interfaces, value, entry;
-
- dbus_message_iter_recurse(properties, &entry);
- dbus_message_iter_get_basic(&entry, &key);
-
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
-
- if (strcasecmp(key, "Interfaces") != 0)
- goto next;
-
- if (dbus_message_iter_get_arg_type(&value)
- != DBUS_TYPE_ARRAY) {
- error("Invalid Signature");
- return;
- }
-
- dbus_message_iter_recurse(&value, &interfaces);
-
- parse_modem_interfaces(path, &interfaces);
-
- if (modem_obj_path != NULL)
- return;
-
- next:
- dbus_message_iter_next(properties);
- }
-}
-
-static void get_modems_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, entry;
-
- DBG("");
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("ofono replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- /* Skip modem selection if a modem already exist */
- if (modem_obj_path != NULL)
- goto done;
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &entry);
-
- while (dbus_message_iter_get_arg_type(&entry)
- == DBUS_TYPE_STRUCT) {
- const char *path;
- DBusMessageIter item, properties;
-
- dbus_message_iter_recurse(&entry, &item);
- dbus_message_iter_get_basic(&item, &path);
-
- dbus_message_iter_next(&item);
- dbus_message_iter_recurse(&item, &properties);
-
- modem_added(path, &properties);
- if (modem_obj_path != NULL)
- break;
-
- dbus_message_iter_next(&entry);
- }
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static gboolean handle_network_property_changed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, variant;
- const char *property;
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
- error("Unexpected signature in networkregistration"
- " PropertyChanged signal");
- return TRUE;
- }
- dbus_message_iter_get_basic(&iter, &property);
- DBG("in handle_registration_property_changed(),"
- " the property is %s", property);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &variant);
-
- handle_network_property(property, &variant);
-
- return TRUE;
-}
-
-static void handle_modem_property(const char *path, const char *property,
- DBusMessageIter *variant)
-{
- DBG("%s", property);
-
- if (g_str_equal(property, "Interfaces")) {
- DBusMessageIter interfaces;
-
- if (dbus_message_iter_get_arg_type(variant)
- != DBUS_TYPE_ARRAY) {
- error("Invalid signature");
- return;
- }
-
- dbus_message_iter_recurse(variant, &interfaces);
- parse_modem_interfaces(path, &interfaces);
- }
-}
-
-static gboolean handle_modem_property_changed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, variant;
- const char *property, *path;
-
- path = dbus_message_get_path(msg);
-
- /* Ignore if modem already exist and paths doesn't match */
- if (modem_obj_path != NULL &&
- g_str_equal(path, modem_obj_path) == FALSE)
- return TRUE;
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
- error("Unexpected signature in %s.%s PropertyChanged signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- return TRUE;
- }
-
- dbus_message_iter_get_basic(&iter, &property);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &variant);
-
- handle_modem_property(path, property, &variant);
-
- return TRUE;
-}
-
-static gboolean handle_vcmanager_call_added(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, properties;
- const char *path = dbus_message_get_path(msg);
-
- /* Ignore call if modem path doesn't math */
- if (g_strcmp0(modem_obj_path, path) != 0)
- return TRUE;
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter)
- != DBUS_TYPE_OBJECT_PATH) {
- error("Unexpected signature in %s.%s signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- return TRUE;
- }
-
- dbus_message_iter_get_basic(&iter, &path);
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &properties);
-
- call_added(path, &properties);
-
- return TRUE;
-}
-
-static void call_removed(const char *path)
-{
- struct voice_call *vc;
-
- DBG("%s", path);
-
- vc = find_vc(path);
- if (vc == NULL)
- return;
-
- calls = g_slist_remove(calls, vc);
- call_free(vc);
-}
-
-static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path = dbus_message_get_path(msg);
-
- /* Ignore call if modem path doesn't math */
- if (g_strcmp0(modem_obj_path, path) != 0)
- return TRUE;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- error("Unexpected signature in %s.%s signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- return TRUE;
- }
-
- call_removed(path);
-
- return TRUE;
-}
-
-static gboolean handle_manager_modem_added(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, properties;
- const char *path;
-
- if (modem_obj_path != NULL)
- return TRUE;
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter)
- != DBUS_TYPE_OBJECT_PATH) {
- error("Unexpected signature in %s.%s signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- return TRUE;
- }
-
- dbus_message_iter_get_basic(&iter, &path);
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &properties);
-
- modem_added(path, &properties);
-
- return TRUE;
-}
-
-static gboolean handle_manager_modem_removed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- error("Unexpected signature in %s.%s signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- return TRUE;
- }
-
- modem_removed(path);
-
- return TRUE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply;
- DBusError err;
- dbus_int32_t level;
- int *value = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (dbus_message_get_args(reply, &err,
- DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse GetPropertyInteger reply: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- *value = (int) level;
-
- if (value == &battchg_last)
- DBG("telephony-ofono: battery.charge_level.last_full"
- " is %d", *value);
- else if (value == &battchg_design)
- DBG("telephony-ofono: battery.charge_level.design"
- " is %d", *value);
- else
- DBG("telephony-ofono: battery.charge_level.current"
- " is %d", *value);
-
- if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
- int new, max;
-
- if (battchg_last > 0)
- max = battchg_last;
- else
- max = battchg_design;
-
- new = battchg_cur * 5 / max;
-
- telephony_update_indicator(ofono_indicators, "battchg", new);
- }
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
- send_method_call("org.freedesktop.Hal", path,
- "org.freedesktop.Hal.Device",
- "GetPropertyInteger",
- hal_battery_level_reply, user_data,
- DBUS_TYPE_STRING, &key,
- DBUS_TYPE_INVALID);
-}
-
-static gboolean handle_hal_property_modified(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path;
- DBusMessageIter iter, array;
- dbus_int32_t num_changes;
-
- path = dbus_message_get_path(msg);
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
- error("Unexpected signature in hal PropertyModified signal");
- return TRUE;
- }
-
- dbus_message_iter_get_basic(&iter, &num_changes);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in hal PropertyModified signal");
- return TRUE;
- }
-
- dbus_message_iter_recurse(&iter, &array);
-
- while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
- DBusMessageIter prop;
- const char *name;
- dbus_bool_t added, removed;
-
- dbus_message_iter_recurse(&array, &prop);
-
- if (!iter_get_basic_args(&prop,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &added,
- DBUS_TYPE_BOOLEAN, &removed,
- DBUS_TYPE_INVALID)) {
- error("Invalid hal PropertyModified parameters");
- break;
- }
-
- if (g_str_equal(name, "battery.charge_level.last_full"))
- hal_get_integer(path, name, &battchg_last);
- else if (g_str_equal(name, "battery.charge_level.current"))
- hal_get_integer(path, name, &battchg_cur);
- else if (g_str_equal(name, "battery.charge_level.design"))
- hal_get_integer(path, name, &battchg_design);
-
- dbus_message_iter_next(&array);
- }
-
- return TRUE;
-}
-
-static void add_watch(const char *sender, const char *path,
- const char *interface, const char *member,
- GDBusSignalFunction function)
-{
- guint watch;
-
- watch = g_dbus_add_signal_watch(connection, sender, path, interface,
- member, function, NULL, NULL);
-
- watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply;
- DBusError err;
- DBusMessageIter iter, sub;
- int type;
- const char *path;
-
- DBG("begin of hal_find_device_reply()");
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
-
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in hal_find_device_reply()");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- type = dbus_message_iter_get_arg_type(&sub);
-
- if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
- error("No hal device with battery capability found");
- goto done;
- }
-
- dbus_message_iter_get_basic(&sub, &path);
-
- DBG("telephony-ofono: found battery device at %s", path);
-
- add_watch(NULL, path, "org.freedesktop.Hal.Device",
- "PropertyModified", handle_hal_property_modified);
-
- hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
- hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
- hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void handle_service_connect(DBusConnection *conn, void *user_data)
-{
- DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
-
- send_method_call(OFONO_BUS_NAME, OFONO_PATH,
- OFONO_MANAGER_INTERFACE, "GetModems",
- get_modems_reply, NULL, DBUS_TYPE_INVALID);
-}
-
-static void handle_service_disconnect(DBusConnection *conn, void *user_data)
-{
- DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
-
- if (modem_obj_path)
- modem_removed(modem_obj_path);
-}
-
-int telephony_init(void)
-{
- uint32_t features = AG_FEATURE_EC_ANDOR_NR |
- AG_FEATURE_INBAND_RINGTONE |
- AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_ENHANCED_CALL_CONTROL |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
- AG_FEATURE_THREE_WAY_CALLING;
- const char *battery_cap = "battery";
- int ret;
- guint watch;
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
- "PropertyChanged", handle_modem_property_changed);
- add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
- "PropertyChanged", handle_network_property_changed);
- add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
- "ModemAdded", handle_manager_modem_added);
- add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
- "ModemRemoved", handle_manager_modem_removed);
- add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
- "CallAdded", handle_vcmanager_call_added);
- add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
- "CallRemoved", handle_vcmanager_call_removed);
-
- watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
- handle_service_connect,
- handle_service_disconnect,
- NULL, NULL);
- if (watch == 0)
- return -ENOMEM;
-
- watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-
- ret = send_method_call("org.freedesktop.Hal",
- "/org/freedesktop/Hal/Manager",
- "org.freedesktop.Hal.Manager",
- "FindDeviceByCapability",
- hal_find_device_reply, NULL,
- DBUS_TYPE_STRING, &battery_cap,
- DBUS_TYPE_INVALID);
- if (ret < 0)
- return ret;
-
- DBG("telephony_init() successfully");
-
- telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
-
- return ret;
-}
-
-static void remove_watch(gpointer data)
-{
- g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-static void pending_free(void *data)
-{
- DBusPendingCall *call = data;
-
- if (!dbus_pending_call_get_completed(call))
- dbus_pending_call_cancel(call);
-
- dbus_pending_call_unref(call);
-}
-
-void telephony_exit(void)
-{
- DBG("");
-
- g_free(last_dialed_number);
- last_dialed_number = NULL;
-
- if (modem_obj_path)
- modem_removed(modem_obj_path);
-
- g_slist_free_full(watches, remove_watch);
- watches = NULL;
-
- g_slist_free_full(pending, pending_free);
- pending = NULL;
-
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
diff --git a/audio/telephony.h b/audio/telephony.h
index 7d1d337..aa23bef 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -26,13 +26,6 @@
#include <errno.h>
#include <glib.h>
-/* Response and hold values */
-#define BTRH_NOT_SUPPORTED -2
-#define BTRH_NONE -1
-#define BTRH_HOLD 0
-#define BTRH_ACCEPT 1
-#define BTRH_REJECT 2
-
/* HFP feature bits */
#define AG_FEATURE_THREE_WAY_CALLING 0x0001
#define AG_FEATURE_EC_ANDOR_NR 0x0002
@@ -52,95 +45,6 @@
#define HF_FEATURE_ENHANCED_CALL_STATUS 0x0020
#define HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040
-/* Indicator event values */
-#define EV_SERVICE_NONE 0
-#define EV_SERVICE_PRESENT 1
-
-#define EV_CALL_INACTIVE 0
-#define EV_CALL_ACTIVE 1
-
-#define EV_CALLSETUP_INACTIVE 0
-#define EV_CALLSETUP_INCOMING 1
-#define EV_CALLSETUP_OUTGOING 2
-#define EV_CALLSETUP_ALERTING 3
-
-#define EV_CALLHELD_NONE 0
-#define EV_CALLHELD_MULTIPLE 1
-#define EV_CALLHELD_ON_HOLD 2
-
-#define EV_ROAM_INACTIVE 0
-#define EV_ROAM_ACTIVE 1
-
-/* Call parameters */
-#define CALL_DIR_OUTGOING 0
-#define CALL_DIR_INCOMING 1
-
-#define CALL_STATUS_ACTIVE 0
-#define CALL_STATUS_HELD 1
-#define CALL_STATUS_DIALING 2
-#define CALL_STATUS_ALERTING 3
-#define CALL_STATUS_INCOMING 4
-#define CALL_STATUS_WAITING 5
-
-#define CALL_MODE_VOICE 0
-#define CALL_MODE_DATA 1
-#define CALL_MODE_FAX 2
-
-#define CALL_MULTIPARTY_NO 0
-#define CALL_MULTIPARTY_YES 1
-
-/* Subscriber number parameters */
-#define SUBSCRIBER_SERVICE_VOICE 4
-#define SUBSCRIBER_SERVICE_FAX 5
-
-/* Operator selection mode values */
-#define OPERATOR_MODE_AUTO 0
-#define OPERATOR_MODE_MANUAL 1
-#define OPERATOR_MODE_DEREGISTER 2
-#define OPERATOR_MODE_MANUAL_AUTO 4
-
-/* Some common number types */
-#define NUMBER_TYPE_UNKNOWN 128
-#define NUMBER_TYPE_TELEPHONY 129
-#define NUMBER_TYPE_INTERNATIONAL 145
-#define NUMBER_TYPE_NATIONAL 161
-#define NUMBER_TYPE_VOIP 255
-
-/* Extended Audio Gateway Error Result Codes */
-typedef enum {
- CME_ERROR_NONE = -1,
- CME_ERROR_AG_FAILURE = 0,
- CME_ERROR_NO_PHONE_CONNECTION = 1,
- CME_ERROR_NOT_ALLOWED = 3,
- CME_ERROR_NOT_SUPPORTED = 4,
- CME_ERROR_PH_SIM_PIN_REQUIRED = 5,
- CME_ERROR_SIM_NOT_INSERTED = 10,
- CME_ERROR_SIM_PIN_REQUIRED = 11,
- CME_ERROR_SIM_PUK_REQUIRED = 12,
- CME_ERROR_SIM_FAILURE = 13,
- CME_ERROR_SIM_BUSY = 14,
- CME_ERROR_INCORRECT_PASSWORD = 16,
- CME_ERROR_SIM_PIN2_REQUIRED = 17,
- CME_ERROR_SIM_PUK2_REQUIRED = 18,
- CME_ERROR_MEMORY_FULL = 20,
- CME_ERROR_INVALID_INDEX = 21,
- CME_ERROR_MEMORY_FAILURE = 23,
- CME_ERROR_TEXT_STRING_TOO_LONG = 24,
- CME_ERROR_INVALID_TEXT_STRING = 25,
- CME_ERROR_DIAL_STRING_TOO_LONG = 26,
- CME_ERROR_INVALID_DIAL_STRING = 27,
- CME_ERROR_NO_NETWORK_SERVICE = 30,
- CME_ERROR_NETWORK_TIMEOUT = 31,
- CME_ERROR_NETWORK_NOT_ALLOWED = 32,
-} cme_error_t;
-
-struct indicator {
- const char *desc;
- const char *range;
- int val;
- gboolean ignore_redundant;
-};
-
/* Notify telephony-*.c of connected/disconnected devices. Implemented by
* telephony-*.c
*/
@@ -152,80 +56,5 @@ void telephony_device_disconnected(void *telephony_device);
gboolean telephony_get_ready_state(void);
uint32_t telephony_get_ag_features(void);
-/* AG responses to HF requests. These are implemented by headset.c */
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err);
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err);
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err);
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err);
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err);
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err);
-
-/* Event indications by AG. These are implemented by headset.c */
-int telephony_event_ind(int index);
-int telephony_response_and_hold_ind(int rh);
-int telephony_incoming_call_ind(const char *number, int type);
-int telephony_calling_stopped_ind(void);
-int telephony_ready_ind(uint32_t features, const struct indicator *indicators,
- int rh, const char *chld);
-int telephony_deinit(void);
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
- int mprty, const char *number,
- int type);
-int telephony_subscriber_number_ind(const char *number, int type,
- int service);
-int telephony_call_waiting_ind(const char *number, int type);
-int telephony_operator_selection_ind(int mode, const char *oper);
-
-/* Helper function for quick indicator updates */
-static inline int telephony_update_indicator(struct indicator *indicators,
- const char *desc,
- int new_val)
-{
- int i;
- struct indicator *ind = NULL;
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (g_str_equal(indicators[i].desc, desc)) {
- ind = &indicators[i];
- break;
- }
- }
-
- if (!ind)
- return -ENOENT;
-
- DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
-
- if (ind->ignore_redundant && ind->val == new_val) {
- DBG("Ignoring no-change indication");
- return 0;
- }
-
- ind->val = new_val;
-
- return telephony_event_ind(i);
-}
-
-static inline int telephony_get_indicator(const struct indicator *indicators,
- const char *desc)
-{
- int i;
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (g_str_equal(indicators[i].desc, desc))
- return indicators[i].val;
- }
-
- return -ENOENT;
-}
-
int telephony_init(void *adapter);
void telephony_exit(void *adapter);
diff --git a/audio/transport.c b/audio/transport.c
index 7bde32d..3c7828d 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -845,14 +845,18 @@ static void get_properties_a2dp(struct media_transport *transport,
static void get_properties_headset(struct media_transport *transport,
DBusMessageIter *dict)
{
+#if 0
gboolean nrec, inband;
+#endif
const char *routing;
+#if 0
nrec = headset_get_nrec(transport->device);
dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec);
inband = headset_get_inband(transport->device);
dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband);
+#endif
routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM";
dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing);
@@ -944,8 +948,10 @@ static void media_transport_free(void *data)
if (transport->session)
avdtp_unref(transport->session);
+#if 0
if (transport->nrec_id)
headset_remove_nrec_cb(transport->device, transport->nrec_id);
+#endif
if (transport->conn)
dbus_connection_unref(transport->conn);
@@ -955,6 +961,7 @@ static void media_transport_free(void *data)
g_free(transport);
}
+#if 0
static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
void *user_data)
{
@@ -966,6 +973,7 @@ static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
MEDIA_TRANSPORT_INTERFACE, "NREC",
DBUS_TYPE_BOOLEAN, &nrec);
}
+#endif
struct media_transport *media_transport_create(DBusConnection *conn,
struct media_endpoint *endpoint,
@@ -1002,9 +1010,11 @@ struct media_transport *media_transport_create(DBusConnection *conn,
transport->cancel = cancel_headset;
transport->get_properties = get_properties_headset;
transport->set_property = set_property_headset;
+#if 0
transport->nrec_id = headset_add_nrec_cb(device,
headset_nrec_changed,
transport);
+#endif
} else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
strcasecmp(uuid, HSP_HS_UUID) == 0) {
transport->resume = resume_gateway;
diff --git a/audio/unix.c b/audio/unix.c
index 5199831..24a6669 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -261,8 +261,10 @@ static uint8_t headset_generate_capability(struct audio_device *dev,
pcm = (void *) codec;
pcm->sampling_rate = 8000;
if (dev->headset) {
+#if 0
if (headset_get_nrec(dev))
pcm->flags |= BT_PCM_FLAG_NREC;
+#endif
if (!headset_get_sco_hci(dev))
pcm->flags |= BT_PCM_FLAG_PCM_ROUTING;
codec->configured = headset_is_active(dev);
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [RFC v3 3/6] audio: Remove maemo5 tel driver
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
2011-12-01 15:14 ` [RFC v3 1/6] audio: Move tel drivers to DBus interface Frédéric Danis
2011-12-01 15:14 ` [RFC v3 2/6] audio: Remove tel drivers Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
2011-12-01 15:14 ` [RFC v3 4/6] audio: Remove maemo6 " Frédéric Danis
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
audio/telephony-maemo5.c | 2104 ----------------------------------------------
1 files changed, 0 insertions(+), 2104 deletions(-)
delete mode 100644 audio/telephony-maemo5.c
diff --git a/audio/telephony-maemo5.c b/audio/telephony-maemo5.c
deleted file mode 100644
index 23801c0..0000000
--- a/audio/telephony-maemo5.c
+++ /dev/null
@@ -1,2104 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define NETWORK_BUS_NAME "com.nokia.phone.net"
-#define NETWORK_INTERFACE "Phone.Net"
-#define NETWORK_PATH "/com/nokia/phone/net"
-
-/* Mask bits for supported services */
-#define NETWORK_MASK_GPRS_SUPPORT 0x01
-#define NETWORK_MASK_CS_SERVICES 0x02
-#define NETWORK_MASK_EGPRS_SUPPORT 0x04
-#define NETWORK_MASK_HSDPA_AVAIL 0x08
-#define NETWORK_MASK_HSUPA_AVAIL 0x10
-
-/* network get cell info: cell type */
-#define NETWORK_UNKNOWN_CELL 0
-#define NETWORK_GSM_CELL 1
-#define NETWORK_WCDMA_CELL 2
-
-enum net_registration_status {
- NETWORK_REG_STATUS_HOME = 0x00,
- NETWORK_REG_STATUS_ROAM,
- NETWORK_REG_STATUS_ROAM_BLINK,
- NETWORK_REG_STATUS_NOSERV,
- NETWORK_REG_STATUS_NOSERV_SEARCHING,
- NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
- NETWORK_REG_STATUS_NOSERV_NOSIM,
- NETWORK_REG_STATUS_POWER_OFF = 0x08,
- NETWORK_REG_STATUS_NSPS,
- NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
- NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
-};
-
-enum network_types {
- NETWORK_GSM_HOME_PLMN = 0,
- NETWORK_GSM_PREFERRED_PLMN,
- NETWORK_GSM_FORBIDDEN_PLMN,
- NETWORK_GSM_OTHER_PLMN,
- NETWORK_GSM_NO_PLMN_AVAIL
-};
-
-enum network_alpha_tag_name_type {
- NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
- NETWORK_HARDCODED_USC2_OPER_NAME,
- NETWORK_NITZ_SHORT_OPER_NAME,
- NETWORK_NITZ_FULL_OPER_NAME,
-};
-
-#define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony"
-#define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony"
-
-#define CALLERID_BASE "/var/lib/bluetooth/maemo-callerid-"
-#define ALLOWED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-allowed"
-#define RESTRICTED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-restricted"
-#define NONE_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-none"
-
-static uint32_t callerid = 0;
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE "com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH "/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE 0
-#define CSD_CALL_STATUS_CREATE 1
-#define CSD_CALL_STATUS_COMING 2
-#define CSD_CALL_STATUS_PROCEEDING 3
-#define CSD_CALL_STATUS_MO_ALERTING 4
-#define CSD_CALL_STATUS_MT_ALERTING 5
-#define CSD_CALL_STATUS_WAITING 6
-#define CSD_CALL_STATUS_ANSWERED 7
-#define CSD_CALL_STATUS_ACTIVE 8
-#define CSD_CALL_STATUS_MO_RELEASE 9
-#define CSD_CALL_STATUS_MT_RELEASE 10
-#define CSD_CALL_STATUS_HOLD_INITIATED 11
-#define CSD_CALL_STATUS_HOLD 12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
-#define CSD_CALL_STATUS_RECONNECT_PENDING 14
-#define CSD_CALL_STATUS_TERMINATED 15
-#define CSD_CALL_STATUS_SWAP_INITIATED 16
-
-#define CALL_FLAG_NONE 0
-#define CALL_FLAG_PRESENTATION_ALLOWED 0x01
-#define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
-
-/* SIM Phonebook D-Bus definitions */
-#define SIM_PHONEBOOK_BUS_NAME "com.nokia.phone.SIM"
-#define SIM_PHONEBOOK_INTERFACE "Phone.Sim.Phonebook"
-#define SIM_PHONEBOOK_PATH "/com/nokia/phone/SIM/phonebook"
-
-#define PHONEBOOK_INDEX_FIRST_ENTRY 0xFFFF
-#define PHONEBOOK_INDEX_NEXT_FREE_LOCATION 0xFFFE
-
-enum sim_phonebook_type {
- SIM_PHONEBOOK_TYPE_ADN = 0x0,
- SIM_PHONEBOOK_TYPE_SDN,
- SIM_PHONEBOOK_TYPE_FDN,
- SIM_PHONEBOOK_TYPE_VMBX,
- SIM_PHONEBOOK_TYPE_MBDN,
- SIM_PHONEBOOK_TYPE_EN,
- SIM_PHONEBOOK_TYPE_MSISDN
-};
-
-enum sim_phonebook_location_type {
- SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
- SIM_PHONEBOOK_LOCATION_NEXT
-};
-
-struct csd_call {
- char *object_path;
- int status;
- gboolean originating;
- gboolean emergency;
- gboolean on_hold;
- gboolean conference;
- char *number;
- gboolean setup;
-};
-
-static struct {
- uint8_t status;
- uint16_t lac;
- uint32_t cell_id;
- uint32_t operator_code;
- uint32_t country_code;
- uint8_t network_type;
- uint8_t supported_services;
- uint16_t signals_bar;
- char *operator_name;
-} net = {
- .status = NETWORK_REG_STATUS_NOSERV,
- .lac = 0,
- .cell_id = 0,
- .operator_code = 0,
- .country_code = 0,
- .network_type = NETWORK_GSM_NO_PLMN_AVAIL,
- .supported_services = 0,
- .signals_bar = 0,
- .operator_name = NULL,
-};
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-static char *msisdn = NULL; /* Subscriber number */
-static char *vmbx = NULL; /* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1; /* "battery.charge_level.current" */
-static int battchg_last = -1; /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-static char *last_dialed_number = NULL;
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 0, TRUE },
- { "service", "0,1", 0, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-static char *call_status_str[] = {
- "IDLE",
- "CREATE",
- "COMING",
- "PROCEEDING",
- "MO_ALERTING",
- "MT_ALERTING",
- "WAITING",
- "ANSWERED",
- "ACTIVE",
- "MO_RELEASE",
- "MT_RELEASE",
- "HOLD_INITIATED",
- "HOLD",
- "RETRIEVE_INITIATED",
- "RECONNECT_PENDING",
- "TERMINATED",
- "SWAP_INITIATED",
- "???"
-};
-
-static struct csd_call *find_call(const char *path)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (g_str_equal(call->object_path, path))
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == CSD_CALL_STATUS_IDLE)
- continue;
-
- if (call->status != CSD_CALL_STATUS_HOLD)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status != CSD_CALL_STATUS_IDLE)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- return call;
- }
-
- return NULL;
-}
-
-static int release_conference(void)
-{
- DBusMessage *msg;
-
- DBG("telephony-maemo: releasing conference call");
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- CSD_CALL_CONFERENCE_PATH,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Answer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Split");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Unhold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Hold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int swap_calls(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Swap");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int create_conference(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Conference");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int call_transfer(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Transfer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int number_type(const char *number)
-{
- if (number == NULL)
- return NUMBER_TYPE_TELEPHONY;
-
- if (number[0] == '+' || strncmp(number, "00", 2) == 0)
- return NUMBER_TYPE_INTERNATIONAL;
-
- return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
- struct csd_call *coming;
-
- DBG("telephony-maemo: device %p connected", telephony_device);
-
- coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (coming) {
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(coming->number,
- number_type(coming->number));
- else
- telephony_incoming_call_ind(coming->number,
- number_type(coming->number));
- }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-maemo: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- DBG("telephony-maemo: last dialed number request");
-
- if (last_dialed_number)
- telephony_dial_number_req(telephony_device,
- last_dialed_number);
- else
- telephony_last_dialed_number_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- struct csd_call *call;
- int err;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- if (!call)
- call = find_non_idle_call();
-
- if (!call) {
- error("No active call");
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- if (call->conference)
- err = release_conference();
- else
- err = release_call(call);
-
- if (err < 0)
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- struct csd_call *call;
-
- call = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (!call) {
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- if (answer_call(call) < 0)
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int send_method_call(const char *dest, const char *path,
- const char *interface, const char *method,
- DBusPendingCallNotifyFunction cb,
- void *user_data, int type, ...)
-{
- DBusMessage *msg;
- DBusPendingCall *call;
- va_list args;
-
- msg = dbus_message_new_method_call(dest, path, interface, method);
- if (!msg) {
- error("Unable to allocate new D-Bus %s message", method);
- return -ENOMEM;
- }
-
- va_start(args, type);
-
- if (!dbus_message_append_args_valist(msg, type, args)) {
- dbus_message_unref(msg);
- va_end(args);
- return -EIO;
- }
-
- va_end(args);
-
- if (!cb) {
- g_dbus_send_message(connection, msg);
- return 0;
- }
-
- if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
- error("Sending %s failed", method);
- dbus_message_unref(msg);
- return -EIO;
- }
-
- dbus_pending_call_set_notify(call, cb, user_data, NULL);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static const char *memory_dial_lookup(int location)
-{
- if (location == 1)
- return vmbx;
- else
- return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- uint32_t flags = callerid;
- int ret;
-
- DBG("telephony-maemo: dial request to %s", number);
-
- if (strncmp(number, "*31#", 4) == 0) {
- number += 4;
- flags = CALL_FLAG_PRESENTATION_ALLOWED;
- } else if (strncmp(number, "#31#", 4) == 0) {
- number += 4;
- flags = CALL_FLAG_PRESENTATION_RESTRICTED;
- } else if (number[0] == '>') {
- const char *location = &number[1];
-
- number = memory_dial_lookup(strtol(&number[1], NULL, 0));
- if (!number) {
- error("No number at memory location %s", location);
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_INVALID_INDEX);
- return;
- }
- }
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "CreateWith",
- NULL, NULL,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- int ret;
- char buf[2] = { tone, '\0' }, *buf_ptr = buf;
-
- DBG("telephony-maemo: transmit dtmf: %s", buf);
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "SendDTMF",
- NULL, NULL,
- DBUS_TYPE_STRING, &buf_ptr,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- telephony_transmit_dtmf_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-maemo: subscriber number request");
- if (msisdn)
- telephony_subscriber_number_ind(msisdn,
- number_type(msisdn),
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
- switch (call->status) {
- case CSD_CALL_STATUS_IDLE:
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- case CSD_CALL_STATUS_TERMINATED:
- return -1;
- case CSD_CALL_STATUS_CREATE:
- return CALL_STATUS_DIALING;
- case CSD_CALL_STATUS_WAITING:
- return CALL_STATUS_WAITING;
- case CSD_CALL_STATUS_PROCEEDING:
- /* PROCEEDING can happen in outgoing/incoming */
- if (call->originating)
- return CALL_STATUS_DIALING;
- else
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_COMING:
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_MO_ALERTING:
- return CALL_STATUS_ALERTING;
- case CSD_CALL_STATUS_MT_ALERTING:
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_ANSWERED:
- case CSD_CALL_STATUS_ACTIVE:
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- case CSD_CALL_STATUS_SWAP_INITIATED:
- case CSD_CALL_STATUS_HOLD_INITIATED:
- return CALL_STATUS_ACTIVE;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- case CSD_CALL_STATUS_HOLD:
- return CALL_STATUS_HELD;
- default:
- return -1;
- }
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- GSList *l;
- int i;
-
- DBG("telephony-maemo: list current calls request");
-
- for (l = calls, i = 1; l != NULL; l = l->next, i++) {
- struct csd_call *call = l->data;
- int status, direction, multiparty;
-
- status = csd_status_to_hfp(call);
- if (status < 0)
- continue;
-
- direction = call->originating ?
- CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
- multiparty = call->conference ?
- CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
- telephony_list_current_call_ind(i, direction, status,
- CALL_MODE_VOICE, multiparty,
- call->number,
- number_type(call->number));
- }
-
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
- net.operator_name ? net.operator_name : "");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_call_with_status(int status,
- int (*func)(struct csd_call *call))
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- func(call);
- }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- const char *idx;
- struct csd_call *call;
- int err = 0;
-
- DBG("telephony-maemo: got call hold request %s", cmd);
-
- if (strlen(cmd) > 1)
- idx = &cmd[1];
- else
- idx = NULL;
-
- if (idx)
- call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
- else
- call = NULL;
-
- switch (cmd[0]) {
- case '0':
- foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call);
- foreach_call_with_status(CSD_CALL_STATUS_WAITING,
- release_call);
- break;
- case '1':
- if (idx) {
- if (call)
- err = release_call(call);
- break;
- }
- foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
- if (call)
- err = answer_call(call);
- break;
- case '2':
- if (idx) {
- if (call)
- err = split_call(call);
- } else {
- struct csd_call *held, *wait;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- held = find_call_with_status(CSD_CALL_STATUS_HOLD);
- wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (wait)
- err = answer_call(wait);
- else if (call && held)
- err = swap_calls();
- else {
- if (call)
- err = hold_call(call);
- if (held)
- err = unhold_call(held);
- }
- }
- break;
- case '3':
- if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
- find_call_with_status(CSD_CALL_STATUS_WAITING))
- err = create_conference();
- break;
- case '4':
- err = call_transfer();
- break;
- default:
- DBG("Unknown call hold request");
- break;
- }
-
- if (err)
- telephony_call_hold_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo: got %s NR and EC request",
- enable ? "enable" : "disable");
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- struct csd_call *active, *waiting;
- int err;
-
- DBG("telephony-maemo: got key press request for %s", keys);
-
- waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
- if (waiting)
- err = answer_call(waiting);
- else if (active)
- err = release_call(active);
- else
- err = 0;
-
- if (err < 0)
- telephony_key_press_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo: got %s voice dial request",
- enable ? "enable" : "disable");
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Coming() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Incoming call to %s from number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
-
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(call->number,
- number_type(call->number));
- else
- telephony_incoming_call_ind(call->number,
- number_type(call->number));
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Created() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Outgoing call from %s to number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- g_free(last_dialed_number);
- last_dialed_number = g_strdup(number);
-
- if (create_request_timer) {
- g_source_remove(create_request_timer);
- create_request_timer = 0;
- }
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- create_request_timer = 0;
- return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
- DBG("Call.CreateRequested()");
-
- if (create_request_timer)
- g_source_remove(create_request_timer);
-
- create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
- struct csd_call *call;
- dbus_uint32_t status, cause_type, cause;
- int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_UINT32, &cause_type,
- DBUS_TYPE_UINT32, &cause,
- DBUS_TYPE_INVALID)) {
- error("Unexpected paramters in Instance.CallStatus() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- if (status > 16) {
- error("Invalid call status %u", status);
- return;
- }
-
- DBG("Call %s changed from %s to %s", call_path,
- call_status_str[call->status], call_status_str[status]);
-
- if (call->status == (int) status) {
- DBG("Ignoring CSD Call state change to existing state");
- return;
- }
-
- call->status = (int) status;
-
- switch (status) {
- case CSD_CALL_STATUS_IDLE:
- if (call->setup) {
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- }
-
- g_free(call->number);
- call->number = NULL;
- call->originating = FALSE;
- call->emergency = FALSE;
- call->on_hold = FALSE;
- call->conference = FALSE;
- call->setup = FALSE;
- break;
- case CSD_CALL_STATUS_CREATE:
- call->originating = TRUE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_COMING:
- call->originating = FALSE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_PROCEEDING:
- break;
- case CSD_CALL_STATUS_MO_ALERTING:
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
- break;
- case CSD_CALL_STATUS_MT_ALERTING:
- break;
- case CSD_CALL_STATUS_WAITING:
- break;
- case CSD_CALL_STATUS_ANSWERED:
- break;
- case CSD_CALL_STATUS_ACTIVE:
- if (call->on_hold) {
- call->on_hold = FALSE;
- if (find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- } else {
- if (!g_slist_find(active_calls, call))
- active_calls = g_slist_prepend(active_calls, call);
- if (g_slist_length(active_calls) == 1)
- telephony_update_indicator(maemo_indicators,
- "call",
- EV_CALL_ACTIVE);
- /* Upgrade callheld status if necessary */
- if (callheld == EV_CALLHELD_ON_HOLD)
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- call->setup = FALSE;
- }
- break;
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- active_calls = g_slist_remove(active_calls, call);
- if (g_slist_length(active_calls) == 0)
- telephony_update_indicator(maemo_indicators, "call",
- EV_CALL_INACTIVE);
- break;
- case CSD_CALL_STATUS_HOLD_INITIATED:
- break;
- case CSD_CALL_STATUS_HOLD:
- call->on_hold = TRUE;
- if (find_non_held_call())
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- break;
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- break;
- case CSD_CALL_STATUS_TERMINATED:
- if (call->on_hold &&
- !find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- else if (callheld == EV_CALLHELD_MULTIPLE &&
- find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_SWAP_INITIATED:
- break;
- default:
- error("Unknown call status %u", status);
- break;
- }
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
- const char *path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Conference.%s",
- dbus_message_get_member(msg));
- return;
- }
-
- call = find_call(path);
- if (!call) {
- error("Conference signal for unknown call %s", path);
- return;
- }
-
- DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
- call->conference = joined;
-}
-
-static void get_operator_name_reply(DBusPendingCall *pending_call,
- void *user_data)
-{
- DBusMessage *reply;
- DBusError err;
- const char *name;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(pending_call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("get_operator_name failed: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unexpected get_operator_name reply parameters: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- if (net_err != 0) {
- error("get_operator_name failed with code %d", net_err);
- goto done;
- }
-
- if (strlen(name) == 0)
- goto done;
-
- g_free(net.operator_name);
- net.operator_name = g_strdup(name);
-
- DBG("telephony-maemo: operator name updated: %s", name);
-
-done:
- dbus_message_unref(reply);
-}
-
-static void resolve_operator_name(uint32_t operator, uint32_t country)
-{
- uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
-
- send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_operator_name",
- get_operator_name_reply, NULL,
- DBUS_TYPE_BYTE, &name_type,
- DBUS_TYPE_UINT32, &operator,
- DBUS_TYPE_UINT32, &country,
- DBUS_TYPE_INVALID);
-}
-
-static void update_registration_status(uint8_t status, uint16_t lac,
- uint32_t cell_id,
- uint32_t operator_code,
- uint32_t country_code,
- uint8_t network_type,
- uint8_t supported_services)
-{
- if (net.status != status) {
- switch (status) {
- case NETWORK_REG_STATUS_HOME:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_INACTIVE);
- if (net.status >= NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_ROAM:
- case NETWORK_REG_STATUS_ROAM_BLINK:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_ACTIVE);
- if (net.status >= NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_NOSERV:
- case NETWORK_REG_STATUS_NOSERV_SEARCHING:
- case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
- case NETWORK_REG_STATUS_NOSERV_NOSIM:
- case NETWORK_REG_STATUS_POWER_OFF:
- case NETWORK_REG_STATUS_NSPS:
- case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
- case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
- if (net.status < NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_NONE);
- break;
- }
-
- net.status = status;
- }
-
- net.lac = lac;
- net.cell_id = cell_id;
-
- if (net.operator_code != operator_code ||
- net.country_code != country_code) {
- g_free(net.operator_name);
- net.operator_name = NULL;
- resolve_operator_name(operator_code, country_code);
- net.operator_code = operator_code;
- net.country_code = country_code;
- }
-
- net.network_type = network_type;
- net.supported_services = supported_services;
-}
-
-static void handle_registration_status_change(DBusMessage *msg)
-{
- uint8_t status;
- dbus_uint16_t lac, network_type, supported_services;
- dbus_uint32_t cell_id, operator_code, country_code;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_BYTE, &status,
- DBUS_TYPE_UINT16, &lac,
- DBUS_TYPE_UINT32, &cell_id,
- DBUS_TYPE_UINT32, &operator_code,
- DBUS_TYPE_UINT32, &country_code,
- DBUS_TYPE_BYTE, &network_type,
- DBUS_TYPE_BYTE, &supported_services,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in registration_status_change");
- return;
- }
-
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
-}
-
-static void update_signal_strength(uint8_t signals_bar)
-{
- int signal;
-
- if (signals_bar > 100) {
- DBG("signals_bar greater than expected: %u", signals_bar);
- signals_bar = 100;
- }
-
- if (net.signals_bar == signals_bar)
- return;
-
- /* A simple conversion from 0-100 to 0-5 (used by HFP) */
- signal = (signals_bar + 20) / 21;
-
- telephony_update_indicator(maemo_indicators, "signal", signal);
-
- net.signals_bar = signals_bar;
-
- DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
-}
-
-static void handle_signal_strength_change(DBusMessage *msg)
-{
- uint8_t signals_bar, rssi_in_dbm;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_BYTE, &signals_bar,
- DBUS_TYPE_BYTE, &rssi_in_dbm,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in signal_strength_change");
- return;
- }
-
- update_signal_strength(signals_bar);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
- int first_arg_type, ...)
-{
- int type;
- va_list ap;
-
- va_start(ap, first_arg_type);
-
- for (type = first_arg_type; type != DBUS_TYPE_INVALID;
- type = va_arg(ap, int)) {
- void *value = va_arg(ap, void *);
- int real_type = dbus_message_iter_get_arg_type(iter);
-
- if (real_type != type) {
- error("iter_get_basic_args: expected %c but got %c",
- (char) type, (char) real_type);
- break;
- }
-
- dbus_message_iter_get_basic(iter, value);
- dbus_message_iter_next(iter);
- }
-
- va_end(ap);
-
- return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- dbus_int32_t level;
- int *value = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (dbus_message_get_args(reply, &err,
- DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse GetPropertyInteger reply: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- *value = (int) level;
-
- if (value == &battchg_last)
- DBG("telephony-maemo: battery.charge_level.last_full is %d",
- *value);
- else if (value == &battchg_design)
- DBG("telephony-maemo: battery.charge_level.design is %d",
- *value);
- else
- DBG("telephony-maemo: battery.charge_level.current is %d",
- *value);
-
- if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
- int new, max;
-
- if (battchg_last > 0)
- max = battchg_last;
- else
- max = battchg_design;
-
- new = battchg_cur * 5 / max;
-
- telephony_update_indicator(maemo_indicators, "battchg", new);
- }
-done:
- dbus_message_unref(reply);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
- send_method_call("org.freedesktop.Hal", path,
- "org.freedesktop.Hal.Device",
- "GetPropertyInteger",
- hal_battery_level_reply, user_data,
- DBUS_TYPE_STRING, &key,
- DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
- DBusMessageIter iter, array;
- dbus_int32_t num_changes;
- const char *path;
-
- path = dbus_message_get_path(msg);
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_get_basic(&iter, &num_changes);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_recurse(&iter, &array);
-
- while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
- DBusMessageIter prop;
- const char *name;
- dbus_bool_t added, removed;
-
- dbus_message_iter_recurse(&array, &prop);
-
- if (!iter_get_basic_args(&prop,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &added,
- DBUS_TYPE_BOOLEAN, &removed,
- DBUS_TYPE_INVALID)) {
- error("Invalid hal PropertyModified parameters");
- break;
- }
-
- if (g_str_equal(name, "battery.charge_level.last_full"))
- hal_get_integer(path, name, &battchg_last);
- else if (g_str_equal(name, "battery.charge_level.current"))
- hal_get_integer(path, name, &battchg_cur);
- else if (g_str_equal(name, "battery.charge_level.design"))
- hal_get_integer(path, name, &battchg_design);
-
- dbus_message_iter_next(&array);
- }
-}
-
-static void csd_call_free(struct csd_call *call)
-{
- if (!call)
- return;
-
- g_free(call->object_path);
- g_free(call->number);
-
- g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
- do {
- DBusMessageIter call_iter;
- struct csd_call *call;
- const char *object_path, *number;
- dbus_uint32_t status;
- dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
- error("Unexpected signature in GetCallInfoAll reply");
- break;
- }
-
- dbus_message_iter_recurse(iter, &call_iter);
-
- if (!iter_get_basic_args(&call_iter,
- DBUS_TYPE_OBJECT_PATH, &object_path,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_BOOLEAN, &originating,
- DBUS_TYPE_BOOLEAN, &terminating,
- DBUS_TYPE_BOOLEAN, &emerg,
- DBUS_TYPE_BOOLEAN, &on_hold,
- DBUS_TYPE_BOOLEAN, &conf,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Parsing call D-Bus parameters failed");
- break;
- }
-
- call = find_call(object_path);
- if (!call) {
- call = g_new0(struct csd_call, 1);
- call->object_path = g_strdup(object_path);
- call->status = (int) status;
- calls = g_slist_append(calls, call);
- DBG("telephony-maemo: new csd call instance at %s",
- object_path);
- }
-
- if (call->status == CSD_CALL_STATUS_IDLE)
- continue;
-
- /* CSD gives incorrect call_hold property sometimes */
- if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
- (call->status == CSD_CALL_STATUS_HOLD &&
- !on_hold)) {
- error("Conflicting call status and on_hold property!");
- on_hold = call->status == CSD_CALL_STATUS_HOLD;
- }
-
- call->originating = originating;
- call->on_hold = on_hold;
- call->conference = conf;
- g_free(call->number);
- call->number = g_strdup(number);
-
- } while (dbus_message_iter_next(iter));
-}
-
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- uint8_t signals_bar, rssi_in_dbm;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("Unable to get signal strength: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_BYTE, &signals_bar,
- DBUS_TYPE_BYTE, &rssi_in_dbm,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unable to parse signal_strength reply: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- return;
- }
-
- if (net_err != 0) {
- error("get_signal_strength failed with code %d", net_err);
- return;
- }
-
- update_signal_strength(signals_bar);
-
-done:
- dbus_message_unref(reply);
-}
-
-static int get_signal_strength(void)
-{
- return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_signal_strength",
- signal_strength_reply, NULL,
- DBUS_TYPE_INVALID);
-}
-
-static void registration_status_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- uint8_t status;
- dbus_uint16_t lac, network_type, supported_services;
- dbus_uint32_t cell_id, operator_code, country_code;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("Unable to get registration status: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_BYTE, &status,
- DBUS_TYPE_UINT16, &lac,
- DBUS_TYPE_UINT32, &cell_id,
- DBUS_TYPE_UINT32, &operator_code,
- DBUS_TYPE_UINT32, &country_code,
- DBUS_TYPE_BYTE, &network_type,
- DBUS_TYPE_BYTE, &supported_services,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unable to parse registration_status_change reply:"
- " %s, %s", err.name, err.message);
- dbus_error_free(&err);
- return;
- }
-
- if (net_err != 0) {
- error("get_registration_status failed with code %d", net_err);
- return;
- }
-
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
-
- get_signal_strength();
-
-done:
- dbus_message_unref(reply);
-}
-
-static int get_registration_status(void)
-{
- return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_registration_status",
- registration_status_reply, NULL,
- DBUS_TYPE_INVALID);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
-
- get_calls_active = FALSE;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in GetCallInfoAll return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- parse_call_list(&sub);
-
- get_registration_status();
-
-done:
- dbus_message_unref(reply);
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
- const char *path;
- char match_string[256];
- int type;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in FindDeviceByCapability return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- type = dbus_message_iter_get_arg_type(&sub);
-
- if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
- error("No hal device with battery capability found");
- goto done;
- }
-
- dbus_message_iter_get_basic(&sub, &path);
-
- DBG("telephony-maemo: found battery device at %s", path);
-
- snprintf(match_string, sizeof(match_string),
- "type='signal',"
- "path='%s',"
- "interface='org.freedesktop.Hal.Device',"
- "member='PropertyModified'", path);
- dbus_bus_add_match(connection, match_string, NULL);
-
- hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
- hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
- hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
- dbus_message_unref(reply);
-}
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError derr;
- DBusMessage *reply;
- const char *name, *number;
- char **number_type = user_data;
- dbus_int32_t current_location, err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- error("SIM.Phonebook replied with an error: %s, %s",
- derr.name, derr.message);
- dbus_error_free(&derr);
- goto done;
- }
-
- dbus_error_init(&derr);
- if (dbus_message_get_args(reply, &derr,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INT32, ¤t_location,
- DBUS_TYPE_INT32, &err,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
- derr.name, derr.message);
- dbus_error_free(&derr);
- goto done;
- }
-
- if (err != 0) {
- error("SIM.Phonebook.read failed with error %d", err);
- if (number_type == &vmbx)
- vmbx = g_strdup(getenv("VMBX_NUMBER"));
- goto done;
- }
-
- if (number_type == &msisdn) {
- g_free(msisdn);
- msisdn = g_strdup(number);
- DBG("Got MSISDN %s (%s)", number, name);
- } else {
- g_free(vmbx);
- vmbx = g_strdup(number);
- DBG("Got voice mailbox number %s (%s)", number, name);
- }
-
-done:
- dbus_message_unref(reply);
-}
-
-static void csd_init(void)
-{
- dbus_uint32_t location;
- uint8_t pb_type, location_type;
- int ret;
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "GetCallInfoAll",
- call_info_reply, NULL, DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to sent GetCallInfoAll method call");
- return;
- }
-
- get_calls_active = TRUE;
-
- pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
- phonebook_read_reply, &msisdn,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return;
- }
-
- pb_type = SIM_PHONEBOOK_TYPE_MBDN;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
- phonebook_read_reply, &vmbx,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return;
- }
-}
-
-static uint32_t get_callflag(const char *callerid_setting)
-{
- if (callerid_setting != NULL) {
- if (g_str_equal(callerid_setting, "allowed"))
- return CALL_FLAG_PRESENTATION_ALLOWED;
- else if (g_str_equal(callerid_setting, "restricted"))
- return CALL_FLAG_PRESENTATION_RESTRICTED;
- else
- return CALL_FLAG_NONE;
- } else
- return CALL_FLAG_NONE;
-}
-
-static void generate_flag_file(const char *filename)
-{
- int fd;
-
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
- g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
- g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- return;
-
- fd = open(filename, O_WRONLY | O_CREAT, 0);
- if (fd >= 0)
- close(fd);
-}
-
-static void save_callerid_to_file(const char *callerid_setting)
-{
- char callerid_file[FILENAME_MAX];
-
- snprintf(callerid_file, sizeof(callerid_file), "%s%s",
- CALLERID_BASE, callerid_setting);
-
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(ALLOWED_FLAG_FILE, callerid_file);
- else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(RESTRICTED_FLAG_FILE, callerid_file);
- else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(NONE_FLAG_FILE, callerid_file);
- else
- generate_flag_file(callerid_file);
-}
-
-static uint32_t callerid_from_file(void)
-{
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_PRESENTATION_ALLOWED;
- else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_PRESENTATION_RESTRICTED;
- else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_NONE;
- else
- return CALL_FLAG_NONE;
-}
-
-static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *callerid_setting;
-
- if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
- &callerid_setting,
- DBUS_TYPE_INVALID) == FALSE)
- return btd_error_invalid_args(msg);
-
- if (g_str_equal(callerid_setting, "allowed") ||
- g_str_equal(callerid_setting, "restricted") ||
- g_str_equal(callerid_setting, "none")) {
- save_callerid_to_file(callerid_setting);
- callerid = get_callflag(callerid_setting);
- DBG("telephony-maemo setting callerid flag: %s",
- callerid_setting);
- return dbus_message_new_method_return(msg);
- }
-
- error("telephony-maemo: invalid argument %s for method call"
- " SetCallerId", callerid_setting);
- return btd_error_invalid_args(msg);
-}
-
-static GDBusMethodTable telephony_maemo_methods[] = {
- {"SetCallerId", "s", "", set_callerid,
- G_DBUS_METHOD_FLAG_ASYNC},
- { }
-};
-
-static void handle_modem_state(DBusMessage *msg)
-{
- const char *state;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
- DBUS_TYPE_INVALID)) {
- error("Unexpected modem state parameters");
- return;
- }
-
- DBG("SSC modem state: %s", state);
-
- if (calls != NULL || get_calls_active)
- return;
-
- if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
- csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("get_modem_status: %s, %s", err.name, err.message);
- dbus_error_free(&err);
- } else
- handle_modem_state(reply);
-
- dbus_message_unref(reply);
-}
-
-static DBusHandlerResult signal_filter(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path = dbus_message_get_path(msg);
-
- if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
- handle_incoming_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
- handle_outgoing_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
- "CreateRequested"))
- handle_create_requested(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
- handle_call_status(msg, path);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
- handle_conference(msg, TRUE);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
- handle_conference(msg, FALSE);
- else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
- "registration_status_change"))
- handle_registration_status_change(msg);
- else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
- "signal_strength_change"))
- handle_signal_strength_change(msg);
- else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
- "PropertyModified"))
- handle_hal_property_modified(msg);
- else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
- "modem_state_changed_ind"))
- handle_modem_state(msg);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-int telephony_init(void)
-{
- const char *battery_cap = "battery";
- uint32_t features = AG_FEATURE_EC_ANDOR_NR |
- AG_FEATURE_INBAND_RINGTONE |
- AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_ENHANCED_CALL_CONTROL |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
- AG_FEATURE_THREE_WAY_CALLING;
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- if (!dbus_connection_add_filter(connection, signal_filter,
- NULL, NULL))
- error("Can't add signal filter");
-
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_INTERFACE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_INSTANCE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" NETWORK_INTERFACE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" SSC_DBUS_IFACE
- ",member=modem_state_changed_ind", NULL);
-
- if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
- "get_modem_state", modem_state_reply,
- NULL, DBUS_TYPE_INVALID) < 0)
- error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
- generate_flag_file(NONE_FLAG_FILE);
- callerid = callerid_from_file();
-
- if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
- TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
- NULL, NULL, NULL, NULL)) {
- error("telephony-maemo interface %s init failed on path %s",
- TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
- }
-
- DBG("telephony-maemo registering %s interface on path %s",
- TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-
- telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
- if (send_method_call("org.freedesktop.Hal",
- "/org/freedesktop/Hal/Manager",
- "org.freedesktop.Hal.Manager",
- "FindDeviceByCapability",
- hal_find_device_reply, NULL,
- DBUS_TYPE_STRING, &battery_cap,
- DBUS_TYPE_INVALID) < 0)
- error("Unable to send HAL method call");
-
- return 0;
-}
-
-void telephony_exit(void)
-{
- g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
- g_slist_free(calls);
- calls = NULL;
-
- dbus_connection_remove_filter(connection, signal_filter, NULL);
-
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [RFC v3 4/6] audio: Remove maemo6 tel driver
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
` (2 preceding siblings ...)
2011-12-01 15:14 ` [RFC v3 3/6] audio: Remove maemo5 tel driver Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
2011-12-01 15:14 ` [RFC v3 5/6] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
2011-12-01 15:14 ` [RFC v3 6/6] audio: Send transport path to telephony agent Frédéric Danis
5 siblings, 0 replies; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
audio/telephony-maemo6.c | 2201 ----------------------------------------------
1 files changed, 0 insertions(+), 2201 deletions(-)
delete mode 100644 audio/telephony-maemo6.c
diff --git a/audio/telephony-maemo6.c b/audio/telephony-maemo6.c
deleted file mode 100644
index dd75422..0000000
--- a/audio/telephony-maemo6.c
+++ /dev/null
@@ -1,2201 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "glib-compat.h"
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define CSD_CSNET_BUS_NAME "com.nokia.csd.CSNet"
-#define CSD_CSNET_PATH "/com/nokia/csd/csnet"
-#define CSD_CSNET_IFACE "com.nokia.csd.CSNet"
-#define CSD_CSNET_REGISTRATION "com.nokia.csd.CSNet.NetworkRegistration"
-#define CSD_CSNET_OPERATOR "com.nokia.csd.CSNet.NetworkOperator"
-#define CSD_CSNET_SIGNAL "com.nokia.csd.CSNet.SignalStrength"
-
-enum net_registration_status {
- NETWORK_REG_STATUS_HOME,
- NETWORK_REG_STATUS_ROAMING,
- NETWORK_REG_STATUS_OFFLINE,
- NETWORK_REG_STATUS_SEARCHING,
- NETWORK_REG_STATUS_NO_SIM,
- NETWORK_REG_STATUS_POWEROFF,
- NETWORK_REG_STATUS_POWERSAFE,
- NETWORK_REG_STATUS_NO_COVERAGE,
- NETWORK_REG_STATUS_REJECTED,
- NETWORK_REG_STATUS_UNKOWN
-};
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE "com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH "/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE 0
-#define CSD_CALL_STATUS_CREATE 1
-#define CSD_CALL_STATUS_COMING 2
-#define CSD_CALL_STATUS_PROCEEDING 3
-#define CSD_CALL_STATUS_MO_ALERTING 4
-#define CSD_CALL_STATUS_MT_ALERTING 5
-#define CSD_CALL_STATUS_WAITING 6
-#define CSD_CALL_STATUS_ANSWERED 7
-#define CSD_CALL_STATUS_ACTIVE 8
-#define CSD_CALL_STATUS_MO_RELEASE 9
-#define CSD_CALL_STATUS_MT_RELEASE 10
-#define CSD_CALL_STATUS_HOLD_INITIATED 11
-#define CSD_CALL_STATUS_HOLD 12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
-#define CSD_CALL_STATUS_RECONNECT_PENDING 14
-#define CSD_CALL_STATUS_TERMINATED 15
-#define CSD_CALL_STATUS_SWAP_INITIATED 16
-
-#define CALL_FLAG_NONE 0
-#define CALL_FLAG_PRESENTATION_ALLOWED 0x01
-#define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
-
-/* SIM Phonebook D-Bus definitions */
-#define CSD_SIMPB_BUS_NAME "com.nokia.csd.SIM"
-#define CSD_SIMPB_INTERFACE "com.nokia.csd.SIM.Phonebook"
-#define CSD_SIMPB_PATH "/com/nokia/csd/sim/phonebook"
-
-#define CSD_SIMPB_TYPE_ADN "ADN"
-#define CSD_SIMPB_TYPE_FDN "FDN"
-#define CSD_SIMPB_TYPE_SDN "SDN"
-#define CSD_SIMPB_TYPE_VMBX "VMBX"
-#define CSD_SIMPB_TYPE_MBDN "MBDN"
-#define CSD_SIMPB_TYPE_EN "EN"
-#define CSD_SIMPB_TYPE_MSISDN "MSISDN"
-
-/* OHM plugin D-Bus definitions */
-#define OHM_BUS_NAME "com.nokia.NonGraphicFeedback1"
-#define OHM_INTERFACE "com.nokia.NonGraphicFeedback1"
-#define OHM_PATH "/com/nokia/NonGraphicFeedback1"
-
-/* tone-genenerator D-Bus definitions */
-#define TONEGEN_BUS_NAME "com.Nokia.Telephony.Tones"
-#define TONEGEN_INTERFACE "com.Nokia.Telephony.Tones"
-#define TONEGEN_PATH "/com/Nokia/Telephony/Tones"
-
-/* tone-generator DTMF definitions */
-#define DTMF_ASTERISK 10
-#define DTMF_HASHMARK 11
-#define DTMF_A 12
-#define DTMF_B 13
-#define DTMF_C 14
-#define DTMF_D 15
-
-#define FEEDBACK_TONE_DURATION 200
-
-struct csd_call {
- char *object_path;
- int status;
- gboolean originating;
- gboolean emergency;
- gboolean on_hold;
- gboolean conference;
- char *number;
- gboolean setup;
-};
-
-static struct {
- char *operator_name;
- uint8_t status;
- int32_t signal_bars;
-} net = {
- .operator_name = NULL,
- .status = NETWORK_REG_STATUS_UNKOWN,
- /* Init as 0 meaning inactive mode. In modem power off state
- * can be be -1, but we treat all values as 0s regardless
- * inactive or power off. */
- .signal_bars = 0,
-};
-
-struct pending_req {
- DBusPendingCall *call;
- void *user_data;
-};
-
-static int get_property(const char *iface, const char *prop);
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-static GSList *watches = NULL;
-static GSList *pending = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-/* Queue of DTMF tones to play */
-static GSList *tones = NULL;
-static guint create_tones_timer = 0;
-
-static char *msisdn = NULL; /* Subscriber number */
-static char *vmbx = NULL; /* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1; /* "battery.charge_level.current" */
-static int battchg_last = -1; /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- /* signal strength in terms of bars */
- { "signal", "0-5", 0, TRUE },
- { "service", "0,1", 0, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-static char *call_status_str[] = {
- "IDLE",
- "CREATE",
- "COMING",
- "PROCEEDING",
- "MO_ALERTING",
- "MT_ALERTING",
- "WAITING",
- "ANSWERED",
- "ACTIVE",
- "MO_RELEASE",
- "MT_RELEASE",
- "HOLD_INITIATED",
- "HOLD",
- "RETRIEVE_INITIATED",
- "RECONNECT_PENDING",
- "TERMINATED",
- "SWAP_INITIATED",
- "???"
-};
-
-static int send_method_call(const char *dest, const char *path,
- const char *interface, const char *method,
- DBusPendingCallNotifyFunction cb,
- void *user_data, int type, ...)
-{
- DBusMessage *msg;
- DBusPendingCall *call;
- va_list args;
- struct pending_req *req;
-
- msg = dbus_message_new_method_call(dest, path, interface, method);
- if (!msg) {
- error("Unable to allocate new D-Bus %s message", method);
- return -ENOMEM;
- }
-
- va_start(args, type);
-
- if (!dbus_message_append_args_valist(msg, type, args)) {
- dbus_message_unref(msg);
- va_end(args);
- return -EIO;
- }
-
- va_end(args);
-
- if (!cb) {
- g_dbus_send_message(connection, msg);
- return 0;
- }
-
- if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
- error("Sending %s failed", method);
- dbus_message_unref(msg);
- return -EIO;
- }
-
- dbus_pending_call_set_notify(call, cb, user_data, NULL);
-
- req = g_new0(struct pending_req, 1);
- req->call = call;
- req->user_data = user_data;
-
- pending = g_slist_prepend(pending, req);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static struct csd_call *find_call(const char *path)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (g_str_equal(call->object_path, path))
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == CSD_CALL_STATUS_IDLE)
- continue;
-
- if (call->status != CSD_CALL_STATUS_HOLD)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status != CSD_CALL_STATUS_IDLE)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- return call;
- }
-
- return NULL;
-}
-
-static int release_conference(void)
-{
- DBusMessage *msg;
-
- DBG("telephony-maemo6: releasing conference call");
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- CSD_CALL_CONFERENCE_PATH,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Answer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static struct pending_req *find_request(const DBusPendingCall *call)
-{
- GSList *l;
-
- for (l = pending; l; l = l->next) {
- struct pending_req *req = l->data;
-
- if (req->call == call)
- return req;
- }
-
- return NULL;
-}
-
-static void pending_req_finalize(void *data)
-{
- struct pending_req *req = data;
-
- if (!dbus_pending_call_get_completed(req->call))
- dbus_pending_call_cancel(req->call);
-
- dbus_pending_call_unref(req->call);
- g_free(req);
-}
-
-static void remove_pending(DBusPendingCall *call)
-{
- struct pending_req *req = find_request(call);
-
- pending = g_slist_remove(pending, req);
- pending_req_finalize(req);
-}
-
-static void stop_ringtone_reply(DBusPendingCall *call, void *user_data)
-{
- struct csd_call *coming = user_data;
-
- remove_pending(call);
- answer_call(coming);
-}
-
-static int stop_ringtone_and_answer(struct csd_call *call)
-{
- int ret;
-
- ret = send_method_call(OHM_BUS_NAME, OHM_PATH,
- OHM_INTERFACE, "StopRingtone",
- stop_ringtone_reply, call,
- DBUS_TYPE_INVALID);
- if (ret < 0)
- return answer_call(call);
-
- return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Split");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Unhold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Hold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int swap_calls(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Swap");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int create_conference(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Conference");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int call_transfer(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Transfer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int number_type(const char *number)
-{
- if (number == NULL)
- return NUMBER_TYPE_TELEPHONY;
-
- if (number[0] == '+' || strncmp(number, "00", 2) == 0)
- return NUMBER_TYPE_INTERNATIONAL;
-
- return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
- struct csd_call *coming;
-
- DBG("telephony-maemo6: device %p connected", telephony_device);
-
- coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (coming) {
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(coming->number,
- number_type(coming->number));
- else
- telephony_incoming_call_ind(coming->number,
- number_type(coming->number));
- }
-}
-
-static void remove_pending_by_data(gpointer data, gpointer user_data)
-{
- struct pending_req *req = data;
-
- if (req->user_data == user_data) {
- pending = g_slist_remove(pending, req);
- pending_req_finalize(req);
- }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-maemo6: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-
- g_slist_foreach(pending, remove_pending_by_data, telephony_device);
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- struct csd_call *call;
- struct csd_call *alerting;
- int err;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- if (!call)
- call = find_non_idle_call();
-
- if (!call) {
- error("No active call");
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
- if (call->on_hold && alerting)
- err = release_call(alerting);
- else if (call->conference)
- err = release_conference();
- else
- err = release_call(call);
-
- if (err < 0)
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- struct csd_call *call;
-
- call = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (!call) {
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- if (stop_ringtone_and_answer(call) < 0)
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void create_call_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- void *telephony_device = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
- if (g_strcmp0(err.name,
- "com.nokia.csd.Call.Error.CSInactive") == 0)
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_NO_NETWORK_SERVICE);
- else
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- dbus_error_free(&err);
- } else
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- int ret;
-
- DBG("telephony-maemo6: last dialed number request");
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "CreateFromLast",
- create_call_reply, telephony_device,
- DBUS_TYPE_INVALID);
- if (ret < 0)
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
-}
-
-static const char *memory_dial_lookup(int location)
-{
- if (location == 1)
- return vmbx;
- else
- return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- int ret;
-
- DBG("telephony-maemo6: dial request to %s", number);
-
- if (strncmp(number, "*31#", 4) == 0)
- number += 4;
- else if (strncmp(number, "#31#", 4) == 0)
- number += 4;
- else if (number[0] == '>') {
- const char *location = &number[1];
-
- number = memory_dial_lookup(strtol(&number[1], NULL, 0));
- if (!number) {
- error("No number at memory location %s", location);
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_INVALID_INDEX);
- return;
- }
- }
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "Create",
- create_call_reply, telephony_device,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID);
- if (ret < 0)
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
-}
-
-static void start_dtmf_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
-
- dbus_error_free(&err);
- } else
- send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "StopDTMF",
- NULL, NULL,
- DBUS_TYPE_INVALID);
-
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void start_dtmf(void *telephony_device, char tone)
-{
- int ret;
-
- /*
- * Stop tone immediately, modem will place it in queue and play
- * required time.
- */
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "StartDTMF",
- start_dtmf_reply, NULL,
- DBUS_TYPE_BYTE, &tone,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- telephony_transmit_dtmf_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int tonegen_startevent(char tone)
-{
- int ret;
- dbus_uint32_t event_tone;
- dbus_int32_t dbm0 = -15;
- dbus_uint32_t duration = 150;
-
- switch (tone) {
- case '*':
- event_tone = DTMF_ASTERISK;
- break;
- case '#':
- event_tone = DTMF_HASHMARK;
- break;
- case 'A':
- event_tone = DTMF_A;
- break;
- case 'B':
- event_tone = DTMF_B;
- break;
- case 'C':
- event_tone = DTMF_C;
- break;
- case 'D':
- event_tone = DTMF_D;
- break;
- default:
- ret = g_ascii_digit_value(tone);
- if (ret < 0)
- return -EINVAL;
- event_tone = ret;
- }
-
- ret = send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
- TONEGEN_INTERFACE, "StartEventTone",
- NULL, NULL,
- DBUS_TYPE_UINT32, &event_tone,
- DBUS_TYPE_INT32, &dbm0,
- DBUS_TYPE_UINT32, &duration,
- DBUS_TYPE_INVALID);
- return ret;
-}
-
-static gboolean stop_feedback_tone(gpointer user_data)
-{
- if (g_slist_length(tones) > 0) {
- gpointer ptone;
- int ret;
-
- send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
- TONEGEN_INTERFACE, "StopTone",
- NULL, NULL,
- DBUS_TYPE_INVALID);
-
- ptone = g_slist_nth_data(tones, 0);
- tones = g_slist_remove(tones, ptone);
-
- ret = tonegen_startevent(GPOINTER_TO_UINT(ptone));
- if (ret < 0)
- goto done;
-
- return TRUE;
- }
-done:
- return FALSE;
-}
-
-static void tones_timer_notify(gpointer data)
-{
- send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
- TONEGEN_INTERFACE, "StopTone",
- NULL, NULL,
- DBUS_TYPE_INVALID);
- g_slist_free(tones);
- tones = NULL;
-
- create_tones_timer = 0;
-}
-
-static void start_feedback_tone(char tone)
-{
- if (!create_tones_timer) {
- int ret;
-
- ret = tonegen_startevent(tone);
- if (ret < 0)
- return;
-
- create_tones_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
- FEEDBACK_TONE_DURATION,
- stop_feedback_tone,
- NULL,
- tones_timer_notify);
- } else {
- glong dtmf_tone = tone;
-
- DBG("add %c to queue", tone);
- tones = g_slist_append(tones, GUINT_TO_POINTER(dtmf_tone));
- }
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- DBG("telephony-maemo6: transmit dtmf: %c", tone);
-
- start_dtmf(telephony_device, tone);
-
- if (!find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- error("No active call");
- else
- start_feedback_tone(tone);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-maemo6: subscriber number request");
- if (msisdn)
- telephony_subscriber_number_ind(msisdn,
- number_type(msisdn),
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
- switch (call->status) {
- case CSD_CALL_STATUS_IDLE:
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- case CSD_CALL_STATUS_TERMINATED:
- return -1;
- case CSD_CALL_STATUS_CREATE:
- return CALL_STATUS_DIALING;
- case CSD_CALL_STATUS_WAITING:
- return CALL_STATUS_WAITING;
- case CSD_CALL_STATUS_PROCEEDING:
- /* PROCEEDING can happen in outgoing/incoming */
- if (call->originating)
- return CALL_STATUS_DIALING;
-
- /*
- * PROCEEDING is followed by WAITING CSD status, therefore
- * second incoming call status indication is set immediately
- * to waiting.
- */
- if (g_slist_length(active_calls) > 0)
- return CALL_STATUS_WAITING;
-
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_COMING:
- if (g_slist_length(active_calls) > 0)
- return CALL_STATUS_WAITING;
-
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_MO_ALERTING:
- return CALL_STATUS_ALERTING;
- case CSD_CALL_STATUS_MT_ALERTING:
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_ANSWERED:
- case CSD_CALL_STATUS_ACTIVE:
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- case CSD_CALL_STATUS_SWAP_INITIATED:
- case CSD_CALL_STATUS_HOLD_INITIATED:
- return CALL_STATUS_ACTIVE;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- case CSD_CALL_STATUS_HOLD:
- return CALL_STATUS_HELD;
- default:
- return -1;
- }
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- GSList *l;
- int i;
-
- DBG("telephony-maemo6: list current calls request");
-
- for (l = calls, i = 1; l != NULL; l = l->next, i++) {
- struct csd_call *call = l->data;
- int status, direction, multiparty;
-
- status = csd_status_to_hfp(call);
- if (status < 0)
- continue;
-
- direction = call->originating ?
- CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
- multiparty = call->conference ?
- CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
- telephony_list_current_call_ind(i, direction, status,
- CALL_MODE_VOICE, multiparty,
- call->number,
- number_type(call->number));
- }
-
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
- net.operator_name ? net.operator_name : "");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_call_with_status(int status,
- int (*func)(struct csd_call *call))
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- func(call);
- }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- const char *idx;
- struct csd_call *call;
- int err = 0;
-
- DBG("telephony-maemo6: got call hold request %s", cmd);
-
- if (strlen(cmd) > 1)
- idx = &cmd[1];
- else
- idx = NULL;
-
- if (idx)
- call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
- else
- call = NULL;
-
- switch (cmd[0]) {
- case '0':
- if (find_call_with_status(CSD_CALL_STATUS_WAITING))
- foreach_call_with_status(CSD_CALL_STATUS_WAITING,
- release_call);
- else
- foreach_call_with_status(CSD_CALL_STATUS_HOLD,
- release_call);
- break;
- case '1':
- if (idx) {
- if (call)
- err = release_call(call);
- break;
- }
- foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
- if (call)
- err = answer_call(call);
- break;
- case '2':
- if (idx) {
- if (call)
- err = split_call(call);
- } else {
- struct csd_call *held, *wait;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- held = find_call_with_status(CSD_CALL_STATUS_HOLD);
- wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (wait)
- err = answer_call(wait);
- else if (call && held)
- err = swap_calls();
- else {
- if (call)
- err = hold_call(call);
- if (held)
- err = unhold_call(held);
- }
- }
- break;
- case '3':
- if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
- find_call_with_status(CSD_CALL_STATUS_WAITING))
- err = create_conference();
- break;
- case '4':
- err = call_transfer();
- break;
- default:
- DBG("Unknown call hold request");
- break;
- }
-
- if (err)
- telephony_call_hold_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo6: got %s NR and EC request",
- enable ? "enable" : "disable");
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- struct csd_call *active, *waiting;
- int err;
-
- DBG("telephony-maemo6: got key press request for %s", keys);
-
- waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
- if (waiting)
- err = answer_call(waiting);
- else if (active)
- err = release_call(active);
- else
- err = 0;
-
- if (err < 0)
- telephony_key_press_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo6: got %s voice dial request",
- enable ? "enable" : "disable");
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Coming() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Incoming call to %s from number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
- find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_call_waiting_ind(call->number,
- number_type(call->number));
- else
- telephony_incoming_call_ind(call->number,
- number_type(call->number));
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Created() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Outgoing call from %s to number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- if (create_request_timer) {
- g_source_remove(create_request_timer);
- create_request_timer = 0;
- }
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- create_request_timer = 0;
- return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
- DBG("Call.CreateRequested()");
-
- if (create_request_timer)
- g_source_remove(create_request_timer);
-
- create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
-}
-
-static void call_set_status(struct csd_call *call, dbus_uint32_t status)
-{
- dbus_uint32_t prev_status;
- int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
- prev_status = call->status;
- DBG("Call %s changed from %s to %s", call->object_path,
- call_status_str[prev_status], call_status_str[status]);
-
- if (prev_status == status) {
- DBG("Ignoring CSD Call state change to existing state");
- return;
- }
-
- call->status = (int) status;
-
- switch (status) {
- case CSD_CALL_STATUS_IDLE:
- if (call->setup) {
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- }
-
- g_free(call->number);
- call->number = NULL;
- call->originating = FALSE;
- call->emergency = FALSE;
- call->on_hold = FALSE;
- call->conference = FALSE;
- call->setup = FALSE;
- break;
- case CSD_CALL_STATUS_CREATE:
- call->originating = TRUE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_COMING:
- call->originating = FALSE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_PROCEEDING:
- break;
- case CSD_CALL_STATUS_MO_ALERTING:
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
- break;
- case CSD_CALL_STATUS_MT_ALERTING:
- /* Some headsets expect incoming call notification before they
- * can send ATA command. When call changed status from waiting
- * to alerting we need to send missing notification. Otherwise
- * headsets like Nokia BH-108 or BackBeat 903 are unable to
- * answer incoming call that was previously waiting. */
- if (prev_status == CSD_CALL_STATUS_WAITING)
- telephony_incoming_call_ind(call->number,
- number_type(call->number));
- break;
- case CSD_CALL_STATUS_WAITING:
- break;
- case CSD_CALL_STATUS_ANSWERED:
- break;
- case CSD_CALL_STATUS_ACTIVE:
- if (call->on_hold) {
- call->on_hold = FALSE;
- if (find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- } else {
- if (!g_slist_find(active_calls, call))
- active_calls = g_slist_prepend(active_calls, call);
- if (g_slist_length(active_calls) == 1)
- telephony_update_indicator(maemo_indicators,
- "call",
- EV_CALL_ACTIVE);
- /* Upgrade callheld status if necessary */
- if (callheld == EV_CALLHELD_ON_HOLD)
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- call->setup = FALSE;
- }
- break;
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- active_calls = g_slist_remove(active_calls, call);
- if (g_slist_length(active_calls) == 0)
- telephony_update_indicator(maemo_indicators, "call",
- EV_CALL_INACTIVE);
-
- if (create_tones_timer)
- g_source_remove(create_tones_timer);
- break;
- case CSD_CALL_STATUS_HOLD_INITIATED:
- break;
- case CSD_CALL_STATUS_HOLD:
- call->on_hold = TRUE;
- if (find_non_held_call())
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- break;
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- break;
- case CSD_CALL_STATUS_TERMINATED:
- if (call->on_hold &&
- !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- return;
- }
-
- if (callheld == EV_CALLHELD_MULTIPLE &&
- find_call_with_status(CSD_CALL_STATUS_HOLD) &&
- !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_SWAP_INITIATED:
- break;
- default:
- error("Unknown call status %u", status);
- break;
- }
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
- struct csd_call *call;
- dbus_uint32_t status, cause_type, cause;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_UINT32, &cause_type,
- DBUS_TYPE_UINT32, &cause,
- DBUS_TYPE_INVALID)) {
- error("Unexpected paramters in Instance.CallStatus() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- if (status > 16) {
- error("Invalid call status %u", status);
- return;
- }
-
- call_set_status(call, status);
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
- const char *path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Conference.%s",
- dbus_message_get_member(msg));
- return;
- }
-
- call = find_call(path);
- if (!call) {
- error("Conference signal for unknown call %s", path);
- return;
- }
-
- DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
- call->conference = joined;
-}
-
-static uint8_t str2status(const char *state)
-{
- if (g_strcmp0(state, "Home") == 0)
- return NETWORK_REG_STATUS_HOME;
- else if (g_strcmp0(state, "Roaming") == 0)
- return NETWORK_REG_STATUS_ROAMING;
- else if (g_strcmp0(state, "Offline") == 0)
- return NETWORK_REG_STATUS_OFFLINE;
- else if (g_strcmp0(state, "Searching") == 0)
- return NETWORK_REG_STATUS_SEARCHING;
- else if (g_strcmp0(state, "NoSim") == 0)
- return NETWORK_REG_STATUS_NO_SIM;
- else if (g_strcmp0(state, "Poweroff") == 0)
- return NETWORK_REG_STATUS_POWEROFF;
- else if (g_strcmp0(state, "Powersafe") == 0)
- return NETWORK_REG_STATUS_POWERSAFE;
- else if (g_strcmp0(state, "NoCoverage") == 0)
- return NETWORK_REG_STATUS_NO_COVERAGE;
- else if (g_strcmp0(state, "Reject") == 0)
- return NETWORK_REG_STATUS_REJECTED;
- else
- return NETWORK_REG_STATUS_UNKOWN;
-}
-
-static void update_registration_status(const char *status)
-{
- uint8_t new_status;
-
- new_status = str2status(status);
-
- if (net.status == new_status)
- return;
-
- switch (new_status) {
- case NETWORK_REG_STATUS_HOME:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_INACTIVE);
- if (net.status > NETWORK_REG_STATUS_ROAMING)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_ROAMING:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_ACTIVE);
- if (net.status > NETWORK_REG_STATUS_ROAMING)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_OFFLINE:
- case NETWORK_REG_STATUS_SEARCHING:
- case NETWORK_REG_STATUS_NO_SIM:
- case NETWORK_REG_STATUS_POWEROFF:
- case NETWORK_REG_STATUS_POWERSAFE:
- case NETWORK_REG_STATUS_NO_COVERAGE:
- case NETWORK_REG_STATUS_REJECTED:
- case NETWORK_REG_STATUS_UNKOWN:
- if (net.status < NETWORK_REG_STATUS_OFFLINE)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_NONE);
- break;
- }
-
- net.status = new_status;
-
- DBG("telephony-maemo6: registration status changed: %s", status);
-}
-
-static void handle_registration_changed(DBusMessage *msg)
-{
- const char *status;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &status,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in RegistrationChanged");
- return;
- }
-
- update_registration_status(status);
-}
-
-static void update_signal_strength(int32_t signal_bars)
-{
- if (signal_bars < 0) {
- DBG("signal strength smaller than expected: %d < 0",
- signal_bars);
- signal_bars = 0;
- } else if (signal_bars > 5) {
- DBG("signal strength greater than expected: %d > 5",
- signal_bars);
- signal_bars = 5;
- }
-
- if (net.signal_bars == signal_bars)
- return;
-
- telephony_update_indicator(maemo_indicators, "signal", signal_bars);
-
- net.signal_bars = signal_bars;
- DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
-}
-
-static void handle_signal_bars_changed(DBusMessage *msg)
-{
- int32_t signal_bars;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_INT32, &signal_bars,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in SignalBarsChanged");
- return;
- }
-
- update_signal_strength(signal_bars);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
- int first_arg_type, ...)
-{
- int type;
- va_list ap;
-
- va_start(ap, first_arg_type);
-
- for (type = first_arg_type; type != DBUS_TYPE_INVALID;
- type = va_arg(ap, int)) {
- void *value = va_arg(ap, void *);
- int real_type = dbus_message_iter_get_arg_type(iter);
-
- if (real_type != type) {
- error("iter_get_basic_args: expected %c but got %c",
- (char) type, (char) real_type);
- break;
- }
-
- dbus_message_iter_get_basic(iter, value);
- dbus_message_iter_next(iter);
- }
-
- va_end(ap);
-
- return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- dbus_int32_t level;
- int *value = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID)) {
- error("Unexpected args in hald reply");
- goto done;
- }
-
- *value = (int) level;
-
- if (value == &battchg_last)
- DBG("telephony-maemo6: battery.charge_level.last_full is %d",
- *value);
- else if (value == &battchg_design)
- DBG("telephony-maemo6: battery.charge_level.design is %d",
- *value);
- else
- DBG("telephony-maemo6: battery.charge_level.current is %d",
- *value);
-
- if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
- int new, max;
-
- if (battchg_last > 0)
- max = battchg_last;
- else
- max = battchg_design;
-
- new = battchg_cur * 5 / max;
-
- telephony_update_indicator(maemo_indicators, "battchg", new);
- }
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
- send_method_call("org.freedesktop.Hal", path,
- "org.freedesktop.Hal.Device",
- "GetPropertyInteger",
- hal_battery_level_reply, user_data,
- DBUS_TYPE_STRING, &key,
- DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
- DBusMessageIter iter, array;
- dbus_int32_t num_changes;
- const char *path;
-
- path = dbus_message_get_path(msg);
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_get_basic(&iter, &num_changes);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_recurse(&iter, &array);
-
- while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
- DBusMessageIter prop;
- const char *name;
- dbus_bool_t added, removed;
-
- dbus_message_iter_recurse(&array, &prop);
-
- if (!iter_get_basic_args(&prop,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &added,
- DBUS_TYPE_BOOLEAN, &removed,
- DBUS_TYPE_INVALID)) {
- error("Invalid hal PropertyModified parameters");
- break;
- }
-
- if (g_str_equal(name, "battery.charge_level.last_full"))
- hal_get_integer(path, name, &battchg_last);
- else if (g_str_equal(name, "battery.charge_level.current"))
- hal_get_integer(path, name, &battchg_cur);
- else if (g_str_equal(name, "battery.charge_level.design"))
- hal_get_integer(path, name, &battchg_design);
-
- dbus_message_iter_next(&array);
- }
-}
-
-static void csd_call_free(void *data)
-{
- struct csd_call *call = data;
-
- if (!call)
- return;
-
- g_free(call->object_path);
- g_free(call->number);
-
- g_slist_foreach(pending, remove_pending_by_data, call);
-
- g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
- do {
- DBusMessageIter call_iter;
- struct csd_call *call;
- const char *object_path, *number;
- dbus_uint32_t status;
- dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
- error("Unexpected signature in GetCallInfoAll reply");
- break;
- }
-
- dbus_message_iter_recurse(iter, &call_iter);
-
- if (!iter_get_basic_args(&call_iter,
- DBUS_TYPE_OBJECT_PATH, &object_path,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_BOOLEAN, &originating,
- DBUS_TYPE_BOOLEAN, &terminating,
- DBUS_TYPE_BOOLEAN, &emerg,
- DBUS_TYPE_BOOLEAN, &on_hold,
- DBUS_TYPE_BOOLEAN, &conf,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Parsing call D-Bus parameters failed");
- break;
- }
-
- call = find_call(object_path);
- if (!call) {
- call = g_new0(struct csd_call, 1);
- call->object_path = g_strdup(object_path);
- calls = g_slist_append(calls, call);
- DBG("telephony-maemo6: new csd call instance at %s",
- object_path);
- }
-
- if (status == CSD_CALL_STATUS_IDLE)
- continue;
-
- /* CSD gives incorrect call_hold property sometimes */
- if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
- (call->status == CSD_CALL_STATUS_HOLD &&
- !on_hold)) {
- error("Conflicting call status and on_hold property!");
- on_hold = call->status == CSD_CALL_STATUS_HOLD;
- }
-
- call->originating = originating;
- call->on_hold = on_hold;
- call->conference = conf;
- g_free(call->number);
- call->number = g_strdup(number);
-
- /* Update indicators */
- call_set_status(call, status);
-
- } while (dbus_message_iter_next(iter));
-}
-
-static void update_operator_name(const char *name)
-{
- if (name == NULL)
- return;
-
- g_free(net.operator_name);
- net.operator_name = g_strndup(name, 16);
- DBG("telephony-maemo6: operator name updated: %s", name);
-}
-
-static void get_property_reply(DBusPendingCall *call, void *user_data)
-{
- char *prop = user_data;
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
- error("Unexpected signature in Get return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- if (g_strcmp0(prop, "RegistrationStatus") == 0) {
- const char *status;
-
- dbus_message_iter_get_basic(&sub, &status);
- update_registration_status(status);
-
- get_property(CSD_CSNET_OPERATOR, "OperatorName");
- get_property(CSD_CSNET_SIGNAL, "SignalBars");
- } else if (g_strcmp0(prop, "OperatorName") == 0) {
- const char *name;
-
- dbus_message_iter_get_basic(&sub, &name);
- update_operator_name(name);
- } else if (g_strcmp0(prop, "SignalBars") == 0) {
- int32_t signal_bars;
-
- dbus_message_iter_get_basic(&sub, &signal_bars);
- update_signal_strength(signal_bars);
- }
-
-done:
- g_free(prop);
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static int get_property(const char *iface, const char *prop)
-{
- return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
- DBUS_INTERFACE_PROPERTIES, "Get",
- get_property_reply, g_strdup(prop),
- DBUS_TYPE_STRING, &iface,
- DBUS_TYPE_STRING, &prop,
- DBUS_TYPE_INVALID);
-}
-
-static void handle_operator_name_changed(DBusMessage *msg)
-{
- const char *name;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in OperatorNameChanged");
- return;
- }
-
- update_operator_name(name);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
-
- get_calls_active = FALSE;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in GetCallInfoAll return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- parse_call_list(&sub);
-
- get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError derr;
- DBusMessage *reply;
- const char *name, *number, *secondname, *additionalnumber, *email;
- int index;
- char **number_type = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- error("%s.ReadFirst replied with an error: %s, %s",
- CSD_SIMPB_INTERFACE, derr.name, derr.message);
- dbus_error_free(&derr);
- if (number_type == &vmbx)
- vmbx = g_strdup(getenv("VMBX_NUMBER"));
- goto done;
- }
-
- dbus_error_init(&derr);
- if (dbus_message_get_args(reply, NULL,
- DBUS_TYPE_INT32, &index,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_STRING, &secondname,
- DBUS_TYPE_STRING, &additionalnumber,
- DBUS_TYPE_STRING, &email,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse %s.ReadFirst arguments: %s, %s",
- CSD_SIMPB_INTERFACE, derr.name, derr.message);
- dbus_error_free(&derr);
- goto done;
- }
-
- if (number_type == &msisdn) {
- g_free(msisdn);
- msisdn = g_strdup(number);
- DBG("Got MSISDN %s (%s)", number, name);
- } else {
- g_free(vmbx);
- vmbx = g_strdup(number);
- DBG("Got voice mailbox number %s (%s)", number, name);
- }
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static void csd_init(void)
-{
- const char *pb_type;
- int ret;
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "GetCallInfoAll",
- call_info_reply, NULL, DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to sent GetCallInfoAll method call");
- return;
- }
-
- get_calls_active = TRUE;
-
- pb_type = CSD_SIMPB_TYPE_MSISDN;
-
- ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
- CSD_SIMPB_INTERFACE, "ReadFirst",
- phonebook_read_reply, &msisdn,
- DBUS_TYPE_STRING, &pb_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
- return;
- }
-
- /* Voicemail should be in MBDN index 0 */
- pb_type = CSD_SIMPB_TYPE_MBDN;
-
- ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
- CSD_SIMPB_INTERFACE, "ReadFirst",
- phonebook_read_reply, &vmbx,
- DBUS_TYPE_STRING, &pb_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
- return;
- }
-}
-
-static void handle_modem_state(DBusMessage *msg)
-{
- const char *state;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
- DBUS_TYPE_INVALID)) {
- error("Unexpected modem state parameters");
- return;
- }
-
- DBG("SSC modem state: %s", state);
-
- if (calls != NULL || get_calls_active)
- return;
-
- if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
- csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("get_modem_state: %s, %s", err.name, err.message);
- dbus_error_free(&err);
- } else
- handle_modem_state(reply);
-
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *path = dbus_message_get_path(msg);
-
- if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
- handle_incoming_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
- handle_outgoing_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
- "CreateRequested"))
- handle_create_requested(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
- handle_call_status(msg, path);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
- handle_conference(msg, TRUE);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
- handle_conference(msg, FALSE);
- else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
- "RegistrationChanged"))
- handle_registration_changed(msg);
- else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
- "OperatorNameChanged"))
- handle_operator_name_changed(msg);
- else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
- "SignalBarsChanged"))
- handle_signal_bars_changed(msg);
- else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
- "PropertyModified"))
- handle_hal_property_modified(msg);
- else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
- "modem_state_changed_ind"))
- handle_modem_state(msg);
-
- return TRUE;
-}
-
-static void add_watch(const char *sender, const char *path,
- const char *interface, const char *member)
-{
- guint watch;
-
- watch = g_dbus_add_signal_watch(connection, sender, path, interface,
- member, signal_filter, NULL, NULL);
-
- watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
- const char *path;
- int type;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in FindDeviceByCapability return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- type = dbus_message_iter_get_arg_type(&sub);
-
- if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
- error("No hal device with battery capability found");
- goto done;
- }
-
- dbus_message_iter_get_basic(&sub, &path);
-
- DBG("telephony-maemo6: found battery device at %s", path);
-
- add_watch(NULL, path, "org.freedesktop.Hal.Device",
- "PropertyModified");
-
- hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
- hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
- hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
- dbus_message_unref(reply);
- remove_pending(call);
-}
-
-int telephony_init(void)
-{
- const char *battery_cap = "battery";
- uint32_t features = AG_FEATURE_EC_ANDOR_NR |
- AG_FEATURE_INBAND_RINGTONE |
- AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_ENHANCED_CALL_CONTROL |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
- AG_FEATURE_THREE_WAY_CALLING;
- int i;
-
- DBG("");
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
- add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
- add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
- add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
- add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
- add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
- add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
-
- if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
- "get_modem_state", modem_state_reply,
- NULL, DBUS_TYPE_INVALID) < 0)
- error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
- /* Reset indicators */
- for (i = 0; maemo_indicators[i].desc != NULL; i++) {
- if (g_str_equal(maemo_indicators[i].desc, "battchg"))
- maemo_indicators[i].val = 5;
- else
- maemo_indicators[i].val = 0;
- }
-
- telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
- if (send_method_call("org.freedesktop.Hal",
- "/org/freedesktop/Hal/Manager",
- "org.freedesktop.Hal.Manager",
- "FindDeviceByCapability",
- hal_find_device_reply, NULL,
- DBUS_TYPE_STRING, &battery_cap,
- DBUS_TYPE_INVALID) < 0)
- error("Unable to send HAL method call");
-
- return 0;
-}
-
-static void remove_watch(gpointer data)
-{
- g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-void telephony_exit(void)
-{
- DBG("");
-
- g_free(net.operator_name);
- net.operator_name = NULL;
-
- net.status = NETWORK_REG_STATUS_UNKOWN;
- net.signal_bars = 0;
-
- g_slist_free(active_calls);
- active_calls = NULL;
-
- g_slist_free_full(calls, csd_call_free);
- calls = NULL;
-
- g_slist_free_full(pending, pending_req_finalize);
- pending = NULL;
-
- g_slist_free_full(watches, remove_watch);
- watches = NULL;
-
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [RFC v3 5/6] audio: Move HFP/HSP AG servers to telephony.c
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
` (3 preceding siblings ...)
2011-12-01 15:14 ` [RFC v3 4/6] audio: Remove maemo6 " Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
2011-12-01 15:14 ` [RFC v3 6/6] audio: Send transport path to telephony agent Frédéric Danis
5 siblings, 0 replies; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
audio/headset.c | 25 +++
audio/headset.h | 5 +-
audio/manager.c | 386 --------------------------------------------
audio/telephony.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++++++---
audio/telephony.h | 1 +
5 files changed, 467 insertions(+), 409 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index 028df16..5de7ed0 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -108,6 +108,7 @@ struct headset {
GIOChannel *rfcomm;
GIOChannel *tmp_rfcomm;
+ void *connecting_agent;
GIOChannel *sco;
guint sco_id;
@@ -413,6 +414,7 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hs->auto_dc = FALSE;
hs->slc = telephony_device_connecting(chan, dev);
+ hs->connecting_agent = NULL;
DBG("%s: Connected to %s", dev->path, hs_address);
@@ -563,6 +565,7 @@ failed_not_supported:
}
failed:
p->svclass = 0;
+ hs->connecting_agent = NULL;
pending_connect_finalize(dev);
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
}
@@ -581,6 +584,14 @@ static int get_records(struct audio_device *device, headset_stream_cb_t cb,
svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
HEADSET_SVCLASS_ID;
+ if (svclass == HANDSFREE_SVCLASS_ID)
+ hs->connecting_agent = telephony_agent_by_uuid(HFP_AG_UUID);
+ else
+ hs->connecting_agent = telephony_agent_by_uuid(HSP_AG_UUID);
+
+ if (hs->connecting_agent == NULL)
+ return -1;
+
sdp_uuid16_create(&uuid, svclass);
err = bt_search_service(&device->src, &device->dst, &uuid,
@@ -1251,6 +1262,20 @@ GIOChannel *headset_get_rfcomm(struct audio_device *dev)
return hs->tmp_rfcomm;
}
+void headset_set_connecting_agent(struct audio_device *dev, void *agent)
+{
+ struct headset *hs = dev->headset;
+
+ hs->connecting_agent = agent;
+}
+
+void *headset_get_connecting_agent(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ return hs->connecting_agent;
+}
+
int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
{
struct headset *hs = dev->headset;
diff --git a/audio/headset.h b/audio/headset.h
index 6bf352c..d74a69c 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -24,9 +24,6 @@
#define AUDIO_HEADSET_INTERFACE "org.bluez.Headset"
-#define DEFAULT_HS_AG_CHANNEL 12
-#define DEFAULT_HF_AG_CHANNEL 13
-
typedef enum {
HEADSET_STATE_DISCONNECTED,
HEADSET_STATE_CONNECTING,
@@ -108,3 +105,5 @@ gboolean headset_play(struct audio_device *dev, void *data);
void headset_shutdown(struct audio_device *dev);
void headset_slc_complete(struct audio_device *dev);
+void headset_set_connecting_agent(struct audio_device *dev, void *agent);
+void *headset_get_connecting_agent(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 4624552..f82c0ec 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -94,11 +94,7 @@ typedef enum {
struct audio_adapter {
struct btd_adapter *btd_adapter;
gboolean powered;
- uint32_t hsp_ag_record_id;
- uint32_t hfp_ag_record_id;
uint32_t hfp_hs_record_id;
- GIOChannel *hsp_ag_server;
- GIOChannel *hfp_ag_server;
GIOChannel *hfp_hs_server;
gint ref;
};
@@ -232,62 +228,6 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
}
}
-static sdp_record_t *hsp_ag_record(uint8_t ch)
-{
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
- uuid_t l2cap_uuid, rfcomm_uuid;
- sdp_profile_desc_t profile;
- sdp_record_t *record;
- sdp_list_t *aproto, *proto[2];
- sdp_data_t *channel;
-
- record = sdp_record_alloc();
- if (!record)
- return NULL;
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(0, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
- svclass_id = sdp_list_append(0, &svclass_uuid);
- sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
- svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
- sdp_set_service_classes(record, svclass_id);
-
- sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
- profile.version = 0x0102;
- pfseq = sdp_list_append(0, &profile);
- sdp_set_profile_descs(record, pfseq);
-
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(0, &l2cap_uuid);
- apseq = sdp_list_append(0, proto[0]);
-
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(0, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &ch);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
-
- aproto = sdp_list_append(0, apseq);
- sdp_set_access_protos(record, aproto);
-
- sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
-
- sdp_data_free(channel);
- sdp_list_free(proto[0], 0);
- sdp_list_free(proto[1], 0);
- sdp_list_free(apseq, 0);
- sdp_list_free(pfseq, 0);
- sdp_list_free(aproto, 0);
- sdp_list_free(root, 0);
- sdp_list_free(svclass_id, 0);
-
- return record;
-}
-
static sdp_record_t *hfp_hs_record(uint8_t ch)
{
sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -344,201 +284,6 @@ static sdp_record_t *hfp_hs_record(uint8_t ch)
return record;
}
-static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)
-{
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
- uuid_t l2cap_uuid, rfcomm_uuid;
- sdp_profile_desc_t profile;
- sdp_list_t *aproto, *proto[2];
- sdp_record_t *record;
- sdp_data_t *channel, *features;
- uint8_t netid = 0x01;
- uint16_t sdpfeat;
- sdp_data_t *network;
-
- record = sdp_record_alloc();
- if (!record)
- return NULL;
-
- network = sdp_data_alloc(SDP_UINT8, &netid);
- if (!network) {
- sdp_record_free(record);
- return NULL;
- }
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(0, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
- svclass_id = sdp_list_append(0, &svclass_uuid);
- sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
- svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
- sdp_set_service_classes(record, svclass_id);
-
- sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
- profile.version = 0x0105;
- pfseq = sdp_list_append(0, &profile);
- sdp_set_profile_descs(record, pfseq);
-
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(0, &l2cap_uuid);
- apseq = sdp_list_append(0, proto[0]);
-
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(0, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &ch);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
-
- sdpfeat = (uint16_t) feat & 0xF;
- features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
- sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
- aproto = sdp_list_append(0, apseq);
- sdp_set_access_protos(record, aproto);
-
- sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
-
- sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
- sdp_data_free(channel);
- sdp_list_free(proto[0], 0);
- sdp_list_free(proto[1], 0);
- sdp_list_free(apseq, 0);
- sdp_list_free(pfseq, 0);
- sdp_list_free(aproto, 0);
- sdp_list_free(root, 0);
- sdp_list_free(svclass_id, 0);
-
- return record;
-}
-
-static void headset_auth_cb(DBusError *derr, void *user_data)
-{
- struct audio_device *device = user_data;
- GError *err = NULL;
- GIOChannel *io;
-
- if (device->hs_preauth_id) {
- g_source_remove(device->hs_preauth_id);
- device->hs_preauth_id = 0;
- }
-
- if (derr && dbus_error_is_set(derr)) {
- error("Access denied: %s", derr->message);
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
- return;
- }
-
- io = headset_get_rfcomm(device);
-
- if (!bt_io_accept(io, headset_connect_cb, device, NULL, &err)) {
- error("bt_io_accept: %s", err->message);
- g_error_free(err);
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
- return;
- }
-}
-
-static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
- gpointer user_data)
-{
- struct audio_device *device = user_data;
-
- DBG("Headset disconnected during authorization");
-
- audio_device_cancel_authorization(device, headset_auth_cb, device);
-
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
- device->hs_preauth_id = 0;
-
- return FALSE;
-}
-
-static void ag_confirm(GIOChannel *chan, gpointer data)
-{
- const char *server_uuid, *remote_uuid;
- struct audio_device *device;
- gboolean hfp_active;
- bdaddr_t src, dst;
- int perr;
- GError *err = NULL;
- uint8_t ch;
-
- bt_io_get(chan, BT_IO_RFCOMM, &err,
- BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_CHANNEL, &ch,
- BT_IO_OPT_INVALID);
- if (err) {
- error("%s", err->message);
- g_error_free(err);
- goto drop;
- }
-
- if (ch == DEFAULT_HS_AG_CHANNEL) {
- hfp_active = FALSE;
- server_uuid = HSP_AG_UUID;
- remote_uuid = HSP_HS_UUID;
- } else {
- hfp_active = TRUE;
- server_uuid = HFP_AG_UUID;
- remote_uuid = HFP_HS_UUID;
- }
-
- device = manager_get_device(&src, &dst, TRUE);
- if (!device)
- goto drop;
-
- if (!manager_allow_headset_connection(device)) {
- DBG("Refusing headset: too many existing connections");
- goto drop;
- }
-
- if (!device->headset) {
- btd_device_add_uuid(device->btd_dev, remote_uuid);
- if (!device->headset)
- goto drop;
- }
-
- if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
- DBG("Refusing new connection since one already exists");
- goto drop;
- }
-
- headset_set_hfp_active(device, hfp_active);
- headset_set_rfcomm_initiator(device, TRUE);
-
- if (headset_connect_rfcomm(device, chan) < 0) {
- error("headset_connect_rfcomm failed");
- goto drop;
- }
-
- headset_set_state(device, HEADSET_STATE_CONNECTING);
-
- perr = audio_device_request_authorization(device, server_uuid,
- headset_auth_cb, device);
- if (perr < 0) {
- DBG("Authorization denied: %s", strerror(-perr));
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
- return;
- }
-
- device->hs_preauth_id = g_io_add_watch(chan,
- G_IO_NVAL | G_IO_HUP | G_IO_ERR,
- hs_preauth_cb, device);
-
- device->auto_connect = auto_connect;
-
- return;
-
-drop:
- g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
static void gateway_auth_cb(DBusError *derr, void *user_data)
{
struct audio_device *device = user_data;
@@ -614,108 +359,6 @@ drop:
g_io_channel_shutdown(chan, TRUE, NULL);
}
-static int headset_server_init(struct audio_adapter *adapter)
-{
- uint8_t chan = DEFAULT_HS_AG_CHANNEL;
- sdp_record_t *record;
- gboolean master = TRUE;
- GError *err = NULL;
- uint32_t features;
- GIOChannel *io;
- bdaddr_t src;
-
- if (config) {
- gboolean tmp;
-
- tmp = g_key_file_get_boolean(config, "General", "Master",
- &err);
- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else
- master = tmp;
- }
-
- adapter_get_address(adapter->btd_adapter, &src);
-
- io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_MASTER, master,
- BT_IO_OPT_INVALID);
- if (!io)
- goto failed;
-
- adapter->hsp_ag_server = io;
-
- record = hsp_ag_record(chan);
- if (!record) {
- error("Unable to allocate new service record");
- goto failed;
- }
-
- if (add_record_to_server(&src, record) < 0) {
- error("Unable to register HS AG service record");
- sdp_record_free(record);
- goto failed;
- }
- adapter->hsp_ag_record_id = record->handle;
-
- features = headset_config_init(config);
-
- if (!enabled.hfp)
- return 0;
-
- chan = DEFAULT_HF_AG_CHANNEL;
-
- io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_MASTER, master,
- BT_IO_OPT_INVALID);
- if (!io)
- goto failed;
-
- adapter->hfp_ag_server = io;
-
- record = hfp_ag_record(chan, features);
- if (!record) {
- error("Unable to allocate new service record");
- goto failed;
- }
-
- if (add_record_to_server(&src, record) < 0) {
- error("Unable to register HF AG service record");
- sdp_record_free(record);
- goto failed;
- }
- adapter->hfp_ag_record_id = record->handle;
-
- return 0;
-
-failed:
- if (err) {
- error("%s", err->message);
- g_error_free(err);
- }
-
- if (adapter->hsp_ag_server) {
- g_io_channel_shutdown(adapter->hsp_ag_server, TRUE, NULL);
- g_io_channel_unref(adapter->hsp_ag_server);
- adapter->hsp_ag_server = NULL;
- }
-
- if (adapter->hfp_ag_server) {
- g_io_channel_shutdown(adapter->hfp_ag_server, TRUE, NULL);
- g_io_channel_unref(adapter->hfp_ag_server);
- adapter->hfp_ag_server = NULL;
- }
-
- return -1;
-}
-
static int gateway_server_init(struct audio_adapter *adapter)
{
uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
@@ -904,7 +547,6 @@ static int headset_server_probe(struct btd_adapter *adapter)
{
struct audio_adapter *adp;
const gchar *path = adapter_get_path(adapter);
- int err;
DBG("path %s", path);
@@ -915,12 +557,6 @@ static int headset_server_probe(struct btd_adapter *adapter)
btd_adapter_register_powered_callback(adapter, state_changed);
state_changed(adapter, TRUE);
- err = headset_server_init(adp);
- if (err < 0) {
- audio_adapter_unref(adp);
- return err;
- }
-
return 0;
}
@@ -935,28 +571,6 @@ static void headset_server_remove(struct btd_adapter *adapter)
if (!adp)
return;
- if (adp->hsp_ag_record_id) {
- remove_record_from_server(adp->hsp_ag_record_id);
- adp->hsp_ag_record_id = 0;
- }
-
- if (adp->hsp_ag_server) {
- g_io_channel_shutdown(adp->hsp_ag_server, TRUE, NULL);
- g_io_channel_unref(adp->hsp_ag_server);
- adp->hsp_ag_server = NULL;
- }
-
- if (adp->hfp_ag_record_id) {
- remove_record_from_server(adp->hfp_ag_record_id);
- adp->hfp_ag_record_id = 0;
- }
-
- if (adp->hfp_ag_server) {
- g_io_channel_shutdown(adp->hfp_ag_server, TRUE, NULL);
- g_io_channel_unref(adp->hfp_ag_server);
- adp->hfp_ag_server = NULL;
- }
-
btd_adapter_unregister_powered_callback(adapter, state_changed);
audio_adapter_unref(adp);
diff --git a/audio/telephony.c b/audio/telephony.c
index 4aa3892..90e8699 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -39,6 +39,7 @@
#include "btio.h"
#include "log.h"
#include "device.h"
+#include "manager.h"
#include "error.h"
#include "glib-helper.h"
#include "sdp-client.h"
@@ -47,11 +48,14 @@
#include "dbus-common.h"
#include "../src/adapter.h"
#include "../src/device.h"
+#include "sdpd.h"
#define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
#define DEFAULT_HS_HS_CHANNEL 6
+#define DEFAULT_HS_AG_CHANNEL 12
#define DEFAULT_HF_HS_CHANNEL 7
+#define DEFAULT_HF_AG_CHANNEL 13
struct telsrv {
GSList *servers; /* server list */
@@ -71,6 +75,7 @@ struct default_agent {
const char *r_uuid;
uint16_t r_class;
uint16_t r_profile;
+ sdp_record_t *(*record_init)(struct tel_agent *agent);
};
struct tel_agent {
@@ -79,6 +84,8 @@ struct tel_agent {
uint16_t version;
uint16_t features;
struct default_agent *properties;
+ GIOChannel *io;
+ uint32_t record_id;
};
static DBusConnection *connection = NULL;
@@ -93,6 +100,14 @@ static void free_agent(struct tel_agent *agent)
if (agent->path)
g_free(agent->path);
+ if (agent->io) {
+ g_io_channel_shutdown(agent->io, TRUE, NULL);
+ g_io_channel_unref(agent->io);
+ }
+
+ if (agent->record_id)
+ remove_record_from_server(agent->record_id);
+
g_free(agent);
}
@@ -119,6 +134,11 @@ static struct tel_agent *find_agent(const char *sender, const char *path,
return NULL;
}
+void *telephony_agent_by_uuid(const char *uuid)
+{
+ return find_agent(NULL, NULL, uuid);
+}
+
static int parse_properties(DBusMessageIter *props, const char **uuid,
uint16_t *version, uint16_t *features)
{
@@ -304,30 +324,16 @@ void *telephony_device_connecting(GIOChannel *io, void *telephony_device)
{
struct audio_device *device = telephony_device;
struct tel_device *dev;
- const char *agent_uuid;
- struct tel_agent *agent;
uuid_t uuid;
int err;
- /*TODO: check for HS roles */
- if (headset_get_hfp_active(device))
- agent_uuid = HFP_AG_UUID;
- else
- agent_uuid = HSP_AG_UUID;
-
- agent = find_agent(NULL, NULL, agent_uuid);
- if (agent == NULL) {
- error("No agent registered for %s", agent_uuid);
- return NULL;
- }
-
dev = g_new0(struct tel_device, 1);
- dev->agent = agent;
+ dev->agent = headset_get_connecting_agent(device);
dev->au_dev = telephony_device;
dev->rfcomm = io;
dev->features = 0xFFFF;
- sdp_uuid16_create(&uuid, agent->properties->r_class);
+ sdp_uuid16_create(&uuid, dev->agent->properties->r_class);
err = bt_search_service(&device->src, &device->dst, &uuid,
get_record_cb, dev, NULL);
@@ -366,38 +372,418 @@ uint32_t telephony_get_ag_features(void)
return 0;
}
+static sdp_record_t *hsp_hs_record(struct tel_agent * agent)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel, *volume;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = agent->version;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &agent->properties->channel);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ volume = sdp_data_alloc(SDP_BOOL, &agent->features);
+ sdp_attr_add(record, SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL, volume);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Headset", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *hsp_ag_record(struct tel_agent * agent)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = agent->version;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &agent->properties->channel);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *hfp_hs_record(struct tel_agent * agent)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *channel, *features;
+ uint16_t sdpfeat;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = agent->version;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &agent->properties->channel);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdpfeat = agent->features & 0xF;
+ features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Hands-Free", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *hfp_ag_record(struct tel_agent * agent)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *channel, *features;
+ uint8_t netid = 0x01;
+ uint16_t sdpfeat;
+ sdp_data_t *network;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ network = sdp_data_alloc(SDP_UINT8, &netid);
+ if (!network) {
+ sdp_record_free(record);
+ return NULL;
+ }
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = agent->version;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &agent->properties->channel);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdpfeat = agent->features & 0xF;
+ features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
+
+ sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static void headset_auth_cb(DBusError *derr, void *user_data)
+{
+ struct audio_device *device = user_data;
+ GError *err = NULL;
+ GIOChannel *io;
+
+ if (device->hs_preauth_id) {
+ g_source_remove(device->hs_preauth_id);
+ device->hs_preauth_id = 0;
+ }
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+ return;
+ }
+
+ io = headset_get_rfcomm(device);
+
+ if (!bt_io_accept(io, headset_connect_cb, device, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+ return;
+ }
+}
+
+static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct audio_device *device = user_data;
+
+ DBG("Headset disconnected during authorization");
+
+ audio_device_cancel_authorization(device, headset_auth_cb, device);
+
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+
+ device->hs_preauth_id = 0;
+
+ return FALSE;
+}
+
+static void ag_confirm(GIOChannel *chan, gpointer data)
+{
+ struct tel_agent *agent = data;
+ struct audio_device *device;
+ gboolean hfp_active;
+ bdaddr_t src, dst;
+ int perr;
+ GError *err = NULL;
+ uint8_t ch;
+
+ bt_io_get(chan, BT_IO_RFCOMM, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_CHANNEL, &ch,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ /* TODO: to remove ? */
+ if (ch == DEFAULT_HS_AG_CHANNEL)
+ hfp_active = FALSE;
+ else
+ hfp_active = TRUE;
+
+ device = manager_get_device(&src, &dst, TRUE);
+ if (!device)
+ goto drop;
+
+ if (!manager_allow_headset_connection(device)) {
+ DBG("Refusing headset: too many existing connections");
+ goto drop;
+ }
+
+ if (!device->headset) {
+ btd_device_add_uuid(device->btd_dev, agent->properties->r_uuid);
+ if (!device->headset)
+ goto drop;
+ }
+
+ if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
+ DBG("Refusing new connection since one already exists");
+ goto drop;
+ }
+
+ headset_set_hfp_active(device, hfp_active);
+ headset_set_rfcomm_initiator(device, TRUE);
+ headset_set_connecting_agent(device, agent);
+
+ if (headset_connect_rfcomm(device, chan) < 0) {
+ error("headset_connect_rfcomm failed");
+ goto drop;
+ }
+
+ headset_set_state(device, HEADSET_STATE_CONNECTING);
+
+ perr = audio_device_request_authorization(device,
+ agent->properties->uuid,
+ headset_auth_cb, device);
+ if (perr < 0) {
+ DBG("Authorization denied: %s", strerror(-perr));
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+ return;
+ }
+
+ device->hs_preauth_id = g_io_add_watch(chan,
+ G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ hs_preauth_cb, device);
+
+#if 0
+ device->auto_connect = auto_connect;
+#endif
+
+ return;
+
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+}
+
static struct default_agent default_properties[] = {
{HSP_HS_UUID,
DEFAULT_HS_HS_CHANNEL,
HSP_AG_UUID,
HEADSET_AGW_SVCLASS_ID,
- HEADSET_PROFILE_ID},
+ HEADSET_PROFILE_ID,
+ hsp_hs_record},
{HSP_AG_UUID,
DEFAULT_HS_AG_CHANNEL,
HSP_HS_UUID,
HEADSET_SVCLASS_ID,
- HEADSET_PROFILE_ID},
+ HEADSET_PROFILE_ID,
+ hsp_ag_record},
{HFP_HS_UUID,
DEFAULT_HF_HS_CHANNEL,
HFP_AG_UUID,
HANDSFREE_AGW_SVCLASS_ID,
- HANDSFREE_PROFILE_ID},
+ HANDSFREE_PROFILE_ID,
+ hfp_hs_record},
{HFP_AG_UUID,
DEFAULT_HF_AG_CHANNEL,
HFP_HS_UUID,
HANDSFREE_SVCLASS_ID,
- HANDSFREE_PROFILE_ID}
+ HANDSFREE_PROFILE_ID,
+ hfp_ag_record}
};
static DBusMessage *register_agent(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
DBusMessageIter args, props;
const char *sender, *path, *uuid;
uint16_t version = 0;
uint16_t features = 0xFFFF;
struct tel_agent *agent;
int i;
+ sdp_record_t *record;
+ bdaddr_t src;
+ gboolean master = TRUE;
+ GError *err = NULL;
sender = dbus_message_get_sender(msg);
@@ -435,9 +821,42 @@ static DBusMessage *register_agent(DBusConnection *conn,
if (i == 4)
return btd_error_invalid_args(msg);
+ record = agent->properties->record_init(agent);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return btd_error_failed(msg, "Unable to allocate new service " \
+ "record");
+ }
+
DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
sender, path, uuid, version, features);
+ /* start RFComm agent server */
+ adapter_get_address(adapter, &src);
+
+ agent->io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, agent, NULL,
+ &err, BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_CHANNEL, agent->properties->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_MASTER, master,
+ BT_IO_OPT_INVALID);
+ if (agent->io == NULL) {
+ error("Unable to register server");
+ sdp_record_free(record);
+ free_agent(agent);
+ return btd_error_failed(msg, "Failed to register server");
+ }
+
+ /* advertise agent sdp record */
+ if (add_record_to_server(&src, record) < 0) {
+ error("Unable to register service record");
+ sdp_record_free(record);
+ free_agent(agent);
+ return btd_error_failed(msg, "Failed to register sdp record");
+ }
+
+ agent->record_id = record->handle;
+
telsrv.servers = g_slist_append(telsrv.servers, agent);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
diff --git a/audio/telephony.h b/audio/telephony.h
index aa23bef..d5d9f65 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -55,6 +55,7 @@ void telephony_device_disconnected(void *telephony_device);
gboolean telephony_get_ready_state(void);
uint32_t telephony_get_ag_features(void);
+void *telephony_agent_by_uuid(const char *uuid);
int telephony_init(void *adapter);
void telephony_exit(void *adapter);
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [RFC v3 6/6] audio: Send transport path to telephony agent
2011-12-01 15:13 [RFC v3 0/6] Add org.bluez.Telephony interface Frédéric Danis
` (4 preceding siblings ...)
2011-12-01 15:14 ` [RFC v3 5/6] audio: Move HFP/HSP AG servers to telephony.c Frédéric Danis
@ 2011-12-01 15:14 ` Frédéric Danis
5 siblings, 0 replies; 9+ messages in thread
From: Frédéric Danis @ 2011-12-01 15:14 UTC (permalink / raw)
To: linux-bluetooth
---
audio/headset.c | 19 +++++++++++++++++++
audio/headset.h | 2 ++
audio/media.c | 9 ++++++++-
audio/telephony.c | 12 ++++++++++++
audio/telephony.h | 1 +
5 files changed, 42 insertions(+), 1 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index 5de7ed0..9839ca2 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -109,6 +109,7 @@ struct headset {
GIOChannel *rfcomm;
GIOChannel *tmp_rfcomm;
void *connecting_agent;
+ const char *connecting_path;
GIOChannel *sco;
guint sco_id;
@@ -415,6 +416,8 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hs->slc = telephony_device_connecting(chan, dev);
hs->connecting_agent = NULL;
+ telephony_set_media_transport_path(hs->slc, hs->connecting_path);
+ hs->connecting_path = NULL;
DBG("%s: Connected to %s", dev->path, hs_address);
@@ -566,6 +569,7 @@ failed_not_supported:
failed:
p->svclass = 0;
hs->connecting_agent = NULL;
+ hs->connecting_path = NULL;
pending_connect_finalize(dev);
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
}
@@ -1276,6 +1280,21 @@ void *headset_get_connecting_agent(struct audio_device *dev)
return hs->connecting_agent;
}
+void headset_set_media_transport_path(struct audio_device *dev,
+ const char *path)
+{
+ struct headset *hs = dev->headset;
+
+ DBG("MediaTransport path: %s", path);
+
+ if (hs->slc == NULL) {
+ hs->connecting_path = path;
+ return;
+ }
+
+ telephony_set_media_transport_path(hs->slc, path);
+}
+
int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
{
struct headset *hs = dev->headset;
diff --git a/audio/headset.h b/audio/headset.h
index d74a69c..7eac876 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -107,3 +107,5 @@ void headset_shutdown(struct audio_device *dev);
void headset_slc_complete(struct audio_device *dev);
void headset_set_connecting_agent(struct audio_device *dev, void *agent);
void *headset_get_connecting_agent(struct audio_device *dev);
+void headset_set_media_transport_path(struct audio_device *dev,
+ const char *path);
diff --git a/audio/media.c b/audio/media.c
index a2ef437..43ffcc2 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -440,6 +440,7 @@ static void headset_state_changed(struct audio_device *dev,
void *user_data)
{
struct media_endpoint *endpoint = user_data;
+ const char *path;
DBG("");
@@ -455,6 +456,8 @@ static void headset_state_changed(struct audio_device *dev,
case HEADSET_STATE_CONNECTING:
set_configuration(endpoint, dev, NULL, 0, headset_setconf_cb,
dev, NULL);
+ path = media_transport_get_path(endpoint->transport);
+ headset_set_media_transport_path(dev, path);
break;
case HEADSET_STATE_CONNECTED:
break;
@@ -669,14 +672,18 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
strcasecmp(uuid, HSP_AG_UUID) == 0) {
struct audio_device *dev;
+ const char *t_path;
endpoint->hs_watch = headset_add_state_cb(headset_state_changed,
endpoint);
dev = manager_find_device(NULL, &adapter->src, BDADDR_ANY,
AUDIO_HEADSET_INTERFACE, TRUE);
- if (dev)
+ if (dev) {
set_configuration(endpoint, dev, NULL, 0,
headset_setconf_cb, dev, NULL);
+ t_path = media_transport_get_path(endpoint->transport);
+ headset_set_media_transport_path(dev, t_path);
+ }
} else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
strcasecmp(uuid, HSP_HS_UUID) == 0) {
struct audio_device *dev;
diff --git a/audio/telephony.c b/audio/telephony.c
index 90e8699..416fd97 100644
--- a/audio/telephony.c
+++ b/audio/telephony.c
@@ -65,6 +65,7 @@ struct tel_device {
struct tel_agent *agent;
struct audio_device *au_dev;
GIOChannel *rfcomm;
+ const char *transport_path;
uint16_t version;
uint16_t features;
};
@@ -220,6 +221,10 @@ static gboolean agent_sendfd(struct tel_device *dev, int fd,
dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
&dev->features);
+ if (dev->transport_path != NULL)
+ dict_append_entry(&dict, "MediaTransportPath", DBUS_TYPE_STRING,
+ &dev->transport_path);
+
dbus_message_iter_close_container(&iter, &dict);
if (dbus_connection_send_with_reply(connection, msg, &call, -1) == FALSE)
@@ -362,6 +367,13 @@ void telephony_device_disconnected(void *telephony_device)
DBG("telephony-dbus: device %p disconnected", telephony_device);
}
+void telephony_set_media_transport_path(void *slc, const char *path)
+{
+ struct tel_device *dev = slc;
+
+ dev->transport_path = path;
+}
+
gboolean telephony_get_ready_state(void)
{
return find_agent(NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
diff --git a/audio/telephony.h b/audio/telephony.h
index d5d9f65..24afd28 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -52,6 +52,7 @@ void *telephony_device_connecting(GIOChannel *io, void *telephony_device);
void telephony_device_connected(void *telephony_device);
void telephony_device_disconnect(void *slc);
void telephony_device_disconnected(void *telephony_device);
+void telephony_set_media_transport_path(void *slc, const char *path);
gboolean telephony_get_ready_state(void);
uint32_t telephony_get_ag_features(void);
--
1.7.1
^ permalink raw reply related [flat|nested] 9+ messages in thread