Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ config FORMAT_U8
help
Support unsigned 8 bit processing data format

config FORMAT_A_LAW
bool "Support A-law"
help
Support 8 bit A-law processing data format.

config FORMAT_MU_LAW
bool "Support mu-law"
help
Support 8 bit mu-law processing data format.

config FORMAT_S16LE
bool "Support S16LE"
default y
Expand Down Expand Up @@ -228,6 +238,18 @@ config PCM_CONVERTER_FORMAT_U8
help
Support 8 bit processing data format without sign

config PCM_CONVERTER_FORMAT_A_LAW
bool "Support A-law"
select MATH_A_LAW_CODEC
help
Support 8 bit A-law data format.

config PCM_CONVERTER_FORMAT_MU_LAW
bool "Support mu-law"
select MATH_MU_LAW_CODEC
help
Support 8 bit mu-law data format.

config PCM_CONVERTER_FORMAT_S16LE
bool "Support S16LE"
default y
Expand Down
31 changes: 22 additions & 9 deletions src/audio/copier/copier_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,28 @@ __cold int copier_host_create(struct comp_dev *dev, struct copier_data *cd,
config->type = SOF_COMP_HOST;
cd->gtw_type = ipc4_gtw_host;

audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth,
copier_cfg->base.audio_fmt.valid_bit_depth,
&in_frame_fmt, &in_valid_fmt,
copier_cfg->base.audio_fmt.s_type);

audio_stream_fmt_conversion(copier_cfg->out_fmt.depth,
copier_cfg->out_fmt.valid_bit_depth,
&out_frame_fmt, &out_valid_fmt,
copier_cfg->out_fmt.s_type);
ret = audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth,
copier_cfg->base.audio_fmt.valid_bit_depth,
&in_frame_fmt, &in_valid_fmt,
copier_cfg->base.audio_fmt.s_type);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a notification to the host in case of such errors? We have them now, but should be rate-limited...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to do it, but I think already this is a large improvement to previous. But I added SOF_IPC_FRAME_INVALID as default for this function. Then functions those do not handle the return value (a lot of them, and also void functions themselves) will fail with formats those can't be supported.

if (ret) {
comp_err(dev, "failed with input format: depth %d, valid %d, type %d",
copier_cfg->base.audio_fmt.depth,
copier_cfg->base.audio_fmt.valid_bit_depth,
copier_cfg->base.audio_fmt.s_type);
return ret;
}

ret = audio_stream_fmt_conversion(copier_cfg->out_fmt.depth,
copier_cfg->out_fmt.valid_bit_depth,
&out_frame_fmt, &out_valid_fmt,
copier_cfg->out_fmt.s_type);
if (ret) {
comp_err(dev, "failed with output format: depth %d, valid %d, type %d",
copier_cfg->out_fmt.depth, copier_cfg->out_fmt.valid_bit_depth,
copier_cfg->out_fmt.s_type);
return ret;
}

memset(&ipc_host, 0, sizeof(ipc_host));
ipc_host.direction = dir;
Expand Down
136 changes: 136 additions & 0 deletions src/audio/pcm_converter/pcm_converter_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

#include <sof/audio/buffer.h>
#include <sof/audio/format.h>
#include <sof/math/a_law.h>
#include <sof/math/mu_law.h>
#include <rtos/bit.h>
#include <sof/common.h>
#include <sof/compiler_attributes.h>
Expand Down Expand Up @@ -93,6 +95,126 @@ static int pcm_convert_s32_to_u8(const struct audio_stream *source,
}
#endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */

#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE
static int pcm_convert_alaw_to_s32(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples, uint32_t chmap)
{
const uint8_t *src = audio_stream_get_rptr(source);
int32_t *dst = audio_stream_get_wptr(sink);
uint32_t processed;
uint32_t nmax, i, n;

src += ioffset;
dst += ooffset;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, (void *)src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sofm_a_law_decode(*src) << 16;
src++;
dst++;
}
}

return samples;
}

static int pcm_convert_s32_to_alaw(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples, uint32_t chmap)
{
const int32_t *src = audio_stream_get_rptr(source);
uint8_t *dst = audio_stream_get_wptr(sink);
uint32_t processed;
uint32_t nmax, i, n;

src += ioffset;
dst += ooffset;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, (void *)src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sofm_a_law_encode(*src >> 16);
src++;
dst++;
}
}

return samples;
}
#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */

#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE
static int pcm_convert_mulaw_to_s32(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples, uint32_t chmap)
{
const uint8_t *src = audio_stream_get_rptr(source);
int32_t *dst = audio_stream_get_wptr(sink);
uint32_t processed;
uint32_t nmax, i, n;

src += ioffset;
dst += ooffset;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, (void *)src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sofm_mu_law_decode(*src) << 16;
src++;
dst++;
}
}

return samples;
}

static int pcm_convert_s32_to_mulaw(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples, uint32_t chmap)
{
const int32_t *src = audio_stream_get_rptr(source);
uint8_t *dst = audio_stream_get_wptr(sink);
uint32_t processed;
uint32_t nmax, i, n;

src += ioffset;
dst += ooffset;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, (void *)src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sofm_mu_law_encode(*src >> 16);
src++;
dst++;
}
}

return samples;
}
#endif /* CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */

#if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE

static int pcm_convert_s16_to_s24(const struct audio_stream *source,
Expand Down Expand Up @@ -555,6 +677,20 @@ const struct pcm_func_map pcm_func_map[] = {
{ SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S32_LE, pcm_convert_u8_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_U8, pcm_convert_s32_to_u8 },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */
#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW
{ SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_A_LAW, just_copy },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW */
#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE
{ SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_alaw_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_A_LAW, pcm_convert_s32_to_alaw },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */
#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW
{ SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_MU_LAW, just_copy },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_MU_LAW */
#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE
{ SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_mulaw_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_MU_LAW, pcm_convert_s32_to_mulaw },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */
#if CONFIG_PCM_CONVERTER_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */
Expand Down
4 changes: 4 additions & 0 deletions src/include/module/audio/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ static inline uint32_t get_sample_bytes(enum sof_ipc_frame fmt)
case SOF_IPC_FRAME_S24_3LE:
return 3;
case SOF_IPC_FRAME_U8:
case SOF_IPC_FRAME_A_LAW:
case SOF_IPC_FRAME_MU_LAW:
return 1;
default:
return 4;
Expand All @@ -37,6 +39,8 @@ static inline uint32_t get_sample_bitdepth(enum sof_ipc_frame fmt)
case SOF_IPC_FRAME_S24_3LE:
return 24;
case SOF_IPC_FRAME_U8:
case SOF_IPC_FRAME_A_LAW:
case SOF_IPC_FRAME_MU_LAW:
return 8;
default:
return 32;
Expand Down
5 changes: 4 additions & 1 deletion src/include/module/ipc/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ enum sof_ipc_frame {
SOF_IPC_FRAME_S24_3LE,
SOF_IPC_FRAME_S24_4LE_MSB,
SOF_IPC_FRAME_U8,
SOF_IPC_FRAME_S16_4LE /* 16-bit in 32-bit container */
SOF_IPC_FRAME_S16_4LE, /* 16-bit in 32-bit container */
SOF_IPC_FRAME_A_LAW,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to double check, is this in sync with Intel reference?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have an internal email thread started, should mark those as reserved there to avoid future conflict.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now agreed with the reference.

SOF_IPC_FRAME_MU_LAW,
SOF_IPC_FRAME_INVALID, /* keep last */
};

#endif /* __MODULE_IPC_STREAM_H__ */
4 changes: 3 additions & 1 deletion src/include/module/ipc4/base-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ enum ipc4_sample_type {
IPC4_TYPE_LSB_INTEGER = 1, /**< integer with Least Significant Byte first */
IPC4_TYPE_SIGNED_INTEGER = 2,
IPC4_TYPE_UNSIGNED_INTEGER = 3,
IPC4_TYPE_FLOAT = 4
IPC4_TYPE_FLOAT = 4,
IPC4_TYPE_A_LAW = 5,
IPC4_TYPE_MU_LAW = 6,
};

enum ipc4_stream_type {
Expand Down
88 changes: 61 additions & 27 deletions src/include/sof/audio/audio_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -1007,40 +1007,74 @@ static inline void cir_buf_set_zero(void *ptr, void *buf_addr, void *buf_end, ui
memset(buf_addr, 0, tail_size);
}

static inline void audio_stream_fmt_conversion(enum ipc4_bit_depth depth,
enum ipc4_bit_depth valid,
enum sof_ipc_frame *frame_fmt,
enum sof_ipc_frame *valid_fmt,
enum ipc4_sample_type type)
static inline int audio_stream_fmt_conversion(enum ipc4_bit_depth depth,
enum ipc4_bit_depth valid,
enum sof_ipc_frame *frame_fmt,
enum sof_ipc_frame *valid_fmt,
enum ipc4_sample_type type)
{
/* IPC4_DEPTH_16BIT (16) <---> SOF_IPC_FRAME_S16_LE (0)
* IPC4_DEPTH_24BIT (24) <---> SOF_IPC_FRAME_S24_4LE (1)
* IPC4_DEPTH_32BIT (32) <---> SOF_IPC_FRAME_S32_LE (2)
*/
*frame_fmt = (enum sof_ipc_frame)((depth >> 3) - 2);
*valid_fmt = (enum sof_ipc_frame)((valid >> 3) - 2);

#ifdef CONFIG_FORMAT_U8
if (depth == 8)
*frame_fmt = SOF_IPC_FRAME_U8;

if (valid == 8)
*valid_fmt = SOF_IPC_FRAME_U8;
#endif /* CONFIG_FORMAT_U8 */

if (valid == 24) {
int ret = -EINVAL;
*frame_fmt = SOF_IPC_FRAME_INVALID;
*valid_fmt = SOF_IPC_FRAME_INVALID;

switch (type) {
case IPC4_TYPE_FLOAT:
#ifdef CONFIG_FORMAT_FLOAT
if (depth == 32 && valid == 32) {
*frame_fmt = SOF_IPC_FRAME_FLOAT;
*valid_fmt = SOF_IPC_FRAME_FLOAT;
ret = 0;
}
#endif
break;
case IPC4_TYPE_MSB_INTEGER:
case IPC4_TYPE_LSB_INTEGER:
case IPC4_TYPE_SIGNED_INTEGER:
if (depth == 24 && valid == 24) {
#ifdef CONFIG_FORMAT_S24_3LE
if (depth == 24) {
*frame_fmt = SOF_IPC_FRAME_S24_3LE;
*valid_fmt = SOF_IPC_FRAME_S24_3LE;
ret = 0;
#endif
} else {
/* IPC4_DEPTH_16BIT (16) <---> SOF_IPC_FRAME_S16_LE (0)
* IPC4_DEPTH_24BIT (24) <---> SOF_IPC_FRAME_S24_4LE (1)
* IPC4_DEPTH_32BIT (32) <---> SOF_IPC_FRAME_S32_LE (2)
*/
*frame_fmt = (enum sof_ipc_frame)((depth >> 3) - 2);
*valid_fmt = (enum sof_ipc_frame)((valid >> 3) - 2);
ret = 0;
}
break;
case IPC4_TYPE_UNSIGNED_INTEGER:
#ifdef CONFIG_FORMAT_U8
if (depth == 8 && valid == 8) {
*frame_fmt = SOF_IPC_FRAME_U8;
*valid_fmt = SOF_IPC_FRAME_U8;
ret = 0;
}
#endif /* CONFIG_FORMAT_U8 */
break;
case IPC4_TYPE_A_LAW:
#ifdef CONFIG_FORMAT_A_LAW
if (depth == 8 && valid == 8) {
*frame_fmt = SOF_IPC_FRAME_A_LAW;
*valid_fmt = SOF_IPC_FRAME_A_LAW;
ret = 0;
}
#endif
break;
case IPC4_TYPE_MU_LAW:
#ifdef CONFIG_FORMAT_MU_LAW
if (depth == 8 && valid == 8) {
*frame_fmt = SOF_IPC_FRAME_MU_LAW;
*valid_fmt = SOF_IPC_FRAME_MU_LAW;
ret = 0;
}
#endif
break;
}

if (type == IPC4_TYPE_FLOAT && depth == 32) {
*frame_fmt = SOF_IPC_FRAME_FLOAT;
*valid_fmt = SOF_IPC_FRAME_FLOAT;
}
return ret;
}
/** @}*/

Expand Down
Loading
Loading