OSDN Git Service

auto import from //branches/cupcake/...@131421
authorThe Android Open Source Project <initial-contribution@android.com>
Fri, 13 Feb 2009 20:57:48 +0000 (12:57 -0800)
committerThe Android Open Source Project <initial-contribution@android.com>
Fri, 13 Feb 2009 20:57:48 +0000 (12:57 -0800)
utils/audio/a2dp.c
utils/audio/avdtp.c
utils/audio/control.c
utils/audio/device.c
utils/audio/device.h
utils/audio/liba2dp.c
utils/audio/sink.c
utils/audio/sink.h

index 67e1782..7f4971b 100644 (file)
@@ -178,7 +178,7 @@ static gboolean finalize_resume(struct a2dp_setup *s)
        for (l = s->cb; l != NULL; l = l->next) {
                struct a2dp_setup_cb *cb = l->data;
 
-               if (cb->resume_cb) {
+               if (cb && cb->resume_cb) {
                        cb->resume_cb(s->session, s->err, cb->user_data);
                        cb->resume_cb = NULL;
                        setup_unref(s);
index 130cd16..8bdfdb4 100644 (file)
@@ -359,6 +359,9 @@ struct avdtp {
 
        guint dc_timer;
 
+       /* Attempt stream setup instead of disconnecting */
+       gboolean stream_setup;
+
        DBusPendingCall *pending_auth;
 };
 
@@ -466,13 +469,21 @@ static gboolean stream_open_timeout(gpointer user_data)
 static gboolean disconnect_timeout(gpointer user_data)
 {
        struct avdtp *session = user_data;
+       struct audio_device *dev;
+       gboolean stream_setup;
+       int i = 0;
 
        assert(session->ref == 1);
 
        session->dc_timer = 0;
+       stream_setup = session->stream_setup;
+       session->stream_setup = FALSE;
+       dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE, FALSE);
 
-       connection_lost(session, -ETIMEDOUT);
-
+       if (dev && dev->sink && stream_setup)
+               sink_setup_stream(dev->sink, session);
+       else
+               connection_lost(session, -ETIMEDOUT);
        return FALSE;
 }
 
@@ -480,6 +491,7 @@ static void remove_disconnect_timer(struct avdtp *session)
 {
        g_source_remove(session->dc_timer);
        session->dc_timer = 0;
+       session->stream_setup = FALSE;
 }
 
 static void set_disconnect_timer(struct avdtp *session)
@@ -740,8 +752,10 @@ static void connection_lost(struct avdtp *session, int err)
 
        dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,
                                        FALSE);
-       if (dev)
+       if (dev && dev->control) {
+               device_remove_control_timer(dev);
                avrcp_disconnect(dev);
+       }
 
        if (session->state == AVDTP_SESSION_STATE_CONNECTED) {
                char address[18];
@@ -2697,14 +2711,15 @@ static void auth_cb(DBusError *derr, void *user_data)
 
        session->buf = g_malloc0(session->mtu);
 
+       session->stream_setup = TRUE;
        set_disconnect_timer(session);
 
        session->state = AVDTP_SESSION_STATE_CONNECTED;
 
        dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,
                                        FALSE);
-       if (dev)
-               avrcp_connect(dev);
+       if (dev && dev->control)
+               device_set_control_timer(dev);
 
        g_source_remove(session->io);
 
index 4354493..a0c1e40 100644 (file)
@@ -652,6 +652,7 @@ static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
        struct l2cap_options l2o;
        struct avctp *session;
        GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+       struct audio_device *dev;
        char address[18];
 
        if (err < 0) {
@@ -671,6 +672,18 @@ static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
                goto drop;
        }
 
+       dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE, FALSE);
+
+       if (!dev) {
+               error("Unable to get audio device object for %s", address);
+               goto drop;
+       }
+
+       if (!dev->control)
+               dev->control = control_init(dev);
+
+       device_remove_control_timer(dev);
+
        session->state = AVCTP_STATE_CONNECTING;
        session->sock = g_io_channel_unix_get_fd(chan);
 
@@ -788,6 +801,8 @@ gboolean avrcp_connect(struct audio_device *dev)
                return FALSE;
        }
 
+       device_remove_control_timer(dev);
+
        session->dev = dev;
        session->state = AVCTP_STATE_CONNECTING;
 
index 2f5f834..e38e734 100644 (file)
@@ -54,6 +54,8 @@
 #include "headset.h"
 #include "sink.h"
 
+#define CONTROL_CONNECT_TIMEOUT 2000
+
 static DBusMessage *device_get_address(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
@@ -176,6 +178,9 @@ static void device_free(struct audio_device *dev)
        if (dev->conn)
                dbus_connection_unref(dev->conn);
 
+       if (dev->control_timer)
+               g_source_remove(dev->control_timer);
+
        g_free(dev->adapter_path);
        g_free(dev->path);
        g_free(dev->name);
@@ -192,6 +197,40 @@ static void device_unregister(void *data)
        device_free(device);
 }
 
+static gboolean control_connect_timeout(gpointer user_data)
+{
+       struct audio_device *dev = user_data;
+
+       dev->control_timer = 0;
+
+       if (dev->control)
+               avrcp_connect(dev);
+
+       return FALSE;
+}
+
+gboolean device_set_control_timer(struct audio_device *dev)
+{
+       if (!dev->control)
+               return FALSE;
+
+       if (dev->control_timer)
+               return FALSE;
+
+       dev->control_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
+                                               control_connect_timeout,
+                                               dev);
+
+       return TRUE;
+}
+
+void device_remove_control_timer(struct audio_device *dev)
+{
+       if (dev->control_timer)
+               g_source_remove(dev->control_timer);
+       dev->control_timer = 0;
+}
+
 struct audio_device *device_register(DBusConnection *conn,
                                        const char *path, const bdaddr_t *bda)
 {
index 5dc99b9..14c2948 100644 (file)
@@ -67,8 +67,13 @@ struct audio_device {
        struct source *source;
        struct control *control;
        struct target *target;
+
+       guint control_timer;
 };
 
+gboolean device_set_control_timer(struct audio_device *dev);
+void device_remove_control_timer(struct audio_device *dev);
+
 struct audio_device *device_register(DBusConnection *conn,
                                        const char *path, const bdaddr_t *bda);
 
index 2b00512..9d2f54a 100644 (file)
@@ -48,6 +48,7 @@
 
 #define ENABLE_DEBUG
 /* #define ENABLE_VERBOSE */
+/* #define ENABLE_TIMING */
 
 #define BUFFER_SIZE 2048
 
@@ -79,6 +80,9 @@
 /* Number of packets to buffer in the stream socket */
 #define PACKET_BUFFER_COUNT            10
 
+/* timeout in milliseconds to prevent poll() from hanging indefinitely */
+#define POLL_TIMEOUT                   1000
+
 struct bluetooth_data {
        int link_mtu;                                   /* MTU for selected transport channel */
        struct pollfd stream;                   /* Audio stream filedescriptor */
@@ -102,9 +106,22 @@ struct bluetooth_data {
        int     channels;
 
        /* used for pacing our writes to the output socket */
-       struct timeval  next_write;
+       uint64_t        next_write;
 };
 
+static uint64_t get_microseconds()
+{
+       struct timeval now;
+       gettimeofday(&now, NULL);
+       return (now.tv_sec * 1000000UL + now.tv_usec);
+}
+
+#ifdef ENABLE_TIMING
+static void print_time(const char* message, uint64_t then, uint64_t now)
+{
+       DBG("%s: %lld us", message, now - then);
+}
+#endif
 
 static int audioservice_send(struct bluetooth_data *data, const bt_audio_msg_header_t *msg);
 static int audioservice_expect(struct bluetooth_data *data, bt_audio_msg_header_t *outmsg,
@@ -114,7 +131,7 @@ static int bluetooth_a2dp_hw_params(struct bluetooth_data *data);
 
 static void bluetooth_close(struct bluetooth_data *data)
 {
-       LOGD("bluetooth_close");
+       DBG("bluetooth_close");
        if (data->server.fd >= 0) {
                bt_audio_service_close(data->server.fd);
                data->server.fd = -1;
@@ -181,8 +198,7 @@ static int bluetooth_start(struct bluetooth_data *data)
        data->nsamples = 0;
        data->seq_num = 0;
        data->frame_count = 0;
-       data->next_write.tv_sec = 0;
-       data->next_write.tv_usec = 0;
+       data->next_write = 0;
 
        return 0;
 }
@@ -401,6 +417,7 @@ static void bluetooth_a2dp_setup(struct bluetooth_data *data)
        data->sbc.bitpool = active_capabilities.max_bitpool;
        data->codesize = sbc_get_codesize(&data->sbc);
        data->frame_duration = sbc_get_frame_duration(&data->sbc);
+       DBG("frame_duration: %d us", data->frame_duration);
 }
 
 static int bluetooth_a2dp_hw_params(struct bluetooth_data *data)
@@ -515,6 +532,7 @@ static int bluetooth_a2dp_hw_params(struct bluetooth_data *data)
        }
 
        data->link_mtu = setconf_rsp->link_mtu;
+       DBG("MTU: %d", data->link_mtu);
 
        /* Setup SBC encoder now we agree on parameters */
        bluetooth_a2dp_setup(data);
@@ -531,8 +549,12 @@ static int avdtp_write(struct bluetooth_data *data)
        int ret = 0;
        struct rtp_header *header;
        struct rtp_payload *payload;
-       struct timeval now;
+       uint64_t now;
        long duration = data->frame_duration * data->frame_count;
+#ifdef ENABLE_TIMING
+       uint64_t begin, end, begin2, end2;
+       begin = get_microseconds();
+#endif
 
        header = (struct rtp_header *)data->buffer;
        payload = (struct rtp_payload *)(data->buffer + sizeof(*header));
@@ -547,14 +569,23 @@ static int avdtp_write(struct bluetooth_data *data)
        header->ssrc = htonl(1);
 
        data->stream.revents = 0;
-       ret = poll(&data->stream, 1, -1);
+#ifdef ENABLE_TIMING
+       begin2 = get_microseconds();
+#endif
+       ret = poll(&data->stream, 1, POLL_TIMEOUT);
+#ifdef ENABLE_TIMING
+       end2 = get_microseconds();
+       print_time("poll", begin2, end2);
+#endif
        if (ret == 1 && data->stream.revents == POLLOUT) {
                long ahead = 0;
-               gettimeofday(&now, NULL);
+               now = get_microseconds();
 
-               if (data->next_write.tv_sec || data->next_write.tv_usec) {
-                       ahead = (data->next_write.tv_sec - now.tv_sec) * 1000000
-                               + (data->next_write.tv_usec - now.tv_usec);
+               if (data->next_write) {
+                       ahead = data->next_write - now;
+#ifdef ENABLE_TIMING
+                       DBG("duration: %ld, ahead: %ld", duration, ahead);
+#endif
                        if (ahead > 0) {
                                /* too fast, need to throttle */
                                usleep(ahead);
@@ -562,25 +593,35 @@ static int avdtp_write(struct bluetooth_data *data)
                } else {
                        data->next_write = now;
                }
-               if (ahead < -duration * PACKET_BUFFER_COUNT) {
+               if (ahead < 0) {
                        /* fallen too far behind, don't try to catch up */
-                       data->next_write.tv_sec = 0;
-                       data->next_write.tv_usec = 0;
+                       VDBG("ahead < 0, resetting next_write");
+                       data->next_write = 0;
                } else {
                        /* advance next_write by duration */
-                       data->next_write.tv_usec += duration;
-                       data->next_write.tv_sec +=
-                               data->next_write.tv_usec / 1000000;
-                       data->next_write.tv_usec %= 1000000;
+                       data->next_write += duration;
                }
 
+#ifdef ENABLE_TIMING
+               begin2 = get_microseconds();
+#endif
                ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL);
+#ifdef ENABLE_TIMING
+               end2 = get_microseconds();
+               print_time("send", begin2, end2);
+#endif
                if (ret < 0) {
                        ERR("send returned %d errno %s.", ret, strerror(errno));
                        ret = -errno;
                }
        } else {
                ret = -errno;
+               ERR("poll failed: %d", ret);
+       }
+
+       if (ret < 0) {
+               close(data->stream.fd);
+               data->stream.fd = -1;
        }
 
        /* Reset buffer of data to send */
@@ -589,6 +630,10 @@ static int avdtp_write(struct bluetooth_data *data)
        data->samples = 0;
        data->seq_num++;
 
+#ifdef ENABLE_TIMING
+       end = get_microseconds();
+       print_time("avdtp_write", begin, end);
+#endif
        return ret;
 }
 
@@ -611,13 +656,19 @@ static int audioservice_send(struct bluetooth_data *data,
        return err;
 }
 
-static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
+static int audioservice_recv(struct bluetooth_data *data,
+               bt_audio_msg_header_t *inmsg)
 {
        int err;
        const char *type;
 
        VDBG("trying to receive msg from audio service...");
-       if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) {
+       data->server.revents = 0;
+       err = poll(&data->server, 1, POLL_TIMEOUT);
+       VDBG("poll returned %d", ret);
+       if (err == 1)
+               err = recv(data->server.fd, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0);
+       if (err > 0) {
                type = bt_audio_strmsg(inmsg->msg_type);
                if (type) {
                        VDBG("Received %s", type);
@@ -632,6 +683,8 @@ static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
                err = -errno;
                ERR("Error receiving data from audio service: %s(%d)",
                                        strerror(errno), errno);
+               close(data->server.fd);
+               data->server.fd = -1;
        }
 
        return err;
@@ -640,7 +693,7 @@ static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
 static int audioservice_expect(struct bluetooth_data *data,
                bt_audio_msg_header_t *rsp_hdr, int expected_type)
 {
-       int err = audioservice_recv(data->server.fd, rsp_hdr);
+       int err = audioservice_recv(data, rsp_hdr);
        if (err == 0) {
                if (rsp_hdr->msg_type != expected_type) {
                        err = -EINVAL;
@@ -661,7 +714,7 @@ static int bluetooth_init(struct bluetooth_data *data)
        struct bt_getcapabilities_req *getcaps_req = (void*) buf;
        struct bt_getcapabilities_rsp *getcaps_rsp = (void*) buf;
 
-       LOGD("bluetooth_init");
+       DBG("bluetooth_init");
 
        sk = bt_audio_service_open();
        if (sk <= 0) {
@@ -758,6 +811,11 @@ int a2dp_write(a2dpData d, const void* buffer, int count)
        long frames_left = count;
        int encoded, written;
        const char *buff;
+#ifdef ENABLE_TIMING
+       uint64_t begin, end;
+       DBG("********** a2dp_write **********");
+       begin = get_microseconds();
+#endif
 
        if (data->server.fd == -1) {
                err = bluetooth_init(data);
@@ -810,7 +868,10 @@ int a2dp_write(a2dpData d, const void* buffer, int count)
                ERR("%ld bytes left at end of a2dp_write\n", frames_left);
 
 done:
-       VDBG("returning %ld", ret);
+#ifdef ENABLE_TIMING
+       end = get_microseconds();
+       print_time("a2dp_write total", begin, end);
+#endif
        return ret;
 }
 
index 2af74bb..31a54be 100644 (file)
@@ -142,14 +142,17 @@ static gboolean stream_setup_retry(gpointer user_data)
        struct pending_request *pending = sink->connect;
 
        if (sink->state >= AVDTP_STATE_OPEN) {
-               DBusMessage *reply;
                debug("Stream successfully created, after XCASE connect:connect");
-               reply = dbus_message_new_method_return(pending->msg);
-               dbus_connection_send(pending->conn, reply, NULL);
-               dbus_message_unref(reply);
+               if (pending->msg) {
+                       DBusMessage *reply;
+                       reply = dbus_message_new_method_return(pending->msg);
+                       dbus_connection_send(pending->conn, reply, NULL);
+                       dbus_message_unref(reply);
+               }
        } else {
                debug("Stream setup failed, after XCASE connect:connect");
-               error_failed(pending->conn, pending->msg, "Stream setup failed");
+               if (pending->msg)
+                       error_failed(pending->conn, pending->msg, "Stream setup failed");
        }
 
        sink->connect = NULL;
@@ -168,27 +171,32 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
        pending = sink->connect;
 
        if (stream) {
-               DBusMessage *reply;
+               debug("Stream successfully created");
+
+               if (pending->msg) {
+                       DBusMessage *reply;
+                       reply = dbus_message_new_method_return(pending->msg);
+                       dbus_connection_send(pending->conn, reply, NULL);
+                       dbus_message_unref(reply);
+               }
                sink->connect = NULL;
-               reply = dbus_message_new_method_return(pending->msg);
-               dbus_connection_send(pending->conn, reply, NULL);
-               dbus_message_unref(reply);
                pending_request_free(pending);
-               debug("Stream successfully created");
+               return;
+       }
+
+       avdtp_unref(sink->session);
+       sink->session = NULL;
+       if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
+                       && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+               debug("connect:connect XCASE detected");
+               g_timeout_add(STREAM_SETUP_RETRY_TIMER,
+                               stream_setup_retry, sink);
        } else {
-               avdtp_unref(sink->session);
-               sink->session = NULL;
-               if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
-                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
-                       debug("connect:connect XCASE detected");
-                       g_timeout_add(STREAM_SETUP_RETRY_TIMER,
-                                       stream_setup_retry, sink);
-               } else {
-                       sink->connect = NULL;
+               if (pending->msg)
                        error_failed(pending->conn, pending->msg, "Stream setup failed");
-                       pending_request_free(pending);
-                       debug("Stream setup failed : %s", avdtp_strerror(err));
-               }
+               sink->connect = NULL;
+               pending_request_free(pending);
+               debug("Stream setup failed : %s", avdtp_strerror(err));
        }
 }
 
@@ -375,11 +383,28 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
        return;
 
 failed:
+       if (pending->msg)
+               error_failed(pending->conn, pending->msg, "Stream setup failed");
        pending_request_free(pending);
        sink->connect = NULL;
        avdtp_unref(sink->session);
        sink->session = NULL;
-       error_failed(pending->conn, pending->msg, "Stream setup failed");
+}
+
+gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
+{
+       if (sink->connect || sink->disconnect)
+               return FALSE;
+
+       if (session && !sink->session)
+               sink->session = avdtp_ref(session);
+
+       if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
+               return FALSE;
+
+       sink->connect = g_new0(struct pending_request, 1);
+
+       return TRUE;
 }
 
 static DBusMessage *sink_connect(DBusConnection *conn,
@@ -405,12 +430,13 @@ static DBusMessage *sink_connect(DBusConnection *conn,
                                                ".AlreadyConnected",
                                                "Device Already Connected");
 
-       pending = g_new0(struct pending_request, 1);
+       if (!sink_setup_stream(sink, NULL))
+               return g_dbus_create_error(msg, ERROR_INTERFACE ".FAILED",
+                                               "Failed to create a stream");
+
+       pending = sink->connect;
        pending->conn = dbus_connection_ref(conn);
        pending->msg = dbus_message_ref(msg);
-       sink->connect = pending;
-
-       avdtp_discover(sink->session, discovery_complete, sink);
 
        debug("stream creation in progress");
 
index 5e4b6aa..7adfa95 100644 (file)
@@ -30,3 +30,4 @@ gboolean sink_is_active(struct audio_device *dev);
 avdtp_state_t sink_get_state(struct audio_device *dev);
 gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
                                struct avdtp_stream *stream);
+gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);