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_msbc_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_msbc_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 {
29 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
30 size_t written = 0;
31 ssize_t decoded;
32
33 /*
34 * Proceed decode when there is buffer left in input and room in
35 * output.
36 */
37 decoded = sbc_decode(&data->sbc, input, input_len, output, output_len,
38 &written);
39
40 *count = written;
41 return decoded;
42 }
43
cras_msbc_encode(struct cras_audio_codec * codec,const void * input,size_t input_len,void * output,size_t output_len,size_t * count)44 int cras_msbc_encode(struct cras_audio_codec *codec, const void *input,
45 size_t input_len, void *output, size_t output_len,
46 size_t *count)
47 {
48 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
49 ssize_t written = 0;
50 ssize_t encoded;
51
52 /*
53 * Proceed encode when input buffer has at least one input block and
54 * there is still room in output buffer.
55 */
56 if (input_len < data->codesize)
57 return -EINVAL;
58
59 encoded = sbc_encode(&data->sbc, input, data->codesize, output,
60 output_len, &written);
61
62 *count = written;
63 return encoded;
64 }
65
cras_sbc_decode(struct cras_audio_codec * codec,const void * input,size_t input_len,void * output,size_t output_len,size_t * count)66 int cras_sbc_decode(struct cras_audio_codec *codec, const void *input,
67 size_t input_len, void *output, size_t output_len,
68 size_t *count)
69 {
70 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
71 size_t written;
72 ssize_t decoded;
73 int processed = 0;
74 int result = 0;
75
76 /* Proceed decode when there is buffer left in input and room in
77 * output.
78 */
79 while (input_len > processed && output_len > result) {
80 decoded = sbc_decode(&data->sbc, input + processed,
81 input_len - processed, output + result,
82 output_len - result, &written);
83 if (decoded <= 0)
84 break;
85
86 processed += decoded;
87 result += written;
88 }
89 *count = result;
90 return processed;
91 }
92
cras_sbc_encode(struct cras_audio_codec * codec,const void * input,size_t input_len,void * output,size_t output_len,size_t * count)93 int cras_sbc_encode(struct cras_audio_codec *codec, const void *input,
94 size_t input_len, void *output, size_t output_len,
95 size_t *count)
96 {
97 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
98 ssize_t written, encoded;
99 int processed = 0, result = 0;
100
101 /* Proceed encode when input buffer has at least one input block and
102 * there is still room in output buffer.
103 */
104 while (input_len - processed >= data->codesize &&
105 output_len >= result) {
106 encoded = sbc_encode(&data->sbc, input + processed,
107 data->codesize, output + result,
108 output_len - result, &written);
109 if (encoded == -ENOSPC)
110 break;
111 else if (encoded < 0)
112 return encoded;
113
114 processed += encoded;
115 result += written;
116 }
117 *count = result;
118 return processed;
119 }
120
cras_sbc_get_codesize(struct cras_audio_codec * codec)121 int cras_sbc_get_codesize(struct cras_audio_codec *codec)
122 {
123 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
124 return data->codesize;
125 }
126
cras_sbc_get_frame_length(struct cras_audio_codec * codec)127 int cras_sbc_get_frame_length(struct cras_audio_codec *codec)
128 {
129 struct cras_sbc_data *data = (struct cras_sbc_data *)codec->priv_data;
130 return data->frame_length;
131 }
132
cras_msbc_codec_create()133 struct cras_audio_codec *cras_msbc_codec_create()
134 {
135 struct cras_audio_codec *codec;
136 struct cras_sbc_data *data;
137
138 codec = (struct cras_audio_codec *)calloc(1, sizeof(*codec));
139 if (!codec)
140 return NULL;
141
142 codec->priv_data =
143 (struct cras_sbc_data *)calloc(1, sizeof(struct cras_sbc_data));
144 if (!codec->priv_data) {
145 free(codec);
146 return NULL;
147 }
148
149 data = (struct cras_sbc_data *)codec->priv_data;
150 sbc_init_msbc(&data->sbc, 0L);
151 data->codesize = sbc_get_codesize(&data->sbc);
152 data->frame_length = sbc_get_frame_length(&data->sbc);
153
154 codec->decode = cras_msbc_decode;
155 codec->encode = cras_msbc_encode;
156 return codec;
157 }
158
cras_sbc_codec_create(uint8_t freq,uint8_t mode,uint8_t subbands,uint8_t alloc,uint8_t blocks,uint8_t bitpool)159 struct cras_audio_codec *cras_sbc_codec_create(uint8_t freq, uint8_t mode,
160 uint8_t subbands, uint8_t alloc,
161 uint8_t blocks, uint8_t bitpool)
162 {
163 struct cras_audio_codec *codec;
164 struct cras_sbc_data *data;
165
166 codec = (struct cras_audio_codec *)calloc(1, sizeof(*codec));
167 if (!codec)
168 return NULL;
169
170 codec->priv_data =
171 (struct cras_sbc_data *)calloc(1, sizeof(struct cras_sbc_data));
172 if (!codec->priv_data)
173 goto create_error;
174
175 data = (struct cras_sbc_data *)codec->priv_data;
176 sbc_init(&data->sbc, 0L);
177 data->sbc.endian = SBC_LE;
178 data->sbc.frequency = freq;
179 data->sbc.mode = mode;
180 data->sbc.subbands = subbands;
181 data->sbc.allocation = alloc;
182 data->sbc.blocks = blocks;
183 data->sbc.bitpool = bitpool;
184 data->codesize = sbc_get_codesize(&data->sbc);
185 data->frame_length = sbc_get_frame_length(&data->sbc);
186
187 codec->decode = cras_sbc_decode;
188 codec->encode = cras_sbc_encode;
189 return codec;
190
191 create_error:
192 free(codec);
193 return NULL;
194 }
195
cras_sbc_codec_destroy(struct cras_audio_codec * codec)196 void cras_sbc_codec_destroy(struct cras_audio_codec *codec)
197 {
198 sbc_finish(&((struct cras_sbc_data *)codec->priv_data)->sbc);
199 free(codec->priv_data);
200 free(codec);
201 }
202