1 /*
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 <unistd.h>
26 #include <cutils/str_parms.h>
27 #include <log/log.h>
28 #include <cutils/misc.h>
29
30 #include "acdb.h"
31 #include "audio_hw.h"
32 #include "platform.h"
33 #include "platform_api.h"
34 #include "audio_extn.h"
35
36 #define MAX_LENGTH_MIXER_CONTROL_IN_INT 128
37
set_stream_app_type_mixer_ctrl(struct audio_device * adev,int pcm_device_id,int app_type,int acdb_dev_id,int sample_rate,int stream_type,snd_device_t snd_device)38 static int set_stream_app_type_mixer_ctrl(struct audio_device *adev,
39 int pcm_device_id, int app_type,
40 int acdb_dev_id, int sample_rate,
41 int stream_type,
42 snd_device_t snd_device)
43 {
44
45 char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
46 struct mixer_ctl *ctl;
47 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc = 0;
48 int snd_device_be_idx = -1;
49
50 if (stream_type == PCM_PLAYBACK) {
51 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
52 "Audio Stream %d App Type Cfg", pcm_device_id);
53 } else if (stream_type == PCM_CAPTURE) {
54 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
55 "Audio Stream Capture %d App Type Cfg", pcm_device_id);
56 }
57
58 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
59 if (!ctl) {
60 ALOGE("%s: Could not get ctl for mixer cmd - %s",
61 __func__, mixer_ctl_name);
62 rc = -EINVAL;
63 goto exit;
64 }
65 app_type_cfg[len++] = app_type;
66 app_type_cfg[len++] = acdb_dev_id;
67 app_type_cfg[len++] = sample_rate;
68
69 snd_device_be_idx = platform_get_snd_device_backend_index(snd_device);
70 if (snd_device_be_idx > 0)
71 app_type_cfg[len++] = snd_device_be_idx;
72 ALOGV("%s: stream type %d app_type %d, acdb_dev_id %d "
73 "sample rate %d, snd_device_be_idx %d",
74 __func__, stream_type, app_type, acdb_dev_id, sample_rate,
75 snd_device_be_idx);
76 mixer_ctl_set_array(ctl, app_type_cfg, len);
77
78 exit:
79 return rc;
80 }
81
audio_extn_utils_send_default_app_type_cfg(void * platform,struct mixer * mixer)82 void audio_extn_utils_send_default_app_type_cfg(void *platform, struct mixer *mixer)
83 {
84 int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
85 int length = 0, app_type = 0,rc = 0;
86 struct mixer_ctl *ctl = NULL;
87 const char *mixer_ctl_name = "App Type Config";
88
89 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
90 if (!ctl) {
91 ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
92 return;
93 }
94 rc = platform_get_default_app_type_v2(platform, PCM_PLAYBACK, &app_type);
95 if (rc == 0) {
96 app_type_cfg[length++] = 1;
97 app_type_cfg[length++] = app_type;
98 app_type_cfg[length++] = 48000;
99 app_type_cfg[length++] = 16;
100 mixer_ctl_set_array(ctl, app_type_cfg, length);
101 }
102 return;
103 }
104
flags_to_mode(int dir,uint32_t flags)105 static const char *flags_to_mode(int dir, uint32_t flags)
106 {
107 if (dir == 0) {
108 if (flags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
109 return "voip";
110 }
111 } else if (dir == 1) {
112 if (flags & AUDIO_INPUT_FLAG_VOIP_TX) {
113 return "voip";
114 }
115 }
116 return "default";
117 }
118
audio_extn_utils_send_app_type_cfg_hfp(struct audio_device * adev,struct audio_usecase * usecase)119 static int audio_extn_utils_send_app_type_cfg_hfp(struct audio_device *adev,
120 struct audio_usecase *usecase)
121 {
122 struct mixer_ctl *ctl;
123 int pcm_device_id, acdb_dev_id = 0, snd_device = usecase->out_snd_device;
124 int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
125 int app_type = 0, rc = 0;
126
127 ALOGV("%s", __func__);
128
129 if (usecase->type != PCM_HFP_CALL) {
130 ALOGV("%s: not a playback or HFP path, no need to cfg app type", __func__);
131 rc = 0;
132 goto exit_send_app_type_cfg;
133 }
134 if ((usecase->id != USECASE_AUDIO_HFP_SCO) &&
135 (usecase->id != USECASE_AUDIO_HFP_SCO_WB)) {
136 ALOGV("%s: a playback path where app type cfg is not required", __func__);
137 rc = 0;
138 goto exit_send_app_type_cfg;
139 }
140
141 snd_device = usecase->out_snd_device;
142 pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
143
144 acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
145 if (acdb_dev_id < 0) {
146 ALOGE("%s: Couldn't get the acdb dev id", __func__);
147 rc = -EINVAL;
148 goto exit_send_app_type_cfg;
149 }
150
151 if (usecase->type == PCM_HFP_CALL) {
152
153 /* config HFP session:1 playback path */
154 rc = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK, &app_type);
155 if (rc < 0)
156 goto exit_send_app_type_cfg;
157
158 sample_rate= CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
159 rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
160 acdb_dev_id, sample_rate,
161 PCM_PLAYBACK,
162 SND_DEVICE_NONE); // use legacy behavior
163 if (rc < 0)
164 goto exit_send_app_type_cfg;
165 /* config HFP session:1 capture path */
166 rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
167
168 if (rc == 0) {
169 rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
170 acdb_dev_id, sample_rate,
171 PCM_CAPTURE,
172 SND_DEVICE_NONE);
173 if (rc < 0)
174 goto exit_send_app_type_cfg;
175 }
176 /* config HFP session:2 capture path */
177 pcm_device_id = HFP_ASM_RX_TX;
178 snd_device = usecase->in_snd_device;
179 acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
180 if (acdb_dev_id <= 0) {
181 ALOGE("%s: Couldn't get the acdb dev id", __func__);
182 rc = -EINVAL;
183 goto exit_send_app_type_cfg;
184 }
185 rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
186 if (rc == 0) {
187 rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
188 acdb_dev_id, sample_rate, PCM_CAPTURE,
189 SND_DEVICE_NONE);
190 if (rc < 0)
191 goto exit_send_app_type_cfg;
192 }
193
194 /* config HFP session:2 playback path */
195 rc = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK, &app_type);
196 if (rc == 0) {
197 rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
198 acdb_dev_id, sample_rate,
199 PCM_PLAYBACK, SND_DEVICE_NONE);
200 if (rc < 0)
201 goto exit_send_app_type_cfg;
202 }
203 }
204
205 rc = 0;
206 exit_send_app_type_cfg:
207 return rc;
208 }
209
210
derive_capture_app_type_cfg(struct audio_device * adev,struct audio_usecase * usecase,int * app_type,int * sample_rate)211 static int derive_capture_app_type_cfg(struct audio_device *adev,
212 struct audio_usecase *usecase,
213 int *app_type,
214 int *sample_rate)
215 {
216 if (usecase->stream.in == NULL) {
217 return -1;
218 }
219 struct stream_in *in = usecase->stream.in;
220 struct stream_app_type_cfg *app_type_cfg = &in->app_type_cfg;
221
222 *sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
223 if (audio_is_usb_in_device(in->device)) {
224 platform_check_and_update_copp_sample_rate(adev->platform,
225 usecase->in_snd_device,
226 in->sample_rate,
227 sample_rate);
228 }
229
230 app_type_cfg->mode = flags_to_mode(1 /*capture*/, in->flags);
231 ALOGV("%s mode %s", __func__, app_type_cfg->mode);
232 if (in->format == AUDIO_FORMAT_PCM_16_BIT) {
233 platform_get_app_type_v2(adev->platform,
234 PCM_CAPTURE,
235 app_type_cfg->mode,
236 16,
237 app_type_cfg->sample_rate,
238 app_type);
239 } else if (in->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
240 in->format == AUDIO_FORMAT_PCM_8_24_BIT) {
241 platform_get_app_type_v2(adev->platform,
242 PCM_CAPTURE,
243 app_type_cfg->mode,
244 24,
245 app_type_cfg->sample_rate,
246 app_type);
247 } else if (in->format == AUDIO_FORMAT_PCM_32_BIT) {
248 platform_get_app_type_v2(adev->platform,
249 PCM_CAPTURE,
250 app_type_cfg->mode,
251 32,
252 app_type_cfg->sample_rate,
253 app_type);
254 } else {
255 ALOGE("%s bad format\n", __func__);
256 return -1;
257 }
258
259 app_type_cfg->app_type = *app_type;
260 app_type_cfg->sample_rate = *sample_rate;
261 return 0;
262 }
263
derive_playback_app_type_cfg(struct audio_device * adev,struct audio_usecase * usecase,int * app_type,int * sample_rate)264 static int derive_playback_app_type_cfg(struct audio_device *adev,
265 struct audio_usecase *usecase,
266 int *app_type,
267 int *sample_rate)
268 {
269 if (usecase->stream.out == NULL) {
270 return -1;
271 }
272 struct stream_out *out = usecase->stream.out;
273 struct stream_app_type_cfg *app_type_cfg = &out->app_type_cfg;
274
275 *sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
276
277 // add speaker prot changes if needed
278 // and use that to check for device
279 if (audio_is_usb_out_device(out->devices)) {
280 platform_check_and_update_copp_sample_rate(adev->platform,
281 usecase->out_snd_device,
282 out->sample_rate,
283 sample_rate);
284 } else if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
285 audio_extn_a2dp_get_sample_rate(sample_rate);
286 ALOGI("%s: Using sample rate %d for A2DP CoPP", __func__,
287 *sample_rate);
288 }
289
290 app_type_cfg->mode = flags_to_mode(0 /*playback*/, out->flags);
291 if (!audio_is_linear_pcm(out->format)) {
292 platform_get_app_type_v2(adev->platform,
293 PCM_PLAYBACK,
294 app_type_cfg->mode,
295 24,
296 *sample_rate,
297 app_type);
298 ALOGV("Non pcm got app type %d", *app_type);
299 } else if (out->format == AUDIO_FORMAT_PCM_16_BIT) {
300 platform_get_app_type_v2(adev->platform,
301 PCM_PLAYBACK,
302 app_type_cfg->mode,
303 16,
304 *sample_rate,
305 app_type);
306 } else if (out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
307 out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
308 platform_get_app_type_v2(adev->platform,
309 PCM_PLAYBACK,
310 app_type_cfg->mode,
311 24,
312 *sample_rate,
313 app_type);
314 } else if (out->format == AUDIO_FORMAT_PCM_32_BIT) {
315 platform_get_app_type_v2(adev->platform,
316 PCM_PLAYBACK,
317 app_type_cfg->mode,
318 32,
319 *sample_rate,
320 app_type);
321 } else {
322 ALOGE("%s bad format\n", __func__);
323 return -1;
324 }
325
326 app_type_cfg->app_type = *app_type;
327 app_type_cfg->sample_rate = *sample_rate;
328 return 0;
329 }
330
derive_acdb_dev_id(struct audio_device * adev __unused,struct audio_usecase * usecase)331 static int derive_acdb_dev_id(struct audio_device *adev __unused,
332 struct audio_usecase *usecase)
333 {
334 struct stream_out *out;
335 struct stream_in *in;
336
337 if (usecase->type == PCM_PLAYBACK) {
338 return platform_get_snd_device_acdb_id(usecase->out_snd_device);
339 } else if(usecase->type == PCM_CAPTURE) {
340 return platform_get_snd_device_acdb_id(usecase->in_snd_device);
341 }
342 return -1;
343 }
344
audio_extn_utils_send_app_type_cfg(struct audio_device * adev,struct audio_usecase * usecase)345 int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
346 struct audio_usecase *usecase)
347 {
348 int len = 0;
349 int sample_rate;
350 int app_type;
351 int acdb_dev_id;
352 int new_snd_device[2] = {0};
353 int i = 0, num_devices = 1;
354 size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
355 char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
356 int pcm_device_id;
357 struct mixer_ctl *ctl;
358 int ret;
359
360 if (usecase->type == PCM_HFP_CALL) {
361 return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
362 }
363
364 if (!platform_supports_app_type_cfg())
365 return -1;
366
367 if (usecase->type == PCM_PLAYBACK) {
368 ret = derive_playback_app_type_cfg(adev,
369 usecase,
370 &app_type,
371 &sample_rate);
372 } else if (usecase->type == PCM_CAPTURE) {
373 ret = derive_capture_app_type_cfg(adev,
374 usecase,
375 &app_type,
376 &sample_rate);
377 } else {
378 ALOGE("%s: Invalid uc type : 0x%x", __func__, usecase->type);
379 return -1;
380 }
381
382 if (ret < 0) {
383 ALOGE("%s: Failed to derive app_type for uc type : 0x%x", __func__,
384 usecase->type);
385 return -1;
386 }
387
388 if (usecase->type == PCM_PLAYBACK) {
389 if (platform_can_split_snd_device(usecase->out_snd_device,
390 &num_devices, new_snd_device) < 0)
391 new_snd_device[0] = usecase->out_snd_device;
392
393 } else if (usecase->type == PCM_CAPTURE)
394 new_snd_device[0] = usecase->in_snd_device;
395
396 pcm_device_id = platform_get_pcm_device_id(usecase->id, usecase->type);
397
398 for (i = 0; i < num_devices; i++) {
399 acdb_dev_id = platform_get_snd_device_acdb_id(new_snd_device[i]);
400
401 if (acdb_dev_id < 0) {
402 ALOGE("%s: Could not find acdb id for device(%d)",
403 __func__, new_snd_device[i]);
404 return -EINVAL;
405 }
406 ALOGV("%s: sending app type for snd_device(%d) acdb_id(%d) i %d",
407 __func__, new_snd_device[i], acdb_dev_id, i);
408
409 set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type, acdb_dev_id,
410 sample_rate,
411 usecase->type,
412 new_snd_device[i]);
413 }
414
415 return 0;
416 }
417
audio_extn_utils_send_app_type_gain(struct audio_device * adev,int app_type,int * gain)418 int audio_extn_utils_send_app_type_gain(struct audio_device *adev,
419 int app_type,
420 int *gain)
421 {
422 int gain_cfg[4];
423 const char *mixer_ctl_name = "App Type Gain";
424 struct mixer_ctl *ctl;
425 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
426 if (!ctl) {
427 ALOGE("%s: Could not get volume ctl mixer %s", __func__,
428 mixer_ctl_name);
429 return -EINVAL;
430 }
431 gain_cfg[0] = 0;
432 gain_cfg[1] = app_type;
433 gain_cfg[2] = gain[0];
434 gain_cfg[3] = gain[1];
435 ALOGV("%s app_type %d l(%d) r(%d)", __func__, app_type, gain[0], gain[1]);
436 return mixer_ctl_set_array(ctl, gain_cfg,
437 sizeof(gain_cfg)/sizeof(gain_cfg[0]));
438 }
439
440 // this assumes correct app_type and sample_rate fields
441 // have been set for the stream using audio_extn_utils_send_app_type_cfg
audio_extn_utils_send_audio_calibration(struct audio_device * adev,struct audio_usecase * usecase)442 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
443 struct audio_usecase *usecase)
444 {
445 int type = usecase->type;
446 int app_type = 0;
447
448 if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
449 struct stream_out *out = usecase->stream.out;
450 ALOGV("%s send cal for app_type %d, rate %d", __func__,
451 out->app_type_cfg.app_type,
452 out->app_type_cfg.sample_rate);
453 platform_send_audio_calibration_v2(adev->platform, usecase,
454 out->app_type_cfg.app_type,
455 out->app_type_cfg.sample_rate);
456 } else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
457 struct stream_in *in = usecase->stream.in;
458 ALOGV("%s send cal for capture app_type %d, rate %d", __func__,
459 in->app_type_cfg.app_type,
460 in->app_type_cfg.sample_rate);
461 platform_send_audio_calibration_v2(adev->platform, usecase,
462 in->app_type_cfg.app_type,
463 in->app_type_cfg.sample_rate);
464 } else {
465 /* when app type is default. the sample rate is not used to send cal */
466 platform_get_default_app_type_v2(adev->platform, type, &app_type);
467 platform_send_audio_calibration_v2(adev->platform, usecase, app_type,
468 48000);
469 }
470 }
471
472 #define MAX_SND_CARD 8
473 #define RETRY_US 500000
474 #define RETRY_NUMBER 10
475
476 #define min(a, b) ((a) < (b) ? (a) : (b))
477
478 static const char *kConfigLocationList[] =
479 {"/odm/etc", "/vendor/etc", "/system/etc"};
480 static const int kConfigLocationListSize =
481 (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
482
audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])483 bool audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])
484 {
485 char full_config_path[MIXER_PATH_MAX_LENGTH];
486 for (int i = 0; i < kConfigLocationListSize; i++) {
487 snprintf(full_config_path,
488 MIXER_PATH_MAX_LENGTH,
489 "%s/%s",
490 kConfigLocationList[i],
491 file_name);
492 if (F_OK == access(full_config_path, 0)) {
493 strcpy(file_name, full_config_path);
494 return true;
495 }
496 }
497 return false;
498 }
499
500 /* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
audio_extn_utils_get_platform_info(const char * snd_card_name,char * platform_info_file)501 int audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
502 {
503 if (NULL == snd_card_name) {
504 return -1;
505 }
506
507 struct snd_card_split *snd_split_handle = NULL;
508 int ret = 0;
509 audio_extn_set_snd_card_split(snd_card_name);
510 snd_split_handle = audio_extn_get_snd_card_split();
511
512 snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
513 PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
514 snd_split_handle->form_factor);
515
516 if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
517 memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
518 snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
519 PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
520
521 if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
522 memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
523 strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
524 ret = audio_extn_utils_resolve_config_file(platform_info_file) ? 0 : -1;
525 }
526 }
527
528 return ret;
529 }
530
audio_extn_utils_get_snd_card_num()531 int audio_extn_utils_get_snd_card_num()
532 {
533
534 void *hw_info = NULL;
535 struct mixer *mixer = NULL;
536 int retry_num = 0;
537 int snd_card_num = 0;
538 const char* snd_card_name = NULL;
539 char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
540
541 struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
542
543 bool card_verifed[MAX_SND_CARD] = {0};
544 const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
545
546 for (;;) {
547 if (snd_card_num >= MAX_SND_CARD) {
548 if (retry_num++ >= retry_limit) {
549 ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
550 snd_card_num = -1;
551 goto done;
552 }
553
554 snd_card_num = 0;
555 usleep(RETRY_US);
556 continue;
557 }
558
559 if (card_verifed[snd_card_num]) {
560 ++snd_card_num;
561 continue;
562 }
563
564 mixer = mixer_open(snd_card_num);
565
566 if (!mixer) {
567 ALOGE("%s: Unable to open the mixer card: %d", __func__,
568 snd_card_num);
569 ++snd_card_num;
570 continue;
571 }
572
573 card_verifed[snd_card_num] = true;
574
575 snd_card_name = mixer_get_name(mixer);
576 hw_info = hw_info_init(snd_card_name);
577
578 if (audio_extn_utils_get_platform_info(snd_card_name, platform_info_file) < 0) {
579 ALOGE("Failed to find platform_info_file");
580 goto cleanup;
581 }
582
583 /* Initialize snd card name specific ids and/or backends*/
584 if (platform_info_init(platform_info_file, my_data, false,
585 &acdb_set_parameters) < 0) {
586 ALOGE("Failed to find platform_info_file");
587 goto cleanup;
588 }
589
590 /* validate the sound card name
591 * my_data->snd_card_name can contain
592 * <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
593 * example: msm8994-tomtom-mtp-snd-card
594 * <b> or sub string of the card name, i.e. <device>-<codec>
595 * example: msm8994-tomtom
596 * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
597 * so use min of my_data->snd_card_name and snd_card_name length for comparison
598 */
599
600 if (my_data->snd_card_name != NULL &&
601 strncmp(snd_card_name, my_data->snd_card_name,
602 min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
603 ALOGI("%s: found valid sound card %s, but not primary sound card %s",
604 __func__, snd_card_name, my_data->snd_card_name);
605 goto cleanup;
606 }
607
608 ALOGI("%s: found sound card %s, primary sound card expected is %s",
609 __func__, snd_card_name, my_data->snd_card_name);
610 break;
611 cleanup:
612 ++snd_card_num;
613 mixer_close(mixer);
614 mixer = NULL;
615 hw_info_deinit(hw_info);
616 hw_info = NULL;
617 }
618
619 done:
620 mixer_close(mixer);
621 hw_info_deinit(hw_info);
622
623 if (my_data)
624 free(my_data);
625
626 return snd_card_num;
627 }
628