@@ -43,6 +43,7 @@
#include "a2dp.h"
#include "headset.h"
#include "gateway.h"
+#include "ipc.h"
#ifndef DBUS_TYPE_UNIX_FD
#define DBUS_TYPE_UNIX_FD -1
@@ -53,6 +54,7 @@
struct media_request {
DBusMessage *msg;
guint id;
+ DBusConnection *conn;
};
struct media_owner {@@ -837,11 +839,123 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static GSList *handle_a2dp_transport(uint8_t codec)
+{
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct sbc_codec_cap sbc_cap;
+ struct mpeg_codec_cap mpg_cap;
+ GSList *caps = NULL;
+
+ if (codec == A2DP_CODEC_MPEG12) {
+ memset(&mpg_cap, 0, sizeof(mpg_cap));
+
+ /* FIXME: this code says MP3 and hope the receiver accept */
+ mpg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ mpg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
+ mpg_cap.channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ mpg_cap.crc = 0;
+ mpg_cap.layer = BT_MPEG_LAYER_3;
+ mpg_cap.frequency = MPEG_SAMPLING_FREQ_44100;
+ mpg_cap.mpf = 0;
+ mpg_cap.bitrate = 0x80;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpg_cap,
+ sizeof(mpg_cap));
+
+ DBG("Handling switch to MPEG transport");
+ } else if (codec == A2DP_CODEC_SBC) {
+ memset(&sbc_cap, 0, sizeof(sbc_cap));
+
+ /* FIXME: this is the mandatory SBC params for a source */
+ sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
+ sbc_cap.channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ sbc_cap.frequency = BT_SBC_SAMPLING_FREQ_44100;
+ sbc_cap.allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+ sbc_cap.subbands = BT_A2DP_SUBBANDS_8;
+ sbc_cap.block_length = BT_A2DP_BLOCK_LENGTH_16;
+ sbc_cap.min_bitpool = 53;
+ sbc_cap.max_bitpool = 53;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
+ sizeof(sbc_cap));
+
+ DBG("Handling switch to SBC transport");
+ } else
+ return NULL;
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ caps = g_slist_append(caps, media_transport);
+ caps = g_slist_append(caps, media_codec);
+
+ return caps;
+}
+
+static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct media_request *req = user_data;
+
+ media_request_reply(req, req->conn, err ? -ENOTSUP : 0);
+
+ dbus_connection_unref(req->conn);
+
+ g_free(req);
+}
+
+static void media_transport_reconfigure(struct avdtp *session, const char *path,
+ struct media_request *req)
+{
+ int err;
+ GSList *caps;
+ uint8_t codec;
+ struct media_endpoint *endpoint;
+ struct a2dp_sep *sep;
+
+ endpoint = media_endpoint_find(path);
+ if (endpoint == NULL) {
+ err = -EEXIST;
+ goto failed;
+ }
+ sep = media_endpoint_get_sep(endpoint);
+ codec = media_endpoint_get_codec(endpoint);
+
+ DBG(" sep %p creating caps list for codec %d", sep, codec);
+
+ /* FIXME prevent usage on SCO transport */
+ caps = handle_a2dp_transport(codec);
+ if (caps == NULL) {
+ err = -EINVAL;
+ goto failed;
+ }
+
+ err = a2dp_config(session, sep, a2dp_config_complete,
+ caps, req);
+ if (err < 0)
+ goto failed;
+
+ req->id = err;
+ return;
+
+failed:
+ media_request_reply(req, req->conn, -err);
+
+ dbus_connection_unref(req->conn);
+
+ g_free(req);
+}
+
static DBusMessage *reconfigure(DBusConnection *conn, DBusMessage *msg,
void *data)
{
+ struct media_transport *transport = data;
DBusMessageIter iter;
const char *endpoint;
+ struct media_request *req;
if (!dbus_message_iter_init(msg, &iter))
return btd_error_invalid_args(msg);@@ -849,6 +963,9 @@ static DBusMessage *reconfigure(DBusConnection *conn, DBusMessage *msg,
return btd_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &endpoint);
+ req = media_request_create(msg, 0);
+ req->conn = dbus_connection_ref(conn);
+ media_transport_reconfigure(transport->session, endpoint, req);
return NULL;
}