blob: df02b3ebaf321c751d55360b9a26ff640392af47 [file] [log] [blame]
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <errno.h>
#include <sbc/sbc.h>
#include <stdlib.h>
#include "cras_sbc_codec.h"
/* SBC library encodes one PCM input block to one SBC output block. This
* structure holds related info about the SBC codec.
* Members:
* sbc - The main structure for SBC codec.
* codesize - The size of one PCM input block in bytes.
* frame_length - The size of one SBC output block in bytes.
*/
struct cras_sbc_data {
sbc_t sbc;
unsigned int codesize;
unsigned int frame_length;
};
int cras_msbc_decode(struct cras_audio_codec *codec, const void *input,
size_t input_len, void *output, size_t output_len,
size_t *count)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
size_t written = 0;
ssize_t decoded;
/*
* Proceed decode when there is buffer left in input and room in
* output.
*/
decoded = sbc_decode(&data->sbc, input, input_len, output, output_len,
&written);
*count = written;
return decoded;
}
int cras_msbc_encode(struct cras_audio_codec *codec, const void *input,
size_t input_len, void *output, size_t output_len,
size_t *count)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
ssize_t written = 0;
ssize_t encoded;
/*
* Proceed encode when input buffer has at least one input block and
* there is still room in output buffer.
*/
if (input_len < data->codesize)
return -EINVAL;
encoded = sbc_encode(&data->sbc, input, data->codesize, output,
output_len, &written);
*count = written;
return encoded;
}
int cras_sbc_decode(struct cras_audio_codec *codec, const void *input,
size_t input_len, void *output, size_t output_len,
size_t *count)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
size_t written;
ssize_t decoded;
int processed = 0;
int result = 0;
/* Proceed decode when there is buffer left in input and room in
* output.
*/
while (input_len > processed && output_len > result) {
decoded = sbc_decode(&data->sbc, input + processed,
input_len - processed, output + result,
output_len - result, &written);
if (decoded <= 0)
break;
processed += decoded;
result += written;
}
*count = result;
return processed;
}
int cras_sbc_encode(struct cras_audio_codec *codec, const void *input,
size_t input_len, void *output, size_t output_len,
size_t *count)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
ssize_t written, encoded;
int processed = 0, result = 0;
/* Proceed encode when input buffer has at least one input block and
* there is still room in output buffer.
*/
while (input_len - processed >= data->codesize &&
output_len >= result) {
encoded = sbc_encode(&data->sbc, input + processed,
data->codesize, output + result,
output_len - result, &written);
if (encoded == -ENOSPC)
break;
else if (encoded < 0)
return encoded;
processed += encoded;
result += written;
}
*count = result;
return processed;
}
int cras_sbc_get_codesize(struct cras_audio_codec *codec)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
return data->codesize;
}
int cras_sbc_get_frame_length(struct cras_audio_codec *codec)
{
struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
return data->frame_length;
}
struct cras_audio_codec *cras_msbc_codec_create()
{
struct cras_audio_codec *codec;
struct cras_sbc_data *data;
codec = (struct cras_audio_codec *)calloc(1, sizeof(*codec));
if (!codec)
return NULL;
codec->priv_data =
(struct cras_sbc_data *)calloc(1, sizeof(struct cras_sbc_data));
if (!codec->priv_data) {
free(codec);
return NULL;
}
data = (struct cras_sbc_data *)codec->priv_data;
sbc_init_msbc(&data->sbc, 0L);
data->codesize = sbc_get_codesize(&data->sbc);
data->frame_length = sbc_get_frame_length(&data->sbc);
codec->decode = cras_msbc_decode;
codec->encode = cras_msbc_encode;
return codec;
}
struct cras_audio_codec *cras_sbc_codec_create(uint8_t freq, uint8_t mode,
uint8_t subbands, uint8_t alloc,
uint8_t blocks, uint8_t bitpool)
{
struct cras_audio_codec *codec;
struct cras_sbc_data *data;
codec = (struct cras_audio_codec *)calloc(1, sizeof(*codec));
if (!codec)
return NULL;
codec->priv_data =
(struct cras_sbc_data *)calloc(1, sizeof(struct cras_sbc_data));
if (!codec->priv_data)
goto create_error;
data = (struct cras_sbc_data *)codec->priv_data;
sbc_init(&data->sbc, 0L);
data->sbc.endian = SBC_LE;
data->sbc.frequency = freq;
data->sbc.mode = mode;
data->sbc.subbands = subbands;
data->sbc.allocation = alloc;
data->sbc.blocks = blocks;
data->sbc.bitpool = bitpool;
data->codesize = sbc_get_codesize(&data->sbc);
data->frame_length = sbc_get_frame_length(&data->sbc);
codec->decode = cras_sbc_decode;
codec->encode = cras_sbc_encode;
return codec;
create_error:
free(codec);
return NULL;
}
void cras_sbc_codec_destroy(struct cras_audio_codec *codec)
{
sbc_finish(&((struct cras_sbc_data *)codec->priv_data)->sbc);
free(codec->priv_data);
free(codec);
}