Home | History | Annotate | Download | only in audio_extn
      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 
     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 
     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 
    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 
    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 
    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 
    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     }
    285 
    286     app_type_cfg->mode = flags_to_mode(0 /*playback*/, out->flags);
    287     if (!audio_is_linear_pcm(out->format)) {
    288         platform_get_app_type_v2(adev->platform,
    289                                  PCM_PLAYBACK,
    290                                  app_type_cfg->mode,
    291                                  24,
    292                                  *sample_rate,
    293                                  app_type);
    294         ALOGV("Non pcm got app type %d", *app_type);
    295     } else if (out->format == AUDIO_FORMAT_PCM_16_BIT) {
    296         platform_get_app_type_v2(adev->platform,
    297                                  PCM_PLAYBACK,
    298                                  app_type_cfg->mode,
    299                                  16,
    300                                  *sample_rate,
    301                                  app_type);
    302     } else if (out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
    303                out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
    304         platform_get_app_type_v2(adev->platform,
    305                                  PCM_PLAYBACK,
    306                                  app_type_cfg->mode,
    307                                  24,
    308                                  *sample_rate,
    309                                  app_type);
    310     } else if (out->format == AUDIO_FORMAT_PCM_32_BIT) {
    311         platform_get_app_type_v2(adev->platform,
    312                                  PCM_PLAYBACK,
    313                                  app_type_cfg->mode,
    314                                  32,
    315                                  *sample_rate,
    316                                  app_type);
    317     } else {
    318         ALOGE("%s bad format\n", __func__);
    319         return -1;
    320     }
    321 
    322     app_type_cfg->app_type = *app_type;
    323     app_type_cfg->sample_rate = *sample_rate;
    324     return 0;
    325 }
    326 
    327 static int derive_acdb_dev_id(struct audio_device *adev __unused,
    328                               struct audio_usecase *usecase)
    329 {
    330     struct stream_out *out;
    331     struct stream_in *in;
    332 
    333     if (usecase->type == PCM_PLAYBACK) {
    334         return platform_get_snd_device_acdb_id(usecase->out_snd_device);
    335     } else if(usecase->type == PCM_CAPTURE) {
    336         return platform_get_snd_device_acdb_id(usecase->in_snd_device);
    337     }
    338     return -1;
    339 }
    340 
    341 int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
    342                                        struct audio_usecase *usecase)
    343 {
    344     int len = 0;
    345     int sample_rate;
    346     int app_type;
    347     int acdb_dev_id;
    348     size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
    349     char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
    350     int pcm_device_id;
    351     struct mixer_ctl *ctl;
    352     int ret;
    353 
    354     if (usecase->type == PCM_HFP_CALL) {
    355         return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
    356     }
    357 
    358     if (!platform_supports_app_type_cfg())
    359         return -1;
    360 
    361     if (usecase->type == PCM_PLAYBACK) {
    362         ret = derive_playback_app_type_cfg(adev,
    363                                            usecase,
    364                                            &app_type,
    365                                            &sample_rate);
    366     } else if (usecase->type == PCM_CAPTURE) {
    367         ret = derive_capture_app_type_cfg(adev,
    368                                           usecase,
    369                                           &app_type,
    370                                           &sample_rate);
    371     } else {
    372         ALOGE("%s: Invalid uc type : 0x%x", __func__, usecase->type);
    373         return -1;
    374     }
    375 
    376     if (ret < 0) {
    377         ALOGE("%s: Failed to derive app_type for uc type : 0x%x", __func__,
    378               usecase->type);
    379         return -1;
    380     }
    381 
    382     acdb_dev_id = derive_acdb_dev_id(adev, usecase);
    383     if (acdb_dev_id <= 0) {
    384         ALOGE("%s: Couldn't get the acdb dev id", __func__);
    385         return -1;
    386     }
    387 
    388     pcm_device_id = platform_get_pcm_device_id(usecase->id, usecase->type);
    389     set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type, acdb_dev_id,
    390                                    sample_rate,
    391                                    usecase->type,
    392                                    usecase->type == PCM_PLAYBACK ? usecase->out_snd_device :
    393                                                                    usecase->in_snd_device);
    394     return 0;
    395 }
    396 
    397 int audio_extn_utils_send_app_type_gain(struct audio_device *adev,
    398                                         int app_type,
    399                                         int *gain)
    400 {
    401     int gain_cfg[4];
    402     const char *mixer_ctl_name = "App Type Gain";
    403     struct mixer_ctl *ctl;
    404     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    405     if (!ctl) {
    406         ALOGE("%s: Could not get volume ctl mixer %s", __func__,
    407               mixer_ctl_name);
    408         return -EINVAL;
    409     }
    410     gain_cfg[0] = 0;
    411     gain_cfg[1] = app_type;
    412     gain_cfg[2] = gain[0];
    413     gain_cfg[3] = gain[1];
    414     ALOGV("%s app_type %d l(%d) r(%d)", __func__,  app_type, gain[0], gain[1]);
    415     return mixer_ctl_set_array(ctl, gain_cfg,
    416                                sizeof(gain_cfg)/sizeof(gain_cfg[0]));
    417 }
    418 
    419 // this assumes correct app_type and sample_rate fields
    420 // have been set for the stream using audio_extn_utils_send_app_type_cfg
    421 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
    422                                              struct audio_usecase *usecase)
    423 {
    424     int type = usecase->type;
    425     int app_type = 0;
    426 
    427     if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
    428         struct stream_out *out = usecase->stream.out;
    429         ALOGV("%s send cal for app_type %d, rate %d", __func__,
    430               out->app_type_cfg.app_type,
    431               out->app_type_cfg.sample_rate);
    432         platform_send_audio_calibration_v2(adev->platform, usecase,
    433                                            out->app_type_cfg.app_type,
    434                                            out->app_type_cfg.sample_rate);
    435     } else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
    436         struct stream_in *in = usecase->stream.in;
    437         ALOGV("%s send cal for capture app_type %d, rate %d", __func__,
    438               in->app_type_cfg.app_type,
    439               in->app_type_cfg.sample_rate);
    440         platform_send_audio_calibration_v2(adev->platform, usecase,
    441                                            in->app_type_cfg.app_type,
    442                                            in->app_type_cfg.sample_rate);
    443     } else {
    444         /* when app type is default. the sample rate is not used to send cal */
    445         platform_get_default_app_type_v2(adev->platform, type, &app_type);
    446         platform_send_audio_calibration_v2(adev->platform, usecase, app_type,
    447                                            48000);
    448     }
    449 }
    450 
    451 #define MAX_SND_CARD 8
    452 #define RETRY_US 500000
    453 #define RETRY_NUMBER 10
    454 
    455 #define min(a, b) ((a) < (b) ? (a) : (b))
    456 
    457 static const char *kConfigLocationList[] =
    458         {"/odm/etc", "/vendor/etc", "/system/etc"};
    459 static const int kConfigLocationListSize =
    460         (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
    461 
    462 bool audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])
    463 {
    464     char full_config_path[MIXER_PATH_MAX_LENGTH];
    465     for (int i = 0; i < kConfigLocationListSize; i++) {
    466         snprintf(full_config_path,
    467                  MIXER_PATH_MAX_LENGTH,
    468                  "%s/%s",
    469                  kConfigLocationList[i],
    470                  file_name);
    471         if (F_OK == access(full_config_path, 0)) {
    472             strcpy(file_name, full_config_path);
    473             return true;
    474         }
    475     }
    476     return false;
    477 }
    478 
    479 /* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
    480 int audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
    481 {
    482     if (NULL == snd_card_name) {
    483         return -1;
    484     }
    485 
    486     struct snd_card_split *snd_split_handle = NULL;
    487     int ret = 0;
    488     audio_extn_set_snd_card_split(snd_card_name);
    489     snd_split_handle = audio_extn_get_snd_card_split();
    490 
    491     snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
    492                      PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
    493                      snd_split_handle->form_factor);
    494 
    495     if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
    496         memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
    497         snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
    498                      PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
    499 
    500         if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
    501             memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
    502             strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
    503             ret = audio_extn_utils_resolve_config_file(platform_info_file) ? 0 : -1;
    504         }
    505     }
    506 
    507     return ret;
    508 }
    509 
    510 int audio_extn_utils_get_snd_card_num()
    511 {
    512 
    513     void *hw_info = NULL;
    514     struct mixer *mixer = NULL;
    515     int retry_num = 0;
    516     int snd_card_num = 0;
    517     const char* snd_card_name = NULL;
    518     char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
    519 
    520     struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
    521 
    522     bool card_verifed[MAX_SND_CARD] = {0};
    523     const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
    524 
    525     for (;;) {
    526         if (snd_card_num >= MAX_SND_CARD) {
    527             if (retry_num++ >= retry_limit) {
    528                 ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
    529                 snd_card_num = -1;
    530                 goto done;
    531             }
    532 
    533             snd_card_num = 0;
    534             usleep(RETRY_US);
    535             continue;
    536         }
    537 
    538         if (card_verifed[snd_card_num]) {
    539             ++snd_card_num;
    540             continue;
    541         }
    542 
    543         mixer = mixer_open(snd_card_num);
    544 
    545         if (!mixer) {
    546             ALOGE("%s: Unable to open the mixer card: %d", __func__,
    547                snd_card_num);
    548             ++snd_card_num;
    549             continue;
    550         }
    551 
    552         card_verifed[snd_card_num] = true;
    553 
    554         snd_card_name = mixer_get_name(mixer);
    555         hw_info = hw_info_init(snd_card_name);
    556 
    557         if (audio_extn_utils_get_platform_info(snd_card_name, platform_info_file) < 0) {
    558             ALOGE("Failed to find platform_info_file");
    559             goto cleanup;
    560         }
    561 
    562         /* Initialize snd card name specific ids and/or backends*/
    563         if (snd_card_info_init(platform_info_file, my_data,
    564                                &acdb_set_parameters) < 0) {
    565             ALOGE("Failed to find platform_info_file");
    566             goto cleanup;
    567         }
    568 
    569         /* validate the sound card name
    570          * my_data->snd_card_name can contain
    571          *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
    572          *         example: msm8994-tomtom-mtp-snd-card
    573          *     <b> or sub string of the card name, i.e. <device>-<codec>
    574          *         example: msm8994-tomtom
    575          * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
    576          * so use min of my_data->snd_card_name and snd_card_name length for comparison
    577          */
    578 
    579         if (my_data->snd_card_name != NULL &&
    580                 strncmp(snd_card_name, my_data->snd_card_name,
    581                         min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
    582             ALOGI("%s: found valid sound card %s, but not primary sound card %s",
    583                    __func__, snd_card_name, my_data->snd_card_name);
    584             goto cleanup;
    585         }
    586 
    587         ALOGI("%s: found sound card %s, primary sound card expected is %s",
    588               __func__, snd_card_name, my_data->snd_card_name);
    589         break;
    590   cleanup:
    591         ++snd_card_num;
    592         mixer_close(mixer);
    593         mixer = NULL;
    594         hw_info_deinit(hw_info);
    595         hw_info = NULL;
    596     }
    597 
    598 done:
    599     mixer_close(mixer);
    600     hw_info_deinit(hw_info);
    601 
    602     if (my_data)
    603         free(my_data);
    604 
    605     return snd_card_num;
    606 }
    607