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