• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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