mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-07 13:30:03 -05:00
Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
This commit is contained in:
commit
c2002dcd1f
31 changed files with 13676 additions and 1766 deletions
|
|
@ -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 (fallback) {
|
||||
snd_mixer_selem_id_set_name(sid, fallback);
|
||||
if (elem_has_volume(elem, playback) &&
|
||||
elem_has_switch(elem, playback))
|
||||
goto success;
|
||||
|
||||
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) &&
|
||||
!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) {
|
||||
|
||||
/* Hmm, so we have both elements, but neither has both mute
|
||||
* and volume. Let's prefer the one with the volume */
|
||||
|
||||
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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 < 0 || (size_t) type > (sizeof(strmsg) / sizeof(strmsg[0])))
|
||||
if (type >= ARRAY_SIZE(strtypes))
|
||||
return NULL;
|
||||
|
||||
return strmsg[type];
|
||||
return strtypes[type];
|
||||
}
|
||||
|
||||
const char *bt_audio_strname(uint8_t name)
|
||||
{
|
||||
if (name >= ARRAY_SIZE(strnames))
|
||||
return NULL;
|
||||
|
||||
return strnames[name];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
<Moves to streaming state>
|
||||
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
|
||||
|
||||
<Moves to open state>
|
||||
BT_STREAMSTOP_RSP-->
|
||||
BT_STOP_STREAM_RSP-->
|
||||
|
||||
on IPC close or appl crash
|
||||
on IPC close or appl crash
|
||||
<Moves to idle>
|
||||
|
||||
*/
|
||||
|
|
@ -71,43 +71,36 @@ extern "C" {
|
|||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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;
|
||||
bt_audio_msg_header_t h;
|
||||
uint8_t posix_errno;
|
||||
} __attribute__ ((packed)) bt_audio_error_t;
|
||||
|
||||
/* Messages list */
|
||||
#define BT_GETCAPABILITIES_REQ 0
|
||||
#define BT_GETCAPABILITIES_RSP 1
|
||||
/* Message types */
|
||||
#define BT_REQUEST 0
|
||||
#define BT_RESPONSE 1
|
||||
#define BT_INDICATION 2
|
||||
#define BT_ERROR 3
|
||||
|
||||
#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 */
|
||||
/* 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,74 +192,64 @@ 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 */
|
||||
} __attribute__ ((packed));
|
||||
typedef struct {
|
||||
codec_capabilities_t capability;
|
||||
uint8_t flags;
|
||||
uint16_t sampling_rate;
|
||||
} __attribute__ ((packed)) pcm_capabilities_t;
|
||||
|
||||
/* BT_SETCONFIGURATION_REQ */
|
||||
struct bt_setconfiguration_req {
|
||||
|
||||
struct bt_get_capabilities_rsp {
|
||||
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 */
|
||||
uint8_t data[0]; /* First codec_capabilities_t */
|
||||
} __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_req {
|
||||
bt_audio_msg_header_t h;
|
||||
char device[18]; /* Address of the remote Device */
|
||||
uint8_t access_mode; /* Requested access mode */
|
||||
codec_capabilities_t codec; /* Requested codec */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
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;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* BT_STREAMSUSPEND_IND */
|
||||
struct bt_streamsuspend_ind {
|
||||
struct bt_stop_stream_rsp {
|
||||
bt_audio_msg_header_t h;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* BT_STREAMRESUME_IND */
|
||||
struct bt_streamresume_ind {
|
||||
struct bt_suspend_stream_ind {
|
||||
bt_audio_msg_header_t h;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* BT_CONTROL_REQ */
|
||||
struct bt_resume_stream_ind {
|
||||
bt_audio_msg_header_t h;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define BT_CONTROL_KEY_POWER 0x40
|
||||
#define BT_CONTROL_KEY_VOL_UP 0x41
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,14 @@ 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;
|
||||
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, length, 0) > 0)
|
||||
e = 0;
|
||||
else {
|
||||
e = -errno;
|
||||
|
|
@ -132,20 +138,25 @@ 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;
|
||||
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, 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, length, 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 +167,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 +244,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 +434,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 +451,19 @@ 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;
|
||||
if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
|
||||
msg.setconf_req.sbc_capabilities = u->a2dp.sbc_capabilities;
|
||||
msg.setconf_req.codec.transport = u->transport;
|
||||
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);
|
||||
|
|
@ -424,17 +472,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 +499,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 +517,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;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Bluetooth low-complexity, subband codec (SBC) library
|
||||
*
|
||||
* Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
|
||||
* Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
|
||||
*
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
/* 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(const int32_t *in, int32_t *out)
|
||||
static void sbc_analyze_4b_4s(int16_t *pcm, int16_t *x,
|
||||
int32_t *out, int out_stride)
|
||||
{
|
||||
sbc_fixed_t t[8], s[5];
|
||||
int i;
|
||||
|
||||
t[0] = SCALE4_STAGE1( /* Q8 */
|
||||
MULA(_sbc_proto_4[0], in[8] - in[32], /* Q18 */
|
||||
MUL( _sbc_proto_4[1], in[16] - in[24])));
|
||||
/* 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];
|
||||
}
|
||||
|
||||
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]);
|
||||
/* 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_four(struct sbc_encoder_state *state,
|
||||
struct sbc_frame *frame, int ch, int blk)
|
||||
static inline void _sbc_analyze_eight(const int16_t *in, int32_t *out)
|
||||
{
|
||||
int32_t *x = &state->X[ch][state->position[ch]];
|
||||
int16_t *pcm = &frame->pcm_sample[ch][blk * 4];
|
||||
FIXED_A t1[8];
|
||||
FIXED_T t2[8];
|
||||
int i, hop;
|
||||
|
||||
/* 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];
|
||||
/* 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);
|
||||
|
||||
_sbc_analyze_four(x, frame->sb_sample_f[blk][ch]);
|
||||
/* 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];
|
||||
}
|
||||
|
||||
state->position[ch] -= 4;
|
||||
if (state->position[ch] < 0)
|
||||
state->position[ch] = 36;
|
||||
/* 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(const int32_t *in, int32_t *out)
|
||||
static void sbc_analyze_4b_8s(int16_t *pcm, int16_t *x,
|
||||
int32_t *out, int out_stride)
|
||||
{
|
||||
sbc_fixed_t t[8], s[8];
|
||||
int i;
|
||||
|
||||
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])))))));
|
||||
/* 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];
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
static inline void sbc_analyze_eight(struct sbc_encoder_state *state,
|
||||
struct sbc_frame *frame, int ch,
|
||||
int blk)
|
||||
{
|
||||
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;
|
||||
/* 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 (produced + 7) >> 3;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Bluetooth low-complexity, subband codec (SBC) library
|
||||
*
|
||||
* Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
|
||||
* Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
|
||||
*
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Bluetooth low-complexity, subband codec (SBC) library
|
||||
*
|
||||
* Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
|
||||
* Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
|
||||
*
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Bluetooth low-complexity, subband codec (SBC) library
|
||||
*
|
||||
* Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
|
||||
* Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
|
||||
*
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue