blob: eb0f9f60c23f0c39c1d6dc1ad690acfc8323e210 [file] [log] [blame]
Yamit Mehtae3b99562016-09-16 22:44:00 +05301/*
2 * Copyright (C) 2016 The Android Open Source Project
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#define LOG_TAG "audio_hw_utils"
18//#define LOG_NDEBUG 0
19
20#include <errno.h>
21#include <cutils/properties.h>
22#include <cutils/config_utils.h>
23#include <stdlib.h>
24#include <dlfcn.h>
25#include <cutils/str_parms.h>
26#include <cutils/log.h>
27#include <cutils/misc.h>
28
vivek mehta0fb11312017-05-15 19:35:32 -070029#include "acdb.h"
Yamit Mehtae3b99562016-09-16 22:44:00 +053030#include "audio_hw.h"
31#include "platform.h"
32#include "platform_api.h"
33#include "audio_extn.h"
34
35#define MAX_LENGTH_MIXER_CONTROL_IN_INT 128
36
37static int set_mixer_ctrl(struct audio_device *adev,
38 int pcm_device_id, int app_type,
39 int acdb_dev_id, int sample_rate, int stream_type)
40{
41
42 char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
43 struct mixer_ctl *ctl;
44 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc = 0;
45
46 if (stream_type == PCM_PLAYBACK) {
47 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
48 "Audio Stream %d App Type Cfg", pcm_device_id);
49 } else if (stream_type == PCM_CAPTURE) {
50 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
51 "Audio Stream Capture %d App Type Cfg", pcm_device_id);
52 }
53
54 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
55 if (!ctl) {
56 ALOGE("%s: Could not get ctl for mixer cmd - %s",
57 __func__, mixer_ctl_name);
58 rc = -EINVAL;
59 goto exit;
60 }
61 app_type_cfg[len++] = app_type;
62 app_type_cfg[len++] = acdb_dev_id;
63 app_type_cfg[len++] = sample_rate;
64 ALOGV("%s: stream type %d app_type %d, acdb_dev_id %d sample rate %d",
65 __func__, stream_type, app_type, acdb_dev_id, sample_rate);
66 mixer_ctl_set_array(ctl, app_type_cfg, len);
67
68exit:
69 return rc;
70}
71
72void audio_extn_utils_send_default_app_type_cfg(void *platform, struct mixer *mixer)
73{
74 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
75 int length = 0, app_type = 0,rc = 0;
76 struct mixer_ctl *ctl = NULL;
77 const char *mixer_ctl_name = "App Type Config";
78
79 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
80 if (!ctl) {
81 ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
82 return;
83 }
84 rc = platform_get_default_app_type_v2(platform, PCM_PLAYBACK, &app_type);
85 if (rc == 0) {
86 app_type_cfg[length++] = 1;
87 app_type_cfg[length++] = app_type;
88 app_type_cfg[length++] = 48000;
89 app_type_cfg[length++] = 16;
90 mixer_ctl_set_array(ctl, app_type_cfg, length);
91 }
92 return;
93}
94
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -080095static int audio_extn_utils_send_app_type_cfg_hfp(struct audio_device *adev,
Yamit Mehtae3b99562016-09-16 22:44:00 +053096 struct audio_usecase *usecase)
97{
98 struct mixer_ctl *ctl;
99 int pcm_device_id, acdb_dev_id = 0, snd_device = usecase->out_snd_device;
100 int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
101 int app_type = 0, rc = 0;
102
103 ALOGV("%s", __func__);
104
105 if (usecase->type != PCM_HFP_CALL) {
106 ALOGV("%s: not a playback or HFP path, no need to cfg app type", __func__);
107 rc = 0;
108 goto exit_send_app_type_cfg;
109 }
110 if ((usecase->id != USECASE_AUDIO_HFP_SCO) &&
111 (usecase->id != USECASE_AUDIO_HFP_SCO_WB)) {
112 ALOGV("%s: a playback path where app type cfg is not required", __func__);
113 rc = 0;
114 goto exit_send_app_type_cfg;
115 }
116
117 snd_device = usecase->out_snd_device;
118 pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
119
120 snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
121 audio_extn_get_spkr_prot_snd_device(snd_device) : snd_device;
122 acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
123 if (acdb_dev_id < 0) {
124 ALOGE("%s: Couldn't get the acdb dev id", __func__);
125 rc = -EINVAL;
126 goto exit_send_app_type_cfg;
127 }
128
129 if (usecase->type == PCM_HFP_CALL) {
130
131 /* config HFP session:1 playback path */
132 rc = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK, &app_type);
133 if (rc < 0)
134 goto exit_send_app_type_cfg;
135
136 sample_rate= CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
137 rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
138 acdb_dev_id, sample_rate, PCM_PLAYBACK);
139 if (rc < 0)
140 goto exit_send_app_type_cfg;
141 /* config HFP session:1 capture path */
142 rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
143
144 if (rc == 0) {
145 rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
146 acdb_dev_id, sample_rate, PCM_CAPTURE);
147 if (rc < 0)
148 goto exit_send_app_type_cfg;
149 }
150 /* config HFP session:2 capture path */
151 pcm_device_id = HFP_ASM_RX_TX;
152 snd_device = usecase->in_snd_device;
153 acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
154 if (acdb_dev_id <= 0) {
155 ALOGE("%s: Couldn't get the acdb dev id", __func__);
156 rc = -EINVAL;
157 goto exit_send_app_type_cfg;
158 }
159 rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
160 if (rc == 0) {
161 rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
162 acdb_dev_id, sample_rate, PCM_CAPTURE);
163 if (rc < 0)
164 goto exit_send_app_type_cfg;
165 }
166
167 /* config HFP session:2 playback path */
168 rc = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK, &app_type);
169 if (rc == 0) {
170 rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
171 acdb_dev_id, sample_rate, PCM_PLAYBACK);
172 if (rc < 0)
173 goto exit_send_app_type_cfg;
174 }
175 }
176
177 rc = 0;
178exit_send_app_type_cfg:
179 return rc;
180}
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800181
182int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
183 struct audio_usecase *usecase)
184{
185 int len = 0;
186 if (usecase->type == PCM_HFP_CALL) {
187 return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
188 }
189
190 if (usecase->type != PCM_PLAYBACK || !platform_supports_app_type_cfg())
191 return -1;
192
193 size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
194 int pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
195
196 char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
197 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
198 "Audio Stream %d App Type Cfg", pcm_device_id);
199 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
200 if (!ctl) {
201 ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
202 mixer_ctl_name);
203 return -EINVAL;
204 }
205
206 snd_device_t snd_device = usecase->out_snd_device; // add speaker prot changes if needed
207 int acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
208 if (acdb_dev_id <= 0) {
209 ALOGE("%s: Couldn't get the acdb dev id", __func__);
210 return -1;
211 }
212
213 if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
214 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
215 } else if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||
216 snd_device == SND_DEVICE_OUT_USB_HEADPHONES) {
217 platform_check_and_update_copp_sample_rate(adev->platform, snd_device,
218 usecase->stream.out->sample_rate,
219 &usecase->stream.out->app_type_cfg.sample_rate);
220 }
221
222 int32_t sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
223 int app_type;
224 if (!audio_is_linear_pcm(usecase->stream.out->format)) {
225 platform_get_default_app_type_v2(adev->platform,
226 PCM_PLAYBACK,
227 &app_type);
228 } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_16_BIT) {
229 platform_get_app_type_v2(adev->platform,
230 16,
231 sample_rate,
232 PCM_PLAYBACK,
233 &app_type);
234 } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
235 usecase->stream.out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
236 platform_get_app_type_v2(adev->platform,
237 24,
238 sample_rate,
239 PCM_PLAYBACK,
240 &app_type);
241 } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_32_BIT) {
242 platform_get_app_type_v2(adev->platform,
243 32,
244 sample_rate,
245 PCM_PLAYBACK,
246 &app_type);
247 } else {
248 ALOGE("%s bad format\n", __func__);
249 return -1;
250 }
251
252 //XXX this would be set somewhere else
253 usecase->stream.out->app_type_cfg.app_type = app_type;
254 app_type_cfg[len++] = app_type;
255 app_type_cfg[len++] = acdb_dev_id;
256 app_type_cfg[len++] = sample_rate;
257
258 // add be_idx once available
259 // if (snd_device_be_idx > 0)
260 // app_type_cfg[len++] = snd_device_be_idx;
261
262 ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
263 __func__, app_type, acdb_dev_id, sample_rate);
264
265 mixer_ctl_set_array(ctl, app_type_cfg, len);
266 return 0;
267}
268
269void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
270 struct audio_usecase *usecase)
271{
272 int type = usecase->type;
273 int app_type = 0;
274
275 if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
276 struct stream_out *out = usecase->stream.out;
277 ALOGV("%s send cal for app_type %d, rate %d", __func__, out->app_type_cfg.app_type,
278 usecase->stream.out->app_type_cfg.sample_rate);
279 platform_send_audio_calibration_v2(adev->platform, usecase,
280 out->app_type_cfg.app_type,
281 usecase->stream.out->app_type_cfg.sample_rate);
282 } else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
283 // TBD
284 // platform_send_audio_calibration_v2(adev->platform, usecase,
285 // usecase->stream.in->app_type_cfg.app_type,
286 // usecase->stream.in->app_type_cfg.sample_rate);
287 // uncomment these once send_app_type_cfg and the config entries for
288 // non-16 bit capture are figured out.
289 platform_get_default_app_type_v2(adev->platform, type, &app_type);
290 platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
291 } else {
292 /* when app type is default. the sample rate is not used to send cal */
293 platform_get_default_app_type_v2(adev->platform, type, &app_type);
294 platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
295 }
296}
vivek mehta0fb11312017-05-15 19:35:32 -0700297
298#define MAX_SND_CARD 8
299#define RETRY_US 500000
300#define RETRY_NUMBER 10
301
302#define min(a, b) ((a) < (b) ? (a) : (b))
303
304static const char *kConfigLocationList[] =
305 {"/odm/etc", "/vendor/etc", "/system/etc"};
306static const int kConfigLocationListSize =
307 (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
308
309bool audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])
310{
311 char full_config_path[MIXER_PATH_MAX_LENGTH];
312 for (int i = 0; i < kConfigLocationListSize; i++) {
313 snprintf(full_config_path,
314 MIXER_PATH_MAX_LENGTH,
315 "%s/%s",
316 kConfigLocationList[i],
317 file_name);
318 if (F_OK == access(full_config_path, 0)) {
319 strcpy(file_name, full_config_path);
320 return true;
321 }
322 }
323 return false;
324}
325
326/* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700327int audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
vivek mehta0fb11312017-05-15 19:35:32 -0700328{
329 if (NULL == snd_card_name) {
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700330 return -1;
vivek mehta0fb11312017-05-15 19:35:32 -0700331 }
332
333 struct snd_card_split *snd_split_handle = NULL;
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700334 int ret = 0;
vivek mehta0fb11312017-05-15 19:35:32 -0700335 audio_extn_set_snd_card_split(snd_card_name);
336 snd_split_handle = audio_extn_get_snd_card_split();
337
338 snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
339 PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
340 snd_split_handle->form_factor);
341
342 if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
343 memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
344 snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
345 PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
346
347 if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
348 memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
349 strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700350 ret = audio_extn_utils_resolve_config_file(platform_info_file) ? 0 : -1;
vivek mehta0fb11312017-05-15 19:35:32 -0700351 }
352 }
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700353
354 return ret;
vivek mehta0fb11312017-05-15 19:35:32 -0700355}
356
357int audio_extn_utils_get_snd_card_num()
358{
359
360 void *hw_info = NULL;
361 struct mixer *mixer = NULL;
362 int retry_num = 0;
363 int snd_card_num = 0;
364 const char* snd_card_name = NULL;
365 char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
366
367 struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
368
369 bool card_verifed[MAX_SND_CARD] = {0};
370 const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
371
372 for (;;) {
373 if (snd_card_num >= MAX_SND_CARD) {
374 if (retry_num++ >= retry_limit) {
375 ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
376 snd_card_num = -1;
377 goto done;
378 }
379
380 snd_card_num = 0;
381 usleep(RETRY_US);
382 continue;
383 }
384
385 if (card_verifed[snd_card_num]) {
386 ++snd_card_num;
387 continue;
388 }
389
390 mixer = mixer_open(snd_card_num);
391
392 if (!mixer) {
393 ALOGE("%s: Unable to open the mixer card: %d", __func__,
394 snd_card_num);
395 ++snd_card_num;
396 continue;
397 }
398
399 card_verifed[snd_card_num] = true;
400
401 snd_card_name = mixer_get_name(mixer);
402 hw_info = hw_info_init(snd_card_name);
403
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700404 if (audio_extn_utils_get_platform_info(snd_card_name, platform_info_file) < 0) {
405 ALOGE("Failed to find platform_info_file");
406 goto cleanup;
407 }
vivek mehta0fb11312017-05-15 19:35:32 -0700408
409 /* Initialize snd card name specific ids and/or backends*/
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700410 if (snd_card_info_init(platform_info_file, my_data,
411 &acdb_set_parameters) < 0) {
412 ALOGE("Failed to find platform_info_file");
413 goto cleanup;
414 }
vivek mehta0fb11312017-05-15 19:35:32 -0700415
416 /* validate the sound card name
417 * my_data->snd_card_name can contain
418 * <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
419 * example: msm8994-tomtom-mtp-snd-card
420 * <b> or sub string of the card name, i.e. <device>-<codec>
421 * example: msm8994-tomtom
422 * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
423 * so use min of my_data->snd_card_name and snd_card_name length for comparison
424 */
425
426 if (my_data->snd_card_name != NULL &&
427 strncmp(snd_card_name, my_data->snd_card_name,
428 min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
429 ALOGI("%s: found valid sound card %s, but not primary sound card %s",
430 __func__, snd_card_name, my_data->snd_card_name);
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700431 goto cleanup;
vivek mehta0fb11312017-05-15 19:35:32 -0700432 }
433
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700434 ALOGI("%s: found sound card %s, primary sound card expected is %s",
vivek mehta0fb11312017-05-15 19:35:32 -0700435 __func__, snd_card_name, my_data->snd_card_name);
436 break;
Haynes Mathew George66ff30c2017-06-01 20:24:42 -0700437 cleanup:
438 ++snd_card_num;
439 mixer_close(mixer);
440 mixer = NULL;
441 hw_info_deinit(hw_info);
442 hw_info = NULL;
vivek mehta0fb11312017-05-15 19:35:32 -0700443 }
444
445done:
446 mixer_close(mixer);
447 hw_info_deinit(hw_info);
448
449 if (my_data)
450 free(my_data);
451
452 return snd_card_num;
453}