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
cras_sbc_decode(struct cras_audio_codec * codec,const void * input,size_t input_len,void * output,size_t output_len,size_t * count)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
cras_sbc_encode(struct cras_audio_codec * codec,const void * input,size_t input_len,void * output,size_t output_len,size_t * count)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
cras_sbc_get_codesize(struct cras_audio_codec * codec)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
cras_sbc_get_frame_length(struct cras_audio_codec * codec)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
cras_sbc_codec_create(uint8_t freq,uint8_t mode,uint8_t subbands,uint8_t alloc,uint8_t blocks,uint8_t bitpool)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
cras_sbc_codec_destroy(struct cras_audio_codec * codec)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