Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / android / hal-audio-aptx.c
1 /*
2  * Copyright (C) 2014 Tieto Poland
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <malloc.h>
22 #include <dlfcn.h>
23
24 #include "audio-msg.h"
25 #include "hal-audio.h"
26 #include "hal-log.h"
27 #include "profiles/audio/a2dp-codecs.h"
28
29 #define APTX_SO_NAME    "libbt-aptx.so"
30
31 struct aptx_data {
32         a2dp_aptx_t aptx;
33
34         void *enc;
35 };
36
37 static const a2dp_aptx_t aptx_presets[] = {
38         {
39                 .info = {
40                         .vendor_id = APTX_VENDOR_ID,
41                         .codec_id = APTX_CODEC_ID,
42                 },
43                 .frequency = APTX_SAMPLING_FREQ_44100 |
44                                                 APTX_SAMPLING_FREQ_48000,
45                 .channel_mode = APTX_CHANNEL_MODE_STEREO,
46         },
47         {
48                 .info = {
49                         .vendor_id = APTX_VENDOR_ID,
50                         .codec_id = APTX_CODEC_ID,
51                 },
52                 .frequency = APTX_SAMPLING_FREQ_48000,
53                 .channel_mode = APTX_CHANNEL_MODE_STEREO,
54         },
55         {
56                 .info = {
57                         .vendor_id = APTX_VENDOR_ID,
58                         .codec_id = APTX_CODEC_ID,
59                 },
60                 .frequency = APTX_SAMPLING_FREQ_44100,
61                 .channel_mode = APTX_CHANNEL_MODE_STEREO,
62         },
63 };
64
65 static void *aptx_handle;
66 static int aptx_btencsize;
67 static int (*aptx_init)(void *, short);
68 static int (*aptx_encode)(void *, void *, void *, void *);
69
70 static bool aptx_load(void)
71 {
72         const char * (*aptx_version)(void);
73         const char * (*aptx_build)(void);
74         int (*aptx_sizeofenc)(void);
75
76         aptx_handle = dlopen(APTX_SO_NAME, RTLD_LAZY);
77         if (!aptx_handle) {
78                 error("APTX: failed to open library %s (%s)", APTX_SO_NAME,
79                                                                 dlerror());
80                 return false;
81         }
82
83         aptx_version = dlsym(aptx_handle, "aptxbtenc_version");
84         aptx_build = dlsym(aptx_handle, "aptxbtenc_build");
85
86         if (aptx_version && aptx_build)
87                 info("APTX: using library version %s build %s", aptx_version(),
88                                                                 aptx_build());
89         else
90                 warn("APTX: cannot retrieve library version");
91
92         aptx_sizeofenc = dlsym(aptx_handle, "SizeofAptxbtenc");
93         aptx_init = dlsym(aptx_handle, "aptxbtenc_init");
94         aptx_encode = dlsym(aptx_handle, "aptxbtenc_encodestereo");
95         if (!aptx_sizeofenc || !aptx_init || !aptx_encode) {
96                 error("APTX: failed initialize library");
97                 dlclose(aptx_handle);
98                 aptx_handle = NULL;
99                 return false;
100         }
101         aptx_btencsize = aptx_sizeofenc();
102
103         info("APTX: codec library initialized (size=%d)", aptx_btencsize);
104
105         return true;
106 }
107
108 static void aptx_unload(void)
109 {
110         if (!aptx_handle)
111                 return;
112
113         dlclose(aptx_handle);
114         aptx_handle = NULL;
115 }
116
117 static int aptx_get_presets(struct audio_preset *preset, size_t *len)
118 {
119         int i;
120         int count;
121         size_t new_len = 0;
122         uint8_t *ptr = (uint8_t *) preset;
123         size_t preset_size = sizeof(*preset) + sizeof(a2dp_aptx_t);
124
125         DBG("");
126
127         count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);
128
129         for (i = 0; i < count; i++) {
130                 preset = (struct audio_preset *) ptr;
131
132                 if (new_len + preset_size > *len)
133                         break;
134
135                 preset->len = sizeof(a2dp_aptx_t);
136                 memcpy(preset->data, &aptx_presets[i], preset->len);
137
138                 new_len += preset_size;
139                 ptr += preset_size;
140         }
141
142         *len = new_len;
143
144         return i;
145 }
146
147 static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,
148                                                         void **codec_data)
149 {
150         struct aptx_data *aptx_data;
151
152         DBG("");
153
154         if (preset->len != sizeof(a2dp_aptx_t)) {
155                 error("APTX: preset size mismatch");
156                 return false;
157         }
158
159         aptx_data = malloc(sizeof(*aptx_data));
160         if (!aptx_data)
161                 return false;
162
163         memset(aptx_data, 0, sizeof(*aptx_data));
164         memcpy(&aptx_data->aptx, preset->data, preset->len);
165
166         aptx_data->enc = calloc(1, aptx_btencsize);
167         if (!aptx_data->enc) {
168                 error("APTX: failed to create encoder");
169                 free(aptx_data);
170                 return false;
171         }
172
173         /* 1 = big-endian, this is what devices are using */
174         aptx_init(aptx_data->enc, 1);
175
176         *codec_data = aptx_data;
177
178         return true;
179 }
180
181 static bool aptx_cleanup(void *codec_data)
182 {
183         struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
184
185         free(aptx_data->enc);
186         free(codec_data);
187
188         return true;
189 }
190
191 static bool aptx_get_config(void *codec_data, struct audio_input_config *config)
192 {
193         struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
194
195         config->rate = aptx_data->aptx.frequency & APTX_SAMPLING_FREQ_48000 ?
196                                                                 48000 : 44100;
197         config->channels = AUDIO_CHANNEL_OUT_STEREO;
198         config->format = AUDIO_FORMAT_PCM_16_BIT;
199
200         return true;
201 }
202
203 static size_t aptx_get_buffer_size(void *codec_data)
204 {
205         /* TODO: return actual value */
206         return 0;
207 }
208
209 static size_t aptx_get_mediapacket_duration(void *codec_data)
210 {
211         /* TODO: return actual value */
212         return 0;
213 }
214
215 static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
216                                         size_t len, struct media_packet *mp,
217                                         size_t mp_data_len, size_t *written)
218 {
219         struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
220         const int16_t *ptr = (const void *) buffer;
221         size_t bytes_in = 0;
222         size_t bytes_out = 0;
223
224         while ((len - bytes_in) >= 16 && (mp_data_len - bytes_out) >= 4) {
225                 int pcm_l[4], pcm_r[4];
226                 int i;
227
228                 for (i = 0; i < 4; i++) {
229                         pcm_l[i] = ptr[0];
230                         pcm_r[i] = ptr[1];
231                         ptr += 2;
232                 }
233
234                 aptx_encode(aptx_data->enc, pcm_l, pcm_r, &mp->data[bytes_out]);
235
236                 bytes_in += 16;
237                 bytes_out += 4;
238         }
239
240         *written = bytes_out;
241
242         return bytes_in;
243 }
244
245 static bool aptx_update_qos(void *codec_data, uint8_t op)
246 {
247         /*
248          * aptX has constant bitrate of 352kbps (with constant 4:1 compression
249          * ratio) thus QoS is not possible here.
250          */
251
252         return false;
253 }
254
255 static const struct audio_codec codec = {
256         .type = A2DP_CODEC_VENDOR,
257         .use_rtp = false,
258
259         .load = aptx_load,
260         .unload = aptx_unload,
261
262         .get_presets = aptx_get_presets,
263
264         .init = aptx_codec_init,
265         .cleanup = aptx_cleanup,
266         .get_config = aptx_get_config,
267         .get_buffer_size = aptx_get_buffer_size,
268         .get_mediapacket_duration = aptx_get_mediapacket_duration,
269         .encode_mediapacket = aptx_encode_mediapacket,
270         .update_qos = aptx_update_qos,
271 };
272
273 const struct audio_codec *codec_aptx(void)
274 {
275         return &codec;
276 }