voicecall: Fix HangupAll for HFP
authorDenis Kenzior <denkenz@gmail.com>
Wed, 12 Oct 2011 21:00:00 +0000 (16:00 -0500)
committerDenis Kenzior <denkenz@gmail.com>
Wed, 12 Oct 2011 21:00:00 +0000 (16:00 -0500)
HFP does not implement HangupAll natively and most AGs do not support
releasing held calls by id.  Work around this by using hangup active and
then dropping all held calls if no waiting calls exist.  Otherwise
fall back to releasing calls by id.

src/voicecall.c

index 2fabbae..17d42b3 100644 (file)
@@ -120,6 +120,7 @@ static const char *default_en_list_no_sim[] = { "119", "118", "999", "110",
                                                "08", "000", NULL };
 
 static void generic_callback(const struct ofono_error *error, void *data);
+static void hangup_all_active(const struct ofono_error *error, void *data);
 static void multirelease_callback(const struct ofono_error *err, void *data);
 static gboolean tone_request_run(gpointer user_data);
 
@@ -1700,12 +1701,15 @@ static DBusMessage *manager_hangup_all(DBusConnection *conn,
 
        vc->pending = dbus_message_ref(msg);
 
-       if (vc->driver->hangup_all == NULL) {
-               voicecalls_release_queue(vc, vc->call_list,
-                                               voicecalls_release_done);
-               voicecalls_release_next(vc);
-       } else
+       if (vc->driver->hangup_all) {
                vc->driver->hangup_all(vc, generic_callback, vc);
+               return NULL;
+       }
+
+       if (voicecalls_num_held(vc) > 0)
+               vc->driver->hangup_active(vc, hangup_all_active, vc);
+       else
+               vc->driver->hangup_active(vc, generic_callback, vc);
 
        return NULL;
 }
@@ -2291,6 +2295,35 @@ static void generic_callback(const struct ofono_error *error, void *data)
        __ofono_dbus_pending_reply(&vc->pending, reply);
 }
 
+static void hangup_all_active(const struct ofono_error *error, void *data)
+{
+       struct ofono_voicecall *vc = data;
+
+       if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+               __ofono_dbus_pending_reply(&vc->pending,
+                                       __ofono_error_failed(vc->pending));
+               return;
+       }
+
+       /*
+        * If we have waiting call, we cannot use CHLD=0 due to side effects
+        * to that call.  Instead we try to hangup all calls one by one,
+        * which might fail if the modem / AG does not support release_specific
+        * for held calls.  In that case the waiting call and held calls will
+        * remain.
+        */
+       if (vc->driver->release_all_held == NULL ||
+                       voicecalls_have_waiting(vc)) {
+               GSList *held = voicecalls_held_list(vc);
+
+               voicecalls_release_queue(vc, held, voicecalls_release_done);
+               voicecalls_release_next(vc);
+
+               g_slist_free(held);
+       } else
+               vc->driver->release_all_held(vc, generic_callback, vc);
+}
+
 static void multirelease_callback(const struct ofono_error *error, void *data)
 {
        struct ofono_voicecall *vc = data;