Home | History | Annotate | Download | only in common
      1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <errno.h>
      7 #include <sbc/sbc.h>
      8 #include <stdlib.h>
      9 
     10 #include "cras_sbc_codec.h"
     11 
     12 /* SBC library encodes one PCM input block to one SBC output block. This
     13  * structure holds related info about the SBC codec.
     14  * Members:
     15  *    sbc - The main structure for SBC codec.
     16  *    codesize - The size of one PCM input block in bytes.
     17  *    frame_length - The size of one SBC output block in bytes.
     18  */
     19 struct cras_sbc_data {
     20 	sbc_t sbc;
     21 	unsigned int codesize;
     22 	unsigned int frame_length;
     23 };
     24 
     25 int cras_sbc_decode(struct cras_audio_codec *codec, const void *input,
     26 		    size_t input_len, void *output, size_t output_len,
     27 		    size_t *count) {
     28 	struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
     29 	size_t written;
     30 	ssize_t decoded;
     31 	int processed = 0;
     32 	int result = 0;
     33 
     34 	/* Proceed decode when there is buffer left in input and room in
     35 	 * output.
     36 	 */
     37 	while (input_len > processed && output_len > result) {
     38 		decoded = sbc_decode(&data->sbc,
     39 				     input + processed,
     40 				     input_len - processed,
     41 				     output + result,
     42 				     output_len - result,
     43 				     &written);
     44 		if (decoded <= 0)
     45 			break;
     46 
     47 		processed += decoded;
     48 		result += written;
     49 	}
     50 	*count = result;
     51 	return processed;
     52 }
     53 
     54 int cras_sbc_encode(struct cras_audio_codec *codec, const void *input,
     55 		    size_t input_len, void *output, size_t output_len,
     56 		    size_t *count) {
     57 	struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
     58 	ssize_t written, encoded;
     59 	int processed = 0, result = 0;
     60 
     61 	/* Proceed encode when input buffer has at least one input block and
     62 	 * there is still room in output buffer.
     63 	 */
     64 	while (input_len - processed >= data->codesize &&
     65 			output_len >= result) {
     66 		encoded = sbc_encode(&data->sbc,
     67 				     input + processed,
     68 				     data->codesize,
     69 				     output + result,
     70 				     output_len - result,
     71 				     &written);
     72 		if (encoded == -ENOSPC)
     73 			break;
     74 		else if (encoded < 0)
     75 			return encoded;
     76 
     77 		processed += encoded;
     78 		result += written;
     79 	}
     80 	*count = result;
     81 	return processed;
     82 }
     83 
     84 int cras_sbc_get_codesize(struct cras_audio_codec *codec)
     85 {
     86 	struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
     87 	return data->codesize;
     88 }
     89 
     90 int cras_sbc_get_frame_length(struct cras_audio_codec *codec)
     91 {
     92 	struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
     93 	return data->frame_length;
     94 }
     95 
     96 struct cras_audio_codec *cras_sbc_codec_create(uint8_t freq,
     97 		   uint8_t mode, uint8_t subbands, uint8_t alloc,
     98 		   uint8_t blocks, uint8_t bitpool) {
     99 	struct cras_audio_codec *codec;
    100 	struct cras_sbc_data *data;
    101 
    102 	codec = (struct cras_audio_codec *)calloc(1, sizeof(*codec));
    103 	if (!codec)
    104 		return NULL;
    105 
    106 	codec->priv_data = (struct cras_sbc_data *)calloc(1,
    107 			sizeof(struct cras_sbc_data));
    108 	if (!codec->priv_data)
    109 		goto create_error;
    110 
    111 	data = (struct cras_sbc_data *)codec->priv_data;
    112 	sbc_init(&data->sbc, 0L);
    113 	data->sbc.endian = SBC_LE;
    114 	data->sbc.frequency = freq;
    115 	data->sbc.mode = mode;
    116 	data->sbc.subbands = subbands;
    117 	data->sbc.allocation = alloc;
    118 	data->sbc.blocks = blocks;
    119 	data->sbc.bitpool = bitpool;
    120 	data->codesize = sbc_get_codesize(&data->sbc);
    121 	data->frame_length = sbc_get_frame_length(&data->sbc);
    122 
    123 	codec->decode = cras_sbc_decode;
    124 	codec->encode = cras_sbc_encode;
    125 	return codec;
    126 
    127 create_error:
    128 	free(codec);
    129 	return NULL;
    130 }
    131 
    132 void cras_sbc_codec_destroy(struct cras_audio_codec *codec)
    133 {
    134 	sbc_finish(&((struct cras_sbc_data *)codec->priv_data)->sbc);
    135 	free(codec->priv_data);
    136 	free(codec);
    137 }
    138