From 7323e1a0a85cb61f92749d9ca88339cea0bfa9c7 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 17 Dec 2008 17:19:22 -0300 Subject: Update module-bluetooth-device to the new ipc. --- src/modules/bluetooth/ipc.c | 52 ++++--- src/modules/bluetooth/ipc.h | 190 ++++++++++++------------ src/modules/bluetooth/module-bluetooth-device.c | 147 +++++++++++------- 3 files changed, 217 insertions(+), 172 deletions(-) (limited to 'src/modules') diff --git a/src/modules/bluetooth/ipc.c b/src/modules/bluetooth/ipc.c index 98256998..67785309 100644 --- a/src/modules/bluetooth/ipc.c +++ b/src/modules/bluetooth/ipc.c @@ -22,22 +22,26 @@ #include "ipc.h" -/* This table contains the string representation for messages */ -static const char *strmsg[] = { - "BT_GETCAPABILITIES_REQ", - "BT_GETCAPABILITIES_RSP", - "BT_SETCONFIGURATION_REQ", - "BT_SETCONFIGURATION_RSP", - "BT_STREAMSTART_REQ", - "BT_STREAMSTART_RSP", - "BT_STREAMSTOP_REQ", - "BT_STREAMSTOP_RSP", - "BT_STREAMSUSPEND_IND", - "BT_STREAMRESUME_IND", - "BT_CONTROL_REQ", - "BT_CONTROL_RSP", - "BT_CONTROL_IND", - "BT_STREAMFD_IND", +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* This table contains the string representation for messages types */ +static const char *strtypes[] = { + "BT_REQUEST", + "BT_RESPONSE", + "BT_INDICATION", + "BT_ERROR", +}; + +/* This table contains the string representation for messages names */ +static const char *strnames[] = { + "BT_GET_CAPABILITIES", + "BT_SET_CONFIGURATION", + "BT_NEW_STREAM", + "BT_START_STREAM", + "BT_STOP_STREAM", + "BT_SUSPEND_STREAM", + "BT_RESUME_STREAM", + "BT_CONTROL", }; int bt_audio_service_open(void) @@ -88,7 +92,7 @@ int bt_audio_service_get_data_fd(int sk) msgh.msg_control = &cmsg_b; msgh.msg_controllen = CMSG_LEN(sizeof(int)); - ret = (int) recvmsg(sk, &msgh, 0); + ret = recvmsg(sk, &msgh, 0); if (ret < 0) { err = errno; fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n", @@ -109,10 +113,18 @@ int bt_audio_service_get_data_fd(int sk) return -1; } -const char *bt_audio_strmsg(int type) +const char *bt_audio_strtype(uint8_t type) +{ + if (type >= ARRAY_SIZE(strtypes)) + return NULL; + + return strtypes[type]; +} + +const char *bt_audio_strname(uint8_t name) { - if (type < 0 || (size_t) type > (sizeof(strmsg) / sizeof(strmsg[0]))) + if (name >= ARRAY_SIZE(strnames)) return NULL; - return strmsg[type]; + return strnames[name]; } diff --git a/src/modules/bluetooth/ipc.h b/src/modules/bluetooth/ipc.h index ae85e727..0e985c3a 100644 --- a/src/modules/bluetooth/ipc.h +++ b/src/modules/bluetooth/ipc.h @@ -23,36 +23,36 @@ /* Message sequence chart of streaming sequence for A2DP transport - Audio daemon User - on snd_pcm_open - <--BT_GETCAPABILITIES_REQ + Audio daemon User + on snd_pcm_open + <--BT_GET_CAPABILITIES_REQ - BT_GETCAPABILITIES_RSP--> + BT_GET_CAPABILITIES_RSP--> - on snd_pcm_hw_params - <--BT_SETCONFIGURATION_REQ + on snd_pcm_hw_params + <--BT_SETCONFIGURATION_REQ - BT_SETCONFIGURATION_RSP--> + BT_SET_CONFIGURATION_RSP--> - on snd_pcm_prepare - <--BT_STREAMSTART_REQ + on snd_pcm_prepare + <--BT_START_STREAM_REQ - BT_STREAMSTART_RSP--> + BT_START_STREAM_RSP--> - BT_STREAMFD_IND --> + BT_NEW_STREAM_IND --> - < streams data > - .......... + < streams data > + .......... - on snd_pcm_drop/snd_pcm_drain + on snd_pcm_drop/snd_pcm_drain - <--BT_STREAMSTOP_REQ + <--BT_STOP_STREAM_REQ - BT_STREAMSTOP_RSP--> + BT_STOP_STREAM_RSP--> - on IPC close or appl crash + on IPC close or appl crash */ @@ -71,43 +71,36 @@ extern "C" { #include #include -#define BT_AUDIO_IPC_PACKET_SIZE 128 +#define BT_SUGGESTED_BUFFER_SIZE 128 #define BT_IPC_SOCKET_NAME "\0/org/bluez/audio" -/* Generic message header definition, except for RSP messages */ +/* Generic message header definition, except for RESPONSE messages */ typedef struct { - uint8_t msg_type; + uint8_t type; + uint8_t name; + uint16_t length; } __attribute__ ((packed)) bt_audio_msg_header_t; -/* Generic message header definition, for all RSP messages */ typedef struct { - bt_audio_msg_header_t msg_h; - uint8_t posix_errno; -} __attribute__ ((packed)) bt_audio_rsp_msg_header_t; - -/* Messages list */ -#define BT_GETCAPABILITIES_REQ 0 -#define BT_GETCAPABILITIES_RSP 1 - -#define BT_SETCONFIGURATION_REQ 2 -#define BT_SETCONFIGURATION_RSP 3 - -#define BT_STREAMSTART_REQ 4 -#define BT_STREAMSTART_RSP 5 - -#define BT_STREAMSTOP_REQ 6 -#define BT_STREAMSTOP_RSP 7 - -#define BT_STREAMSUSPEND_IND 8 -#define BT_STREAMRESUME_IND 9 - -#define BT_CONTROL_REQ 10 -#define BT_CONTROL_RSP 11 -#define BT_CONTROL_IND 12 - -#define BT_STREAMFD_IND 13 - -/* BT_GETCAPABILITIES_REQ */ + bt_audio_msg_header_t h; + uint8_t posix_errno; +} __attribute__ ((packed)) bt_audio_error_t; + +/* Message types */ +#define BT_REQUEST 0 +#define BT_RESPONSE 1 +#define BT_INDICATION 2 +#define BT_ERROR 3 + +/* Messages names */ +#define BT_GET_CAPABILITIES 0 +#define BT_SET_CONFIGURATION 1 +#define BT_NEW_STREAM 2 +#define BT_START_STREAM 3 +#define BT_STOP_STREAM 4 +#define BT_SUSPEND_STREAM 5 +#define BT_RESUME_STREAM 6 +#define BT_CONTROL 7 #define BT_CAPABILITIES_TRANSPORT_A2DP 0 #define BT_CAPABILITIES_TRANSPORT_SCO 1 @@ -119,19 +112,22 @@ typedef struct { #define BT_FLAG_AUTOCONNECT 1 -struct bt_getcapabilities_req { +struct bt_get_capabilities_req { bt_audio_msg_header_t h; char device[18]; /* Address of the remote Device */ uint8_t transport; /* Requested transport */ uint8_t flags; /* Requested flags */ } __attribute__ ((packed)); -/* BT_GETCAPABILITIES_RSP */ - /** * SBC Codec parameters as per A2DP profile 1.0 § 4.3 */ +#define BT_A2DP_CODEC_SBC 0x00 +#define BT_A2DP_CODEC_MPEG12 0x01 +#define BT_A2DP_CODEC_MPEG24 0x02 +#define BT_A2DP_CODEC_ATRAC 0x03 + #define BT_SBC_SAMPLING_FREQ_16000 (1 << 3) #define BT_SBC_SAMPLING_FREQ_32000 (1 << 2) #define BT_SBC_SAMPLING_FREQ_44100 (1 << 1) @@ -164,7 +160,19 @@ struct bt_getcapabilities_req { #define BT_MPEG_LAYER_2 (1 << 1) #define BT_MPEG_LAYER_3 1 +#define BT_HFP_CODEC_PCM 0x00 + +#define BT_PCM_FLAG_NREC 1 + +typedef struct { + uint8_t transport; + uint8_t type; + uint8_t length; + uint8_t data[0]; +} __attribute__ ((packed)) codec_capabilities_t; + typedef struct { + codec_capabilities_t capability; uint8_t channel_mode; uint8_t frequency; uint8_t allocation_method; @@ -175,6 +183,7 @@ typedef struct { } __attribute__ ((packed)) sbc_capabilities_t; typedef struct { + codec_capabilities_t capability; uint8_t channel_mode; uint8_t crc; uint8_t layer; @@ -183,75 +192,65 @@ typedef struct { uint16_t bitrate; } __attribute__ ((packed)) mpeg_capabilities_t; -struct bt_getcapabilities_rsp { - bt_audio_rsp_msg_header_t rsp_h; - uint8_t transport; /* Granted transport */ - sbc_capabilities_t sbc_capabilities; /* A2DP only */ - mpeg_capabilities_t mpeg_capabilities; /* A2DP only */ - uint16_t sampling_rate; /* SCO only */ +typedef struct { + codec_capabilities_t capability; + uint8_t flags; + uint16_t sampling_rate; +} __attribute__ ((packed)) pcm_capabilities_t; + + +struct bt_get_capabilities_rsp { + bt_audio_msg_header_t h; + uint8_t data[0]; /* First codec_capabilities_t */ } __attribute__ ((packed)); -/* BT_SETCONFIGURATION_REQ */ -struct bt_setconfiguration_req { +struct bt_set_configuration_req { bt_audio_msg_header_t h; - char device[18]; /* Address of the remote Device */ - uint8_t transport; /* Requested transport */ - uint8_t access_mode; /* Requested access mode */ - sbc_capabilities_t sbc_capabilities; /* A2DP only - only one of this field - and next one must be filled */ - mpeg_capabilities_t mpeg_capabilities; /* A2DP only */ + char device[18]; /* Address of the remote Device */ + uint8_t access_mode; /* Requested access mode */ + codec_capabilities_t codec; /* Requested codec */ } __attribute__ ((packed)); -/* BT_SETCONFIGURATION_RSP */ -struct bt_setconfiguration_rsp { - bt_audio_rsp_msg_header_t rsp_h; - uint8_t transport; /* Granted transport */ - uint8_t access_mode; /* Granted access mode */ - uint16_t link_mtu; /* Max length that transport supports */ +struct bt_set_configuration_rsp { + bt_audio_msg_header_t h; + uint8_t transport; /* Granted transport */ + uint8_t access_mode; /* Granted access mode */ + uint16_t link_mtu; /* Max length that transport supports */ } __attribute__ ((packed)); -/* BT_STREAMSTART_REQ */ #define BT_STREAM_ACCESS_READ 0 #define BT_STREAM_ACCESS_WRITE 1 #define BT_STREAM_ACCESS_READWRITE 2 -struct bt_streamstart_req { +struct bt_start_stream_req { bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMSTART_RSP */ -struct bt_streamstart_rsp { - bt_audio_rsp_msg_header_t rsp_h; +struct bt_start_stream_rsp { + bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMFD_IND */ /* This message is followed by one byte of data containing the stream data fd as ancilliary data */ -struct bt_streamfd_ind { +struct bt_new_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMSTOP_REQ */ -struct bt_streamstop_req { +struct bt_stop_stream_req { bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMSTOP_RSP */ -struct bt_streamstop_rsp { - bt_audio_rsp_msg_header_t rsp_h; +struct bt_stop_stream_rsp { + bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMSUSPEND_IND */ -struct bt_streamsuspend_ind { +struct bt_suspend_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_STREAMRESUME_IND */ -struct bt_streamresume_ind { +struct bt_resume_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); -/* BT_CONTROL_REQ */ - #define BT_CONTROL_KEY_POWER 0x40 #define BT_CONTROL_KEY_VOL_UP 0x41 #define BT_CONTROL_KEY_VOL_DOWN 0x42 @@ -272,14 +271,12 @@ struct bt_control_req { uint8_t key; /* Control Key */ } __attribute__ ((packed)); -/* BT_CONTROL_RSP */ struct bt_control_rsp { - bt_audio_rsp_msg_header_t rsp_h; - uint8_t mode; /* Control Mode */ - uint8_t key; /* Control Key */ + bt_audio_msg_header_t h; + uint8_t mode; /* Control Mode */ + uint8_t key; /* Control Key */ } __attribute__ ((packed)); -/* BT_CONTROL_IND */ struct bt_control_ind { bt_audio_msg_header_t h; uint8_t mode; /* Control Mode */ @@ -299,7 +296,10 @@ BT_STREAMFD_IND message is returned */ int bt_audio_service_get_data_fd(int sk); /* Human readable message type string */ -const char *bt_audio_strmsg(int type); +const char *bt_audio_strtype(uint8_t type); + +/* Human readable message name string */ +const char *bt_audio_strname(uint8_t name); #ifdef __cplusplus } diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 3460fe9a..5974d485 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -122,8 +122,12 @@ static const char* const valid_modargs[] = { static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) { int e; - pa_log_debug("sending %s", bt_audio_strmsg(msg->msg_type)); - if (send(sk, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) + const char *type, *name; + + type = bt_audio_strtype(msg->type); + name = bt_audio_strname(msg->name); + pa_log_debug("sending: %s -> %s", type, name); + if (send(sk, msg, BT_SUGGESTED_BUFFER_SIZE, 0) > 0) e = 0; else { e = -errno; @@ -132,20 +136,22 @@ static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) { return e; } -static int bt_audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) { +static int bt_audioservice_recv(int sk, bt_audio_msg_header_t *inmsg, uint16_t expected_length) { int e; - const char *type; + const char *type, *name; pa_log_debug("trying to receive msg from audio service..."); - if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) { - type = bt_audio_strmsg(inmsg->msg_type); - if (type) { - pa_log_debug("Received %s", type); + if (recv(sk, inmsg, expected_length ? : BT_SUGGESTED_BUFFER_SIZE, 0) > 0) { + type = bt_audio_strtype(inmsg->type); + name = bt_audio_strname(inmsg->name); + if (type && name) { + pa_log_debug("Received: %s <- %s", type, name); e = 0; } else { e = -EINVAL; - pa_log_error("Bogus message type %d received from audio service", inmsg->msg_type); + pa_log_error("Bogus message type %d name %d received from audio service", + inmsg->type, inmsg->name); } } else { @@ -156,29 +162,66 @@ static int bt_audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) { return e; } -static int bt_audioservice_expect(int sk, bt_audio_msg_header_t *rsp_hdr, int expected_type) { - int e = bt_audioservice_recv(sk, rsp_hdr); - if (e == 0) { - if (rsp_hdr->msg_type != expected_type) { +static int bt_audioservice_expect(int sk, bt_audio_msg_header_t *rsp, uint8_t expected_name, uint16_t expected_length) { + int e = bt_audioservice_recv(sk, rsp, expected_length); + + if (e < 0) { + if (rsp->name != expected_name) { e = -EINVAL; - pa_log_error("Bogus message %s received while %s was expected", bt_audio_strmsg(rsp_hdr->msg_type), - bt_audio_strmsg(expected_type)); + pa_log_error("Bogus message %s received while %s was expected", + bt_audio_strname(rsp->name), + bt_audio_strname(expected_name)); } } + + if (rsp->type == BT_ERROR) { + bt_audio_error_t *error = (void *) rsp; + pa_log_error("%s failed : %s(%d)", bt_audio_strname(rsp->name), pa_cstrerror(error->posix_errno), error->posix_errno); + return -error->posix_errno; + } + return e; } +static int bt_parsecaps(struct userdata *u, struct bt_get_capabilities_rsp *rsp) { + uint16_t bytes_left = rsp->h.length - sizeof(*rsp); + codec_capabilities_t *codec = (void *) rsp->data; + + u->transport = codec->transport; + + if (codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) + return 0; + + while (bytes_left > 0) { + if (codec->type == BT_A2DP_CODEC_SBC) + break; + + bytes_left -= codec->length; + codec = (void *) (codec + codec->length); + } + + if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities)) + return -EINVAL; + + memcpy(&u->a2dp.sbc_capabilities, codec, codec->length); + + return 0; +} + static int bt_getcaps(struct userdata *u) { int e; union { - bt_audio_rsp_msg_header_t rsp_hdr; - struct bt_getcapabilities_req getcaps_req; - struct bt_getcapabilities_rsp getcaps_rsp; - uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE]; + bt_audio_msg_header_t rsp; + struct bt_get_capabilities_req getcaps_req; + struct bt_get_capabilities_rsp getcaps_rsp; + uint8_t buf[BT_SUGGESTED_BUFFER_SIZE]; } msg; - memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE); - msg.getcaps_req.h.msg_type = BT_GETCAPABILITIES_REQ; + memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE); + msg.getcaps_req.h.type = BT_REQUEST; + msg.getcaps_req.h.name = BT_GET_CAPABILITIES; + msg.getcaps_req.h.length = sizeof(msg.getcaps_req); + strncpy(msg.getcaps_req.device, u->addr, 18); if (strcasecmp(u->profile, "a2dp") == 0) msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP; @@ -196,20 +239,13 @@ static int bt_getcaps(struct userdata *u) { return e; } - e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_GETCAPABILITIES_RSP); + e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp, BT_GET_CAPABILITIES, 0); if (e < 0) { pa_log_error("Failed to expect for GETCAPABILITIES_RSP"); return e; } - if (msg.rsp_hdr.posix_errno != 0) { - pa_log_error("BT_GETCAPABILITIES failed : %s (%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno); - return -msg.rsp_hdr.posix_errno; - } - - if ((u->transport = msg.getcaps_rsp.transport) == BT_CAPABILITIES_TRANSPORT_A2DP) - u->a2dp.sbc_capabilities = msg.getcaps_rsp.sbc_capabilities; - return 0; + return bt_parsecaps(u, &msg.getcaps_rsp); } static uint8_t default_bitpool(uint8_t freq, uint8_t mode) { @@ -393,10 +429,10 @@ static void bt_a2dp_setup(struct bt_a2dp *a2dp) { static int bt_setconf(struct userdata *u) { int e; union { - bt_audio_rsp_msg_header_t rsp_hdr; - struct bt_setconfiguration_req setconf_req; - struct bt_setconfiguration_rsp setconf_rsp; - uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE]; + bt_audio_msg_header_t rsp; + struct bt_set_configuration_req setconf_req; + struct bt_set_configuration_rsp setconf_rsp; + uint8_t buf[BT_SUGGESTED_BUFFER_SIZE]; } msg; if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) { @@ -410,12 +446,16 @@ static int bt_setconf(struct userdata *u) { else u->ss.format = PA_SAMPLE_U8; - memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE); - msg.setconf_req.h.msg_type = BT_SETCONFIGURATION_REQ; + memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE); + msg.setconf_req.h.type = BT_REQUEST; + msg.setconf_req.h.name = BT_SET_CONFIGURATION; + msg.setconf_req.h.length = sizeof(msg.setconf_req); + strncpy(msg.setconf_req.device, u->addr, 18); - msg.setconf_req.transport = u->transport; + msg.setconf_req.codec.transport = u->transport; if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) - msg.setconf_req.sbc_capabilities = u->a2dp.sbc_capabilities; + memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, + sizeof(u->a2dp.sbc_capabilities)); msg.setconf_req.access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE; e = bt_audioservice_send(u->audioservice_fd, &msg.setconf_req.h); @@ -424,17 +464,12 @@ static int bt_setconf(struct userdata *u) { return e; } - e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_SETCONFIGURATION_RSP); + e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp, BT_SET_CONFIGURATION, sizeof(msg.setconf_rsp)); if (e < 0) { pa_log_error("Failed to expect BT_SETCONFIGURATION_RSP"); return e; } - if (msg.rsp_hdr.posix_errno != 0) { - pa_log_error("BT_SETCONFIGURATION failed : %s(%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno); - return -msg.rsp_hdr.posix_errno; - } - u->transport = msg.setconf_rsp.transport; u->strtransport = (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ? pa_xstrdup("A2DP") : pa_xstrdup("SCO")); u->link_mtu = msg.setconf_rsp.link_mtu; @@ -456,14 +491,17 @@ static int bt_getstreamfd(struct userdata *u) { int e; // uint32_t period_count = io->buffer_size / io->period_size; union { - bt_audio_rsp_msg_header_t rsp_hdr; - struct bt_streamstart_req start_req; - struct bt_streamfd_ind streamfd_ind; - uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE]; + bt_audio_msg_header_t rsp; + struct bt_start_stream_req start_req; + struct bt_start_stream_rsp start_rsp; + struct bt_new_stream_ind streamfd_ind; + uint8_t buf[BT_SUGGESTED_BUFFER_SIZE]; } msg; - memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE); - msg.start_req.h.msg_type = BT_STREAMSTART_REQ; + memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE); + msg.start_req.h.type = BT_REQUEST; + msg.start_req.h.name = BT_START_STREAM; + msg.start_req.h.length = sizeof(msg.start_req); e = bt_audioservice_send(u->audioservice_fd, &msg.start_req.h); if (e < 0) { @@ -471,18 +509,13 @@ static int bt_getstreamfd(struct userdata *u) { return e; } - e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_STREAMSTART_RSP); + e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp, BT_START_STREAM, sizeof(msg.start_rsp)); if (e < 0) { pa_log_error("Failed to expect BT_STREAMSTART_RSP"); return e; } - if (msg.rsp_hdr.posix_errno != 0) { - pa_log_error("BT_START failed : %s(%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno); - return -msg.rsp_hdr.posix_errno; - } - - e = bt_audioservice_expect(u->audioservice_fd, &msg.streamfd_ind.h, BT_STREAMFD_IND); + e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp, BT_NEW_STREAM, sizeof(msg.streamfd_ind)); if (e < 0) { pa_log_error("Failed to expect BT_STREAMFD_IND"); return e; -- cgit From fe2b8c359b505dfa4c5fb75f223fc35c7ecdfd4b Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Sat, 20 Dec 2008 23:44:09 +0200 Subject: Multicast SDP packets sent with same IP TTL as RTP packets Signed-off-by: Lennart Poettering --- src/modules/rtp/module-rtp-send.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/modules') diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 8d1e92fe..9c0f07f1 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -296,6 +296,11 @@ int pa__init(pa_module*m) { pa_log("IP_MULTICAST_TTL failed: %s", pa_cstrerror(errno)); goto fail; } + + if (setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) { + pa_log("IP_MULTICAST_TTL (sap) failed: %s", pa_cstrerror(errno)); + goto fail; + } } /* If the socket queue is full, let's drop packets */ -- cgit From be49c92a381d433704438c810ce8e1b09b9aa550 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 5 Jan 2009 19:12:43 -0300 Subject: Send packets with proper size. --- src/modules/bluetooth/module-bluetooth-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 5974d485..492ee203 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -127,7 +127,7 @@ static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) { type = bt_audio_strtype(msg->type); name = bt_audio_strname(msg->name); pa_log_debug("sending: %s -> %s", type, name); - if (send(sk, msg, BT_SUGGESTED_BUFFER_SIZE, 0) > 0) + if (send(sk, msg, msg->length, 0) > 0) e = 0; else { e = -errno; -- cgit From 1a96c9b0a6dceeeb1701703fef8bdb15572662cf Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 6 Jan 2009 11:00:44 -0300 Subject: Fix send and recv message sizes. --- src/modules/bluetooth/module-bluetooth-device.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/modules') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 492ee203..2546c694 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -123,11 +123,13 @@ static const char* const valid_modargs[] = { static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) { int e; const char *type, *name; + uint16_t length; + length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE; type = bt_audio_strtype(msg->type); name = bt_audio_strname(msg->name); pa_log_debug("sending: %s -> %s", type, name); - if (send(sk, msg, msg->length, 0) > 0) + if (send(sk, msg, length, 0) > 0) e = 0; else { e = -errno; @@ -139,9 +141,12 @@ static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) { static int bt_audioservice_recv(int sk, bt_audio_msg_header_t *inmsg, uint16_t expected_length) { int e; const char *type, *name; + uint16_t length; + + length = expected_length ? expected_length : BT_SUGGESTED_BUFFER_SIZE; pa_log_debug("trying to receive msg from audio service..."); - if (recv(sk, inmsg, expected_length ? : BT_SUGGESTED_BUFFER_SIZE, 0) > 0) { + if (recv(sk, inmsg, length, 0) > 0) { type = bt_audio_strtype(inmsg->type); name = bt_audio_strname(inmsg->name); if (type && name) { -- cgit From e7e6f86bbe0dda37e906ed31144b44a83327ee02 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 6 Jan 2009 11:02:16 -0300 Subject: Fix sending wrong codec capability length. --- src/modules/bluetooth/module-bluetooth-device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/modules') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 2546c694..cb4746a4 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -458,9 +458,12 @@ static int bt_setconf(struct userdata *u) { strncpy(msg.setconf_req.device, u->addr, 18); msg.setconf_req.codec.transport = u->transport; - if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) + if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) { memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities)); + msg.setconf_req.h.length += msg.setconf_req.codec.length + - sizeof(msg.setconf_req.codec); + } msg.setconf_req.access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE; e = bt_audioservice_send(u->audioservice_fd, &msg.setconf_req.h); -- cgit From c2450501af82d1c9d1994e4f4ce80d506d3c90ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Jan 2009 01:03:42 +0100 Subject: Prefer mixer controls with volumes over switches When we look for a mixer control prefer controls that have both volume and a mute switch over those that have only a volume switch over those that only have a mute switch. Originally pointed out by Adel Gadllah. --- src/modules/alsa-util.c | 80 ++++++++++++++++++++++++++++++++++++---- src/modules/alsa-util.h | 2 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- 4 files changed, 75 insertions(+), 11 deletions(-) (limited to 'src/modules') diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 75b84c40..ff3af19d 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -760,8 +760,32 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { return 0; } -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) { - snd_mixer_elem_t *elem; +static pa_bool_t elem_has_volume(snd_mixer_elem_t *elem, pa_bool_t playback) { + pa_assert(elem); + + if (playback && snd_mixer_selem_has_playback_volume(elem)) + return TRUE; + + if (!playback && snd_mixer_selem_has_capture_volume(elem)) + return TRUE; + + return FALSE; +} + +static pa_bool_t elem_has_switch(snd_mixer_elem_t *elem, pa_bool_t playback) { + pa_assert(elem); + + if (playback && snd_mixer_selem_has_playback_switch(elem)) + return TRUE; + + if (!playback && snd_mixer_selem_has_capture_switch(elem)) + return TRUE; + + return FALSE; +} + +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback) { + snd_mixer_elem_t *elem = NULL, *fallback_elem = NULL; snd_mixer_selem_id_t *sid = NULL; snd_mixer_selem_id_alloca(&sid); @@ -771,17 +795,57 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const snd_mixer_selem_id_set_name(sid, name); - if (!(elem = snd_mixer_find_selem(mixer, sid))) { - pa_log_info("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + if ((elem = snd_mixer_find_selem(mixer, sid))) { + + if (elem_has_volume(elem, playback) && + elem_has_switch(elem, playback)) + goto success; + + if (!elem_has_volume(elem, playback) && + !elem_has_switch(elem, playback)) + elem = NULL; + } + + pa_log_info("Cannot find mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid)); + + if (fallback) { + snd_mixer_selem_id_set_name(sid, fallback); + + if ((fallback_elem = snd_mixer_find_selem(mixer, sid))) { + + if (elem_has_volume(fallback_elem, playback) && + elem_has_switch(fallback_elem, playback)) { + elem = fallback_elem; + goto success; + } + + if (!elem_has_volume(fallback_elem, playback) && + !elem_has_switch(fallback_elem, playback)) + fallback_elem = NULL; + } + + pa_log_warn("Cannot find fallback mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid)); + } + + if (elem && fallback_elem) { - if (fallback) { - snd_mixer_selem_id_set_name(sid, fallback); + /* Hmm, so we have both elements, but neither has both mute + * and volume. Let's prefer the one with the volume */ - if (!(elem = snd_mixer_find_selem(mixer, sid))) - pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + if (elem_has_volume(elem, playback)) + goto success; + + if (elem_has_volume(fallback_elem, playback)) { + elem = fallback_elem; + goto success; } } + if (!elem && fallback_elem) + elem = fallback_elem; + +success: + if (elem) pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index aaa01c78..95bb983a 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -52,7 +52,7 @@ int pa_alsa_set_hw_params( int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback); +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback); snd_pcm_t *pa_alsa_open_by_device_id( const char *dev_id, diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6dea172f..95a8c972 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -1409,7 +1409,7 @@ int pa__init(pa_module*m) { } if (found) - if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM", TRUE))) found = FALSE; if (!found) { diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index f796ef14..b6c6ed1a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -1236,7 +1236,7 @@ int pa__init(pa_module*m) { } if (found) - if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic", FALSE))) found = FALSE; if (!found) { -- cgit From 7e6309c77cefee8c447266df4bab25e544000011 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 8 Jan 2009 19:13:49 +0200 Subject: bluetooth: Update sbc from git upstream. It contains encoding fixes, pass the conformance tests, and is now vectorizable. Next update might include SSE and/or Neon code. --- src/modules/bluetooth/sbc.c | 537 +++++++++++++++++-------------------- src/modules/bluetooth/sbc.h | 4 +- src/modules/bluetooth/sbc_math.h | 16 +- src/modules/bluetooth/sbc_tables.h | 250 ++++++++++++++--- 4 files changed, 460 insertions(+), 347 deletions(-) (limited to 'src/modules') diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc.c index 02a6143d..651981fa 100644 --- a/src/modules/bluetooth/sbc.c +++ b/src/modules/bluetooth/sbc.c @@ -2,7 +2,7 @@ * * Bluetooth low-complexity, subband codec (SBC) library * - * Copyright (C) 2004-2008 Marcel Holtmann + * Copyright (C) 2004-2009 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2008 Brad Midgley * @@ -40,6 +40,7 @@ #include #include #include +#include #include "sbc_math.h" #include "sbc_tables.h" @@ -68,7 +69,7 @@ struct sbc_frame { uint8_t subband_mode; uint8_t subbands; uint8_t bitpool; - uint8_t codesize; + uint16_t codesize; uint8_t length; /* bit number x set means joint stereo has been used in subband x */ @@ -93,7 +94,11 @@ struct sbc_decoder_state { struct sbc_encoder_state { int subbands; int position[2]; - int32_t X[2][160]; + int16_t X[2][256]; + void (*sbc_analyze_4b_4s)(int16_t *pcm, int16_t *x, + int32_t *out, int out_stride); + void (*sbc_analyze_4b_8s)(int16_t *pcm, int16_t *x, + int32_t *out, int out_stride); }; /* @@ -145,7 +150,7 @@ static uint8_t sbc_crc8(const uint8_t *data, size_t len) octet = data[i]; for (i = 0; i < len % 8; i++) { - unsigned char bit = ((octet ^ crc) & 0x80) >> 7; + char bit = ((octet ^ crc) & 0x80) >> 7; crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0); @@ -563,7 +568,7 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state, k = (i + 4) & 0xf; /* Store in output, Q0 */ - frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED2( + frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED1( MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0], MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0], MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1], @@ -609,7 +614,7 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, k = (i + 8) & 0xf; /* Store in output */ - frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED2( // Q0 + frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED1( // Q0 MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0], MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0], MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1], @@ -648,242 +653,144 @@ static int sbc_synthesize_audio(struct sbc_decoder_state *state, } } -static void sbc_encoder_init(struct sbc_encoder_state *state, - const struct sbc_frame *frame) +static inline void _sbc_analyze_four(const int16_t *in, int32_t *out) { - memset(&state->X, 0, sizeof(state->X)); - state->subbands = frame->subbands; - state->position[0] = state->position[1] = 9 * frame->subbands; -} + FIXED_A t1[4]; + FIXED_T t2[4]; + int i = 0, hop = 0; + + /* rounding coefficient */ + t1[0] = t1[1] = t1[2] = t1[3] = + (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); + + /* low pass polyphase filter */ + for (hop = 0; hop < 40; hop += 8) { + t1[0] += (FIXED_A) in[hop] * _sbc_proto_fixed4[hop]; + t1[1] += (FIXED_A) in[hop + 1] * _sbc_proto_fixed4[hop + 1]; + t1[2] += (FIXED_A) in[hop + 2] * _sbc_proto_fixed4[hop + 2]; + t1[1] += (FIXED_A) in[hop + 3] * _sbc_proto_fixed4[hop + 3]; + t1[0] += (FIXED_A) in[hop + 4] * _sbc_proto_fixed4[hop + 4]; + t1[3] += (FIXED_A) in[hop + 5] * _sbc_proto_fixed4[hop + 5]; + t1[3] += (FIXED_A) in[hop + 7] * _sbc_proto_fixed4[hop + 7]; + } -static inline void _sbc_analyze_four(const int32_t *in, int32_t *out) -{ - sbc_fixed_t t[8], s[5]; - - t[0] = SCALE4_STAGE1( /* Q8 */ - MULA(_sbc_proto_4[0], in[8] - in[32], /* Q18 */ - MUL( _sbc_proto_4[1], in[16] - in[24]))); - - t[1] = SCALE4_STAGE1( - MULA(_sbc_proto_4[2], in[1], - MULA(_sbc_proto_4[3], in[9], - MULA(_sbc_proto_4[4], in[17], - MULA(_sbc_proto_4[5], in[25], - MUL( _sbc_proto_4[6], in[33])))))); - - t[2] = SCALE4_STAGE1( - MULA(_sbc_proto_4[7], in[2], - MULA(_sbc_proto_4[8], in[10], - MULA(_sbc_proto_4[9], in[18], - MULA(_sbc_proto_4[10], in[26], - MUL( _sbc_proto_4[11], in[34])))))); - - t[3] = SCALE4_STAGE1( - MULA(_sbc_proto_4[12], in[3], - MULA(_sbc_proto_4[13], in[11], - MULA(_sbc_proto_4[14], in[19], - MULA(_sbc_proto_4[15], in[27], - MUL( _sbc_proto_4[16], in[35])))))); - - t[4] = SCALE4_STAGE1( - MULA(_sbc_proto_4[17], in[4] + in[36], - MULA(_sbc_proto_4[18], in[12] + in[28], - MUL( _sbc_proto_4[19], in[20])))); - - t[5] = SCALE4_STAGE1( - MULA(_sbc_proto_4[16], in[5], - MULA(_sbc_proto_4[15], in[13], - MULA(_sbc_proto_4[14], in[21], - MULA(_sbc_proto_4[13], in[29], - MUL( _sbc_proto_4[12], in[37])))))); - - /* don't compute t[6]... this term always multiplies - * with cos(pi/2) = 0 */ - - t[7] = SCALE4_STAGE1( - MULA(_sbc_proto_4[6], in[7], - MULA(_sbc_proto_4[5], in[15], - MULA(_sbc_proto_4[4], in[23], - MULA(_sbc_proto_4[3], in[31], - MUL( _sbc_proto_4[2], in[39])))))); - - s[0] = MUL( _anamatrix4[0], t[0] + t[4]); - s[1] = MUL( _anamatrix4[2], t[2]); - s[2] = MULA(_anamatrix4[1], t[1] + t[3], - MUL(_anamatrix4[3], t[5])); - s[3] = MULA(_anamatrix4[3], t[1] + t[3], - MUL(_anamatrix4[1], -t[5] + t[7])); - s[4] = MUL( _anamatrix4[3], t[7]); - - out[0] = SCALE4_STAGE2( s[0] + s[1] + s[2] + s[4]); /* Q0 */ - out[1] = SCALE4_STAGE2(-s[0] + s[1] + s[3]); - out[2] = SCALE4_STAGE2(-s[0] + s[1] - s[3]); - out[3] = SCALE4_STAGE2( s[0] + s[1] - s[2] - s[4]); + /* scaling */ + t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE; + t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE; + t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE; + t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE; + + /* do the cos transform */ + for (i = 0, hop = 0; i < 4; hop += 8, i++) { + out[i] = ((FIXED_A) t2[0] * cos_table_fixed_4[0 + hop] + + (FIXED_A) t2[1] * cos_table_fixed_4[1 + hop] + + (FIXED_A) t2[2] * cos_table_fixed_4[2 + hop] + + (FIXED_A) t2[3] * cos_table_fixed_4[5 + hop]) >> + (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); + } } -static inline void sbc_analyze_four(struct sbc_encoder_state *state, - struct sbc_frame *frame, int ch, int blk) +static void sbc_analyze_4b_4s(int16_t *pcm, int16_t *x, + int32_t *out, int out_stride) { - int32_t *x = &state->X[ch][state->position[ch]]; - int16_t *pcm = &frame->pcm_sample[ch][blk * 4]; - - /* Input 4 Audio Samples */ - x[40] = x[0] = pcm[3]; - x[41] = x[1] = pcm[2]; - x[42] = x[2] = pcm[1]; - x[43] = x[3] = pcm[0]; - - _sbc_analyze_four(x, frame->sb_sample_f[blk][ch]); + int i; + + /* Input 4 x 4 Audio Samples */ + for (i = 0; i < 16; i += 4) { + x[64 + i] = x[0 + i] = pcm[15 - i]; + x[65 + i] = x[1 + i] = pcm[14 - i]; + x[66 + i] = x[2 + i] = pcm[13 - i]; + x[67 + i] = x[3 + i] = pcm[12 - i]; + } - state->position[ch] -= 4; - if (state->position[ch] < 0) - state->position[ch] = 36; + /* Analyze four blocks */ + _sbc_analyze_four(x + 12, out); + out += out_stride; + _sbc_analyze_four(x + 8, out); + out += out_stride; + _sbc_analyze_four(x + 4, out); + out += out_stride; + _sbc_analyze_four(x, out); } -static inline void _sbc_analyze_eight(const int32_t *in, int32_t *out) +static inline void _sbc_analyze_eight(const int16_t *in, int32_t *out) { - sbc_fixed_t t[8], s[8]; - - t[0] = SCALE8_STAGE1( /* Q10 */ - MULA(_sbc_proto_8[0], (in[16] - in[64]), /* Q18 = Q18 * Q0 */ - MULA(_sbc_proto_8[1], (in[32] - in[48]), - MULA(_sbc_proto_8[2], in[4], - MULA(_sbc_proto_8[3], in[20], - MULA(_sbc_proto_8[4], in[36], - MUL( _sbc_proto_8[5], in[52]))))))); - - t[1] = SCALE8_STAGE1( - MULA(_sbc_proto_8[6], in[2], - MULA(_sbc_proto_8[7], in[18], - MULA(_sbc_proto_8[8], in[34], - MULA(_sbc_proto_8[9], in[50], - MUL(_sbc_proto_8[10], in[66])))))); - - t[2] = SCALE8_STAGE1( - MULA(_sbc_proto_8[11], in[1], - MULA(_sbc_proto_8[12], in[17], - MULA(_sbc_proto_8[13], in[33], - MULA(_sbc_proto_8[14], in[49], - MULA(_sbc_proto_8[15], in[65], - MULA(_sbc_proto_8[16], in[3], - MULA(_sbc_proto_8[17], in[19], - MULA(_sbc_proto_8[18], in[35], - MULA(_sbc_proto_8[19], in[51], - MUL( _sbc_proto_8[20], in[67]))))))))))); - - t[3] = SCALE8_STAGE1( - MULA( _sbc_proto_8[21], in[5], - MULA( _sbc_proto_8[22], in[21], - MULA( _sbc_proto_8[23], in[37], - MULA( _sbc_proto_8[24], in[53], - MULA( _sbc_proto_8[25], in[69], - MULA(-_sbc_proto_8[15], in[15], - MULA(-_sbc_proto_8[14], in[31], - MULA(-_sbc_proto_8[13], in[47], - MULA(-_sbc_proto_8[12], in[63], - MUL( -_sbc_proto_8[11], in[79]))))))))))); - - t[4] = SCALE8_STAGE1( - MULA( _sbc_proto_8[26], in[6], - MULA( _sbc_proto_8[27], in[22], - MULA( _sbc_proto_8[28], in[38], - MULA( _sbc_proto_8[29], in[54], - MULA( _sbc_proto_8[30], in[70], - MULA(-_sbc_proto_8[10], in[14], - MULA(-_sbc_proto_8[9], in[30], - MULA(-_sbc_proto_8[8], in[46], - MULA(-_sbc_proto_8[7], in[62], - MUL( -_sbc_proto_8[6], in[78]))))))))))); - - t[5] = SCALE8_STAGE1( - MULA( _sbc_proto_8[31], in[7], - MULA( _sbc_proto_8[32], in[23], - MULA( _sbc_proto_8[33], in[39], - MULA( _sbc_proto_8[34], in[55], - MULA( _sbc_proto_8[35], in[71], - MULA(-_sbc_proto_8[20], in[13], - MULA(-_sbc_proto_8[19], in[29], - MULA(-_sbc_proto_8[18], in[45], - MULA(-_sbc_proto_8[17], in[61], - MUL( -_sbc_proto_8[16], in[77]))))))))))); - - t[6] = SCALE8_STAGE1( - MULA( _sbc_proto_8[36], (in[8] + in[72]), - MULA( _sbc_proto_8[37], (in[24] + in[56]), - MULA( _sbc_proto_8[38], in[40], - MULA(-_sbc_proto_8[39], in[12], - MULA(-_sbc_proto_8[5], in[28], - MULA(-_sbc_proto_8[4], in[44], - MULA(-_sbc_proto_8[3], in[60], - MUL( -_sbc_proto_8[2], in[76]))))))))); - - t[7] = SCALE8_STAGE1( - MULA( _sbc_proto_8[35], in[9], - MULA( _sbc_proto_8[34], in[25], - MULA( _sbc_proto_8[33], in[41], - MULA( _sbc_proto_8[32], in[57], - MULA( _sbc_proto_8[31], in[73], - MULA(-_sbc_proto_8[25], in[11], - MULA(-_sbc_proto_8[24], in[27], - MULA(-_sbc_proto_8[23], in[43], - MULA(-_sbc_proto_8[22], in[59], - MUL( -_sbc_proto_8[21], in[75]))))))))))); - - s[0] = MULA( _anamatrix8[0], t[0], - MUL( _anamatrix8[1], t[6])); - s[1] = MUL( _anamatrix8[7], t[1]); - s[2] = MULA( _anamatrix8[2], t[2], - MULA( _anamatrix8[3], t[3], - MULA( _anamatrix8[4], t[5], - MUL( _anamatrix8[5], t[7])))); - s[3] = MUL( _anamatrix8[6], t[4]); - s[4] = MULA( _anamatrix8[3], t[2], - MULA(-_anamatrix8[5], t[3], - MULA(-_anamatrix8[2], t[5], - MUL( -_anamatrix8[4], t[7])))); - s[5] = MULA( _anamatrix8[4], t[2], - MULA(-_anamatrix8[2], t[3], - MULA( _anamatrix8[5], t[5], - MUL( _anamatrix8[3], t[7])))); - s[6] = MULA( _anamatrix8[1], t[0], - MUL( -_anamatrix8[0], t[6])); - s[7] = MULA( _anamatrix8[5], t[2], - MULA(-_anamatrix8[4], t[3], - MULA( _anamatrix8[3], t[5], - MUL( -_anamatrix8[2], t[7])))); - - out[0] = SCALE8_STAGE2( s[0] + s[1] + s[2] + s[3]); - out[1] = SCALE8_STAGE2( s[1] - s[3] + s[4] + s[6]); - out[2] = SCALE8_STAGE2( s[1] - s[3] + s[5] - s[6]); - out[3] = SCALE8_STAGE2(-s[0] + s[1] + s[3] + s[7]); - out[4] = SCALE8_STAGE2(-s[0] + s[1] + s[3] - s[7]); - out[5] = SCALE8_STAGE2( s[1] - s[3] - s[5] - s[6]); - out[6] = SCALE8_STAGE2( s[1] - s[3] - s[4] + s[6]); - out[7] = SCALE8_STAGE2( s[0] + s[1] - s[2] + s[3]); + FIXED_A t1[8]; + FIXED_T t2[8]; + int i, hop; + + /* rounding coefficient */ + t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = + (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); + + /* low pass polyphase filter */ + for (hop = 0; hop < 80; hop += 16) { + t1[0] += (FIXED_A) in[hop] * _sbc_proto_fixed8[hop]; + t1[1] += (FIXED_A) in[hop + 1] * _sbc_proto_fixed8[hop + 1]; + t1[2] += (FIXED_A) in[hop + 2] * _sbc_proto_fixed8[hop + 2]; + t1[3] += (FIXED_A) in[hop + 3] * _sbc_proto_fixed8[hop + 3]; + t1[4] += (FIXED_A) in[hop + 4] * _sbc_proto_fixed8[hop + 4]; + t1[3] += (FIXED_A) in[hop + 5] * _sbc_proto_fixed8[hop + 5]; + t1[2] += (FIXED_A) in[hop + 6] * _sbc_proto_fixed8[hop + 6]; + t1[1] += (FIXED_A) in[hop + 7] * _sbc_proto_fixed8[hop + 7]; + t1[0] += (FIXED_A) in[hop + 8] * _sbc_proto_fixed8[hop + 8]; + t1[5] += (FIXED_A) in[hop + 9] * _sbc_proto_fixed8[hop + 9]; + t1[6] += (FIXED_A) in[hop + 10] * _sbc_proto_fixed8[hop + 10]; + t1[7] += (FIXED_A) in[hop + 11] * _sbc_proto_fixed8[hop + 11]; + t1[7] += (FIXED_A) in[hop + 13] * _sbc_proto_fixed8[hop + 13]; + t1[6] += (FIXED_A) in[hop + 14] * _sbc_proto_fixed8[hop + 14]; + t1[5] += (FIXED_A) in[hop + 15] * _sbc_proto_fixed8[hop + 15]; + } + + /* scaling */ + t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE; + t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE; + t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE; + t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE; + t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE; + t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE; + t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE; + t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE; + + /* do the cos transform */ + for (i = 0, hop = 0; i < 8; hop += 16, i++) { + out[i] = ((FIXED_A) t2[0] * cos_table_fixed_8[0 + hop] + + (FIXED_A) t2[1] * cos_table_fixed_8[1 + hop] + + (FIXED_A) t2[2] * cos_table_fixed_8[2 + hop] + + (FIXED_A) t2[3] * cos_table_fixed_8[3 + hop] + + (FIXED_A) t2[4] * cos_table_fixed_8[4 + hop] + + (FIXED_A) t2[5] * cos_table_fixed_8[9 + hop] + + (FIXED_A) t2[6] * cos_table_fixed_8[10 + hop] + + (FIXED_A) t2[7] * cos_table_fixed_8[11 + hop]) >> + (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS); + } } -static inline void sbc_analyze_eight(struct sbc_encoder_state *state, - struct sbc_frame *frame, int ch, - int blk) +static void sbc_analyze_4b_8s(int16_t *pcm, int16_t *x, + int32_t *out, int out_stride) { - int32_t *x = &state->X[ch][state->position[ch]]; - int16_t *pcm = &frame->pcm_sample[ch][blk * 8]; - - /* Input 8 Audio Samples */ - x[80] = x[0] = pcm[7]; - x[81] = x[1] = pcm[6]; - x[82] = x[2] = pcm[5]; - x[83] = x[3] = pcm[4]; - x[84] = x[4] = pcm[3]; - x[85] = x[5] = pcm[2]; - x[86] = x[6] = pcm[1]; - x[87] = x[7] = pcm[0]; - - _sbc_analyze_eight(x, frame->sb_sample_f[blk][ch]); - - state->position[ch] -= 8; - if (state->position[ch] < 0) - state->position[ch] = 72; + int i; + + /* Input 4 x 8 Audio Samples */ + for (i = 0; i < 32; i += 8) { + x[128 + i] = x[0 + i] = pcm[31 - i]; + x[129 + i] = x[1 + i] = pcm[30 - i]; + x[130 + i] = x[2 + i] = pcm[29 - i]; + x[131 + i] = x[3 + i] = pcm[28 - i]; + x[132 + i] = x[4 + i] = pcm[27 - i]; + x[133 + i] = x[5 + i] = pcm[26 - i]; + x[134 + i] = x[6 + i] = pcm[25 - i]; + x[135 + i] = x[7 + i] = pcm[24 - i]; + } + + /* Analyze four blocks */ + _sbc_analyze_eight(x + 24, out); + out += out_stride; + _sbc_analyze_eight(x + 16, out); + out += out_stride; + _sbc_analyze_eight(x + 8, out); + out += out_stride; + _sbc_analyze_eight(x, out); } static int sbc_analyze_audio(struct sbc_encoder_state *state, @@ -894,14 +801,32 @@ static int sbc_analyze_audio(struct sbc_encoder_state *state, switch (frame->subbands) { case 4: for (ch = 0; ch < frame->channels; ch++) - for (blk = 0; blk < frame->blocks; blk++) - sbc_analyze_four(state, frame, ch, blk); + for (blk = 0; blk < frame->blocks; blk += 4) { + state->sbc_analyze_4b_4s( + &frame->pcm_sample[ch][blk * 4], + &state->X[ch][state->position[ch]], + frame->sb_sample_f[blk][ch], + frame->sb_sample_f[blk + 1][ch] - + frame->sb_sample_f[blk][ch]); + state->position[ch] -= 16; + if (state->position[ch] < 0) + state->position[ch] = 64 - 16; + } return frame->blocks * 4; case 8: for (ch = 0; ch < frame->channels; ch++) - for (blk = 0; blk < frame->blocks; blk++) - sbc_analyze_eight(state, frame, ch, blk); + for (blk = 0; blk < frame->blocks; blk += 4) { + state->sbc_analyze_4b_8s( + &frame->pcm_sample[ch][blk * 8], + &state->X[ch][state->position[ch]], + frame->sb_sample_f[blk][ch], + frame->sb_sample_f[blk + 1][ch] - + frame->sb_sample_f[blk][ch]); + state->position[ch] -= 32; + if (state->position[ch] < 0) + state->position[ch] = 128 - 32; + } return frame->blocks * 8; default: @@ -909,6 +834,26 @@ static int sbc_analyze_audio(struct sbc_encoder_state *state, } } +/* Supplementary bitstream writing macros for 'sbc_pack_frame' */ + +#define PUT_BITS(v, n)\ + bits_cache = (v) | (bits_cache << (n));\ + bits_count += (n);\ + if (bits_count >= 16) {\ + bits_count -= 8;\ + *data_ptr++ = (uint8_t) (bits_cache >> bits_count);\ + bits_count -= 8;\ + *data_ptr++ = (uint8_t) (bits_cache >> bits_count);\ + }\ + +#define FLUSH_BITS()\ + while (bits_count >= 8) {\ + bits_count -= 8;\ + *data_ptr++ = (uint8_t) (bits_cache >> bits_count);\ + }\ + if (bits_count > 0)\ + *data_ptr++ = (uint8_t) (bits_cache << (8 - bits_count));\ + /* * Packs the SBC frame from frame into the memory at data. At most len * bytes will be used, should more memory be needed an appropriate @@ -926,16 +871,21 @@ static int sbc_analyze_audio(struct sbc_encoder_state *state, static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) { - int produced; + /* Bitstream writer starts from the fourth byte */ + uint8_t *data_ptr = data + 4; + uint32_t bits_cache = 0; + uint32_t bits_count = 0; + /* Will copy the header parts for CRC-8 calculation here */ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int crc_pos = 0; - uint16_t audio_sample; + uint32_t audio_sample; - int ch, sb, blk, bit; /* channel, subband, block and bit counters */ + int ch, sb, blk; /* channel, subband, block and bit counters */ int bits[2][8]; /* bits distribution */ - int levels[2][8]; /* levels are derived from that */ + uint32_t levels[2][8]; /* levels are derived from that */ + uint32_t sb_sample_delta[2][8]; u_int32_t scalefactor[2][8]; /* derived from frame->scale_factor */ @@ -973,8 +923,6 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) /* Can't fill in crc yet */ - produced = 32; - crc_header[0] = data[1]; crc_header[1] = data[2]; crc_pos = 16; @@ -982,7 +930,7 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) { frame->scale_factor[ch][sb] = 0; - scalefactor[ch][sb] = 2; + scalefactor[ch][sb] = 2 << SCALE_OUT_BITS; for (blk = 0; blk < frame->blocks; blk++) { while (scalefactor[ch][sb] < fabs(frame->sb_sample_f[blk][ch][sb])) { frame->scale_factor[ch][sb]++; @@ -999,22 +947,23 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) u_int32_t scalefactor_j[2]; uint8_t scale_factor_j[2]; + uint8_t joint = 0; frame->joint = 0; for (sb = 0; sb < frame->subbands - 1; sb++) { scale_factor_j[0] = 0; - scalefactor_j[0] = 2; + scalefactor_j[0] = 2 << SCALE_OUT_BITS; scale_factor_j[1] = 0; - scalefactor_j[1] = 2; + scalefactor_j[1] = 2 << SCALE_OUT_BITS; for (blk = 0; blk < frame->blocks; blk++) { /* Calculate joint stereo signal */ sb_sample_j[blk][0] = - (frame->sb_sample_f[blk][0][sb] + - frame->sb_sample_f[blk][1][sb]) >> 1; + ASR(frame->sb_sample_f[blk][0][sb], 1) + + ASR(frame->sb_sample_f[blk][1][sb], 1); sb_sample_j[blk][1] = - (frame->sb_sample_f[blk][0][sb] - - frame->sb_sample_f[blk][1][sb]) >> 1; + ASR(frame->sb_sample_f[blk][0][sb], 1) - + ASR(frame->sb_sample_f[blk][1][sb], 1); /* calculate scale_factor_j and scalefactor_j for joint case */ while (scalefactor_j[0] < fabs(sb_sample_j[blk][0])) { @@ -1028,14 +977,15 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) } /* decide whether to join this subband */ - if ((scalefactor[0][sb] + scalefactor[1][sb]) > - (scalefactor_j[0] + scalefactor_j[1]) ) { + if ((frame->scale_factor[0][sb] + + frame->scale_factor[1][sb]) > + (scale_factor_j[0] + + scale_factor_j[1])) { /* use joint stereo for this subband */ + joint |= 1 << (frame->subbands - 1 - sb); frame->joint |= 1 << sb; frame->scale_factor[0][sb] = scale_factor_j[0]; frame->scale_factor[1][sb] = scale_factor_j[1]; - scalefactor[0][sb] = scalefactor_j[0]; - scalefactor[1][sb] = scalefactor_j[1]; for (blk = 0; blk < frame->blocks; blk++) { frame->sb_sample_f[blk][0][sb] = sb_sample_j[blk][0]; @@ -1045,24 +995,16 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) } } - data[4] = 0; - for (sb = 0; sb < frame->subbands - 1; sb++) - data[4] |= ((frame->joint >> sb) & 0x01) << (frame->subbands - 1 - sb); - - crc_header[crc_pos >> 3] = data[4]; - - produced += frame->subbands; + PUT_BITS(joint, frame->subbands); + crc_header[crc_pos >> 3] = joint; crc_pos += frame->subbands; } for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) { - data[produced >> 3] <<= 4; + PUT_BITS(frame->scale_factor[ch][sb] & 0x0F, 4); crc_header[crc_pos >> 3] <<= 4; - data[produced >> 3] |= frame->scale_factor[ch][sb] & 0x0F; crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F; - - produced += 4; crc_pos += 4; } } @@ -1076,37 +1018,47 @@ static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len) sbc_calculate_bits(frame, bits); for (ch = 0; ch < frame->channels; ch++) { - for (sb = 0; sb < frame->subbands; sb++) - levels[ch][sb] = (1 << bits[ch][sb]) - 1; + for (sb = 0; sb < frame->subbands; sb++) { + levels[ch][sb] = ((1 << bits[ch][sb]) - 1) << + (32 - (frame->scale_factor[ch][sb] + + SCALE_OUT_BITS + 2)); + sb_sample_delta[ch][sb] = (uint32_t) 1 << + (frame->scale_factor[ch][sb] + + SCALE_OUT_BITS + 1); + } } for (blk = 0; blk < frame->blocks; blk++) { for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) { - if (levels[ch][sb] > 0) { - audio_sample = - (uint16_t) ((((frame->sb_sample_f[blk][ch][sb]*levels[ch][sb]) >> - (frame->scale_factor[ch][sb] + 1)) + - levels[ch][sb]) >> 1); - audio_sample <<= 16 - bits[ch][sb]; - for (bit = 0; bit < bits[ch][sb]; bit++) { - data[produced >> 3] <<= 1; - if (audio_sample & 0x8000) - data[produced >> 3] |= 0x1; - audio_sample <<= 1; - produced++; - } - } + + if (bits[ch][sb] == 0) + continue; + + audio_sample = ((uint64_t) levels[ch][sb] * + (sb_sample_delta[ch][sb] + + frame->sb_sample_f[blk][ch][sb])) >> 32; + + PUT_BITS(audio_sample, bits[ch][sb]); } } } - /* align the last byte */ - if (produced % 8) { - data[produced >> 3] <<= 8 - (produced % 8); - } + FLUSH_BITS(); + + return data_ptr - data; +} + +static void sbc_encoder_init(struct sbc_encoder_state *state, + const struct sbc_frame *frame) +{ + memset(&state->X, 0, sizeof(state->X)); + state->subbands = frame->subbands; + state->position[0] = state->position[1] = 12 * frame->subbands; - return (produced + 7) >> 3; + /* Default implementation for analyze function */ + state->sbc_analyze_4b_4s = sbc_analyze_4b_4s; + state->sbc_analyze_4b_8s = sbc_analyze_4b_8s; } struct sbc_priv { @@ -1190,6 +1142,9 @@ int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output, if (written) *written = 0; + if (framelen <= 0) + return framelen; + samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame); ptr = output; @@ -1202,13 +1157,7 @@ int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output, int16_t s; s = priv->frame.pcm_sample[ch][i]; -#if __BYTE_ORDER == __LITTLE_ENDIAN if (sbc->endian == SBC_BE) { -#elif __BYTE_ORDER == __BIG_ENDIAN - if (sbc->endian == SBC_LE) { -#else -#error "Unknown byte order" -#endif *ptr++ = (s & 0xff00) >> 8; *ptr++ = (s & 0x00ff); } else { @@ -1269,13 +1218,7 @@ int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output, for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++) { for (ch = 0; ch < priv->frame.channels; ch++) { int16_t s; -#if __BYTE_ORDER == __LITTLE_ENDIAN if (sbc->endian == SBC_BE) -#elif __BYTE_ORDER == __BIG_ENDIAN - if (sbc->endian == SBC_LE) -#else -#error "Unknown byte order" -#endif s = (ptr[0] & 0xff) << 8 | (ptr[1] & 0xff); else s = (ptr[0] & 0xff) | (ptr[1] & 0xff) << 8; @@ -1374,9 +1317,9 @@ int sbc_get_frame_duration(sbc_t *sbc) return (1000000 * blocks * subbands) / frequency; } -int sbc_get_codesize(sbc_t *sbc) +uint16_t sbc_get_codesize(sbc_t *sbc) { - uint8_t subbands, channels, blocks; + uint16_t subbands, channels, blocks; struct sbc_priv *priv; priv = sbc->priv; diff --git a/src/modules/bluetooth/sbc.h b/src/modules/bluetooth/sbc.h index ab47e329..8ac59309 100644 --- a/src/modules/bluetooth/sbc.h +++ b/src/modules/bluetooth/sbc.h @@ -2,7 +2,7 @@ * * Bluetooth low-complexity, subband codec (SBC) library * - * Copyright (C) 2004-2008 Marcel Holtmann + * Copyright (C) 2004-2009 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * @@ -87,7 +87,7 @@ int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output, int output_len, int *written); int sbc_get_frame_length(sbc_t *sbc); int sbc_get_frame_duration(sbc_t *sbc); -int sbc_get_codesize(sbc_t *sbc); +uint16_t sbc_get_codesize(sbc_t *sbc); void sbc_finish(sbc_t *sbc); #ifdef __cplusplus diff --git a/src/modules/bluetooth/sbc_math.h b/src/modules/bluetooth/sbc_math.h index b3d87a62..6ca4f526 100644 --- a/src/modules/bluetooth/sbc_math.h +++ b/src/modules/bluetooth/sbc_math.h @@ -2,7 +2,7 @@ * * Bluetooth low-complexity, subband codec (SBC) library * - * Copyright (C) 2004-2008 Marcel Holtmann + * Copyright (C) 2004-2009 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2008 Brad Midgley * @@ -29,31 +29,21 @@ #define ASR(val, bits) ((-2 >> 1 == -1) ? \ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits))) -#define SCALE_PROTO4_TBL 15 -#define SCALE_ANA4_TBL 17 -#define SCALE_PROTO8_TBL 16 -#define SCALE_ANA8_TBL 17 +#define SCALE_OUT_BITS 15 + #define SCALE_SPROTO4_TBL 12 #define SCALE_SPROTO8_TBL 14 #define SCALE_NPROTO4_TBL 11 #define SCALE_NPROTO8_TBL 11 -#define SCALE4_STAGE1_BITS 15 -#define SCALE4_STAGE2_BITS 16 #define SCALE4_STAGED1_BITS 15 #define SCALE4_STAGED2_BITS 16 -#define SCALE8_STAGE1_BITS 15 -#define SCALE8_STAGE2_BITS 15 #define SCALE8_STAGED1_BITS 15 #define SCALE8_STAGED2_BITS 16 typedef int32_t sbc_fixed_t; -#define SCALE4_STAGE1(src) ASR(src, SCALE4_STAGE1_BITS) -#define SCALE4_STAGE2(src) ASR(src, SCALE4_STAGE2_BITS) #define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS) #define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS) -#define SCALE8_STAGE1(src) ASR(src, SCALE8_STAGE1_BITS) -#define SCALE8_STAGE2(src) ASR(src, SCALE8_STAGE2_BITS) #define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS) #define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS) diff --git a/src/modules/bluetooth/sbc_tables.h b/src/modules/bluetooth/sbc_tables.h index 7ac4e68b..f1dfe6c0 100644 --- a/src/modules/bluetooth/sbc_tables.h +++ b/src/modules/bluetooth/sbc_tables.h @@ -2,7 +2,7 @@ * * Bluetooth low-complexity, subband codec (SBC) library * - * Copyright (C) 2004-2008 Marcel Holtmann + * Copyright (C) 2004-2009 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * @@ -39,40 +39,12 @@ static const int sbc_offset8[4][8] = { { -4, 0, 0, 0, 0, 0, 1, 2 } }; -#define SP4(val) ASR(val, SCALE_PROTO4_TBL) -#define SA4(val) ASR(val, SCALE_ANA4_TBL) -#define SP8(val) ASR(val, SCALE_PROTO8_TBL) -#define SA8(val) ASR(val, SCALE_ANA8_TBL) + #define SS4(val) ASR(val, SCALE_SPROTO4_TBL) #define SS8(val) ASR(val, SCALE_SPROTO8_TBL) #define SN4(val) ASR(val, SCALE_NPROTO4_TBL) #define SN8(val) ASR(val, SCALE_NPROTO8_TBL) -static const int32_t _sbc_proto_4[20] = { - SP4(0x02cb3e8c), SP4(0x22b63dc0), SP4(0x002329cc), SP4(0x053b7548), - SP4(0x31eab940), SP4(0xec1f5e60), SP4(0xff3773a8), SP4(0x0061c5a7), - SP4(0x07646680), SP4(0x3f239480), SP4(0xf89f23a8), SP4(0x007a4737), - SP4(0x00b32807), SP4(0x083ddc80), SP4(0x4825e480), SP4(0x0191e578), - SP4(0x00ff11ca), SP4(0x00fb7991), SP4(0x069fdc58), SP4(0x4b584000) -}; - -static const int32_t _anamatrix4[4] = { - SA4(0x2d413cc0), SA4(0x3b20d780), SA4(0x40000000), SA4(0x187de2a0) -}; - -static const int32_t _sbc_proto_8[40] = { - SP8(0x02e5cd20), SP8(0x22d0c200), SP8(0x006bfe27), SP8(0x07808930), - SP8(0x3f1c8800), SP8(0xf8810d70), SP8(0x002cfdc6), SP8(0x055acf28), - SP8(0x31f566c0), SP8(0xebfe57e0), SP8(0xff27c437), SP8(0x001485cc), - SP8(0x041c6e58), SP8(0x2a7cfa80), SP8(0xe4c4a240), SP8(0xfe359e4c), - SP8(0x0048b1f8), SP8(0x0686ce30), SP8(0x38eec5c0), SP8(0xf2a1b9f0), - SP8(0xffe8904a), SP8(0x0095698a), SP8(0x0824a480), SP8(0x443b3c00), - SP8(0xfd7badc8), SP8(0x00d3e2d9), SP8(0x00c183d2), SP8(0x084e1950), - SP8(0x4810d800), SP8(0x017f43fe), SP8(0x01056dd8), SP8(0x00e9cb9f), - SP8(0x07d7d090), SP8(0x4a708980), SP8(0x0488fae8), SP8(0x0113bd20), - SP8(0x0107b1a8), SP8(0x069fb3c0), SP8(0x4b3db200), SP8(0x00763f48) -}; - static const int32_t sbc_proto_4_40m0[] = { SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), @@ -115,11 +87,6 @@ static const int32_t sbc_proto_8_80m1[] = { SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) }; -static const int32_t _anamatrix8[8] = { - SA8(0x3b20d780), SA8(0x187de2a0), SA8(0x3ec52f80), SA8(0x3536cc40), - SA8(0x238e7680), SA8(0x0c7c5c20), SA8(0x2d413cc0), SA8(0x40000000) -}; - static const int32_t synmatrix4[8][4] = { { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, @@ -165,3 +132,216 @@ static const int32_t synmatrix8[16][8] = { { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } }; + +/* Uncomment the following line to enable high precision build of SBC encoder */ + +/* #define SBC_HIGH_PRECISION */ + +#ifdef SBC_HIGH_PRECISION +#define FIXED_A int64_t /* data type for fixed point accumulator */ +#define FIXED_T int32_t /* data type for fixed point constants */ +#define SBC_FIXED_EXTRA_BITS 16 +#else +#define FIXED_A int32_t /* data type for fixed point accumulator */ +#define FIXED_T int16_t /* data type for fixed point constants */ +#define SBC_FIXED_EXTRA_BITS 0 +#endif + +/* A2DP specification: Section 12.8 Tables + * + * Original values are premultiplied by 2 for better precision (that is the + * maximum which is possible without overflows) + * + * Note: in each block of 8 numbers sign was changed for elements 2 and 7 + * in order to compensate the same change applied to cos_table_fixed_4 + */ +#define SBC_PROTO_FIXED4_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) +#define F(x) (FIXED_A) ((x * 2) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +static const FIXED_T _sbc_proto_fixed4[40] = { + F(0.00000000E+00), F(5.36548976E-04), + -F(1.49188357E-03), F(2.73370904E-03), + F(3.83720193E-03), F(3.89205149E-03), + F(1.86581691E-03), F(3.06012286E-03), + + F(1.09137620E-02), F(2.04385087E-02), + -F(2.88757392E-02), F(3.21939290E-02), + F(2.58767811E-02), F(6.13245186E-03), + -F(2.88217274E-02), F(7.76463494E-02), + + F(1.35593274E-01), F(1.94987841E-01), + -F(2.46636662E-01), F(2.81828203E-01), + F(2.94315332E-01), F(2.81828203E-01), + F(2.46636662E-01), -F(1.94987841E-01), + + -F(1.35593274E-01), -F(7.76463494E-02), + F(2.88217274E-02), F(6.13245186E-03), + F(2.58767811E-02), F(3.21939290E-02), + F(2.88757392E-02), -F(2.04385087E-02), + + -F(1.09137620E-02), -F(3.06012286E-03), + -F(1.86581691E-03), F(3.89205149E-03), + F(3.83720193E-03), F(2.73370904E-03), + F(1.49188357E-03), -F(5.36548976E-04), +}; +#undef F + +/* + * To produce this cosine matrix in Octave: + * + * b = zeros(4, 8); + * for i = 0:3 + * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4)) + * endfor + * endfor; + * printf("%.10f, ", b'); + * + * Note: in each block of 8 numbers sign was changed for elements 2 and 7 + * + * Change of sign for element 2 allows to replace constant 1.0 (not + * representable in Q15 format) with -1.0 (fine with Q15). + * Changed sign for element 7 allows to have more similar constants + * and simplify subband filter function code. + */ +#define SBC_COS_TABLE_FIXED4_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) +#define F(x) (FIXED_A) ((x) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +static const FIXED_T cos_table_fixed_4[32] = { + F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), + F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), + + -F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324), + -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325), + + -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324), + -F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325), + + F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325), + F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324), +}; +#undef F + +/* A2DP specification: Section 12.8 Tables + * + * Original values are premultiplied by 4 for better precision (that is the + * maximum which is possible without overflows) + * + * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 + * in order to compensate the same change applied to cos_table_fixed_8 + */ +#define SBC_PROTO_FIXED8_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 2) +#define F(x) (FIXED_A) ((x * 4) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +static const FIXED_T _sbc_proto_fixed8[80] = { + F(0.00000000E+00), F(1.56575398E-04), + F(3.43256425E-04), F(5.54620202E-04), + -F(8.23919506E-04), F(1.13992507E-03), + F(1.47640169E-03), F(1.78371725E-03), + F(2.01182542E-03), F(2.10371989E-03), + F(1.99454554E-03), F(1.61656283E-03), + F(9.02154502E-04), F(1.78805361E-04), + F(1.64973098E-03), F(3.49717454E-03), + + F(5.65949473E-03), F(8.02941163E-03), + F(1.04584443E-02), F(1.27472335E-02), + -F(1.46525263E-02), F(1.59045603E-02), + F(1.62208471E-02), F(1.53184106E-02), + F(1.29371806E-02), F(8.85757540E-03), + F(2.92408442E-03), -F(4.91578024E-03), + -F(1.46404076E-02), F(2.61098752E-02), + F(3.90751381E-02), F(5.31873032E-02), + + F(6.79989431E-02), F(8.29847578E-02), + F(9.75753918E-02), F(1.11196689E-01), + -F(1.23264548E-01), F(1.33264415E-01), + F(1.40753505E-01), F(1.45389847E-01), + F(1.46955068E-01), F(1.45389847E-01), + F(1.40753505E-01), F(1.33264415E-01), + F(1.23264548E-01), -F(1.11196689E-01), + -F(9.75753918E-02), -F(8.29847578E-02), + + -F(6.79989431E-02), -F(5.31873032E-02), + -F(3.90751381E-02), -F(2.61098752E-02), + F(1.46404076E-02), -F(4.91578024E-03), + F(2.92408442E-03), F(8.85757540E-03), + F(1.29371806E-02), F(1.53184106E-02), + F(1.62208471E-02), F(1.59045603E-02), + F(1.46525263E-02), -F(1.27472335E-02), + -F(1.04584443E-02), -F(8.02941163E-03), + + -F(5.65949473E-03), -F(3.49717454E-03), + -F(1.64973098E-03), -F(1.78805361E-04), + -F(9.02154502E-04), F(1.61656283E-03), + F(1.99454554E-03), F(2.10371989E-03), + F(2.01182542E-03), F(1.78371725E-03), + F(1.47640169E-03), F(1.13992507E-03), + F(8.23919506E-04), -F(5.54620202E-04), + -F(3.43256425E-04), -F(1.56575398E-04), +}; +#undef F + +/* + * To produce this cosine matrix in Octave: + * + * b = zeros(8, 16); + * for i = 0:7 + * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8)) + * endfor endfor; + * printf("%.10f, ", b'); + * + * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 + * + * Change of sign for element 4 allows to replace constant 1.0 (not + * representable in Q15 format) with -1.0 (fine with Q15). + * Changed signs for elements 13, 14, 15 allow to have more similar constants + * and simplify subband filter function code. + */ +#define SBC_COS_TABLE_FIXED8_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) +#define F(x) (FIXED_A) ((x) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +static const FIXED_T cos_table_fixed_8[128] = { + F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), + -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), + F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), + F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330), + + -F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123), + -F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220), + -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330), + -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804), + + -F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330), + -F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804), + -F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123), + F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220), + + F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220), + -F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330), + F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804), + -F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123), + + F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220), + -F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330), + F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804), + F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123), + + -F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330), + -F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804), + -F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123), + -F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220), + + -F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123), + -F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220), + -F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330), + -F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804), + + F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804), + -F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123), + F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220), + -F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330), +}; +#undef F -- cgit