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