Home | History | Annotate | Download | only in audio_extn
      1 /*
      2  * Copyright (C) 2015 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 #define LOG_TAG "soundtrigger"
     17 /* #define LOG_NDEBUG 0 */
     18 #define LOG_NDDEBUG 0
     19 
     20 #include <errno.h>
     21 #include <stdbool.h>
     22 #include <stdlib.h>
     23 #include <dlfcn.h>
     24 #include <cutils/log.h>
     25 #include "audio_hw.h"
     26 #include "audio_extn.h"
     27 #include "platform.h"
     28 #include "platform_api.h"
     29 #include "sound_trigger_prop_intf.h"
     30 
     31 #define XSTR(x) STR(x)
     32 #define STR(x) #x
     33 
     34 #ifdef __LP64__
     35 #define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib64/hw/sound_trigger.primary.%s.so"
     36 #else
     37 #define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib/hw/sound_trigger.primary.%s.so"
     38 #endif
     39 
     40 struct sound_trigger_info  {
     41     struct sound_trigger_session_info st_ses;
     42     bool lab_stopped;
     43     struct listnode list;
     44 };
     45 
     46 struct sound_trigger_audio_device {
     47     void *lib_handle;
     48     struct audio_device *adev;
     49     sound_trigger_hw_call_back_t st_callback;
     50     struct listnode st_ses_list;
     51     pthread_mutex_t lock;
     52 };
     53 
     54 static struct sound_trigger_audio_device *st_dev;
     55 
     56 static struct sound_trigger_info *
     57 get_sound_trigger_info(int capture_handle)
     58 {
     59     struct sound_trigger_info  *st_ses_info = NULL;
     60     struct listnode *node;
     61     ALOGV("%s: list %d capture_handle %d", __func__,
     62            list_empty(&st_dev->st_ses_list), capture_handle);
     63     list_for_each(node, &st_dev->st_ses_list) {
     64         st_ses_info = node_to_item(node, struct sound_trigger_info , list);
     65         if (st_ses_info->st_ses.capture_handle == capture_handle)
     66             return st_ses_info;
     67     }
     68     return NULL;
     69 }
     70 
     71 int audio_hw_call_back(sound_trigger_event_type_t event,
     72                        sound_trigger_event_info_t* config)
     73 {
     74     int status = 0;
     75     struct sound_trigger_info  *st_ses_info;
     76 
     77     if (!st_dev)
     78        return -EINVAL;
     79 
     80     pthread_mutex_lock(&st_dev->lock);
     81     switch (event) {
     82     case ST_EVENT_SESSION_REGISTER:
     83         if (!config) {
     84             ALOGE("%s: NULL config", __func__);
     85             status = -EINVAL;
     86             break;
     87         }
     88         st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
     89         if (!st_ses_info) {
     90             ALOGE("%s: st_ses_info alloc failed", __func__);
     91             status = -ENOMEM;
     92             break;
     93         }
     94         memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (config->st_ses));
     95         ALOGV("%s: add capture_handle %d pcm %p", __func__,
     96               st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
     97         list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
     98         break;
     99 
    100     case ST_EVENT_SESSION_DEREGISTER:
    101         if (!config) {
    102             ALOGE("%s: NULL config", __func__);
    103             status = -EINVAL;
    104             break;
    105         }
    106         st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
    107         if (!st_ses_info) {
    108             ALOGE("%s: pcm %p not in the list!", __func__, config->st_ses.pcm);
    109             status = -EINVAL;
    110             break;
    111         }
    112         ALOGV("%s: remove capture_handle %d pcm %p", __func__,
    113               st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
    114         list_remove(&st_ses_info->list);
    115         free(st_ses_info);
    116         break;
    117     default:
    118         ALOGW("%s: Unknown event %d", __func__, event);
    119         break;
    120     }
    121     pthread_mutex_unlock(&st_dev->lock);
    122     return status;
    123 }
    124 
    125 int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
    126                        size_t bytes)
    127 {
    128     int ret = -1;
    129     struct sound_trigger_info  *st_info = NULL;
    130     audio_event_info_t event;
    131 
    132     if (!st_dev)
    133        return ret;
    134 
    135     if (!in->is_st_session_active) {
    136         ALOGE(" %s: Sound trigger is not active", __func__);
    137         goto exit;
    138     }
    139     if (in->standby)
    140         in->standby = false;
    141 
    142     pthread_mutex_lock(&st_dev->lock);
    143     st_info = get_sound_trigger_info(in->capture_handle);
    144     pthread_mutex_unlock(&st_dev->lock);
    145     if (st_info) {
    146         event.u.aud_info.ses_info = &st_info->st_ses;
    147         event.u.aud_info.buf = buffer;
    148         event.u.aud_info.num_bytes = bytes;
    149         ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
    150     }
    151 
    152 exit:
    153     if (ret) {
    154         if (-ENETRESET == ret)
    155             in->is_st_session_active = false;
    156         memset(buffer, 0, bytes);
    157         ALOGV("%s: read failed status %d - sleep", __func__, ret);
    158         usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
    159                                    in->config.rate));
    160     }
    161     return ret;
    162 }
    163 
    164 void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
    165 {
    166     int status = 0;
    167     struct sound_trigger_info  *st_ses_info = NULL;
    168     audio_event_info_t event;
    169 
    170     if (!st_dev || !in)
    171        return;
    172 
    173     pthread_mutex_lock(&st_dev->lock);
    174     st_ses_info = get_sound_trigger_info(in->capture_handle);
    175     pthread_mutex_unlock(&st_dev->lock);
    176     if (st_ses_info) {
    177         event.u.ses_info = st_ses_info->st_ses;
    178         ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
    179         st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
    180     }
    181 }
    182 void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
    183 {
    184     struct sound_trigger_info  *st_ses_info = NULL;
    185     struct listnode *node;
    186 
    187     if (!st_dev || !in)
    188        return;
    189 
    190     pthread_mutex_lock(&st_dev->lock);
    191     in->is_st_session = false;
    192     ALOGV("%s: list %d capture_handle %d", __func__,
    193           list_empty(&st_dev->st_ses_list), in->capture_handle);
    194     list_for_each(node, &st_dev->st_ses_list) {
    195         st_ses_info = node_to_item(node, struct sound_trigger_info , list);
    196         if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
    197             in->pcm = st_ses_info->st_ses.pcm;
    198             in->config = st_ses_info->st_ses.config;
    199             in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
    200             in->is_st_session = true;
    201             in->is_st_session_active = true;
    202             ALOGV("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
    203             break;
    204         }
    205     }
    206     pthread_mutex_unlock(&st_dev->lock);
    207 }
    208 
    209 void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
    210                                      st_event_type_t event)
    211 {
    212     int device_type = -1;
    213 
    214     if (!st_dev)
    215        return;
    216 
    217     if (snd_device >= SND_DEVICE_OUT_BEGIN &&
    218         snd_device < SND_DEVICE_OUT_END) {
    219         device_type = PCM_PLAYBACK;
    220     } else if (snd_device >= SND_DEVICE_IN_BEGIN &&
    221         snd_device < SND_DEVICE_IN_END) {
    222         if (snd_device == SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)
    223             return;
    224         device_type = PCM_CAPTURE;
    225     } else {
    226         ALOGE("%s: invalid device 0x%x, for event %d",
    227                            __func__, snd_device, event);
    228         return;
    229     }
    230 
    231     ALOGV("%s: device 0x%x of type %d for Event %d",
    232         __func__, snd_device, device_type, event);
    233     if (device_type == PCM_CAPTURE) {
    234         switch(event) {
    235         case ST_EVENT_SND_DEVICE_FREE:
    236             st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
    237             break;
    238         case ST_EVENT_SND_DEVICE_BUSY:
    239             st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
    240             break;
    241         default:
    242             ALOGW("%s:invalid event %d for device 0x%x",
    243                                   __func__, event, snd_device);
    244         }
    245     }/*Events for output device, if required can be placed here in else*/
    246 }
    247 
    248 void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
    249                                struct str_parms *params)
    250 {
    251     audio_event_info_t event;
    252     char value[32];
    253     int ret, val;
    254 
    255     if(!st_dev || !params) {
    256         ALOGE("%s: str_params NULL", __func__);
    257         return;
    258     }
    259 
    260     ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
    261                             sizeof(value));
    262     if (ret > 0) {
    263         if (strstr(value, "OFFLINE")) {
    264             event.u.status = SND_CARD_STATUS_OFFLINE;
    265             st_dev->st_callback(AUDIO_EVENT_SSR, &event);
    266         }
    267         else if (strstr(value, "ONLINE")) {
    268             event.u.status = SND_CARD_STATUS_ONLINE;
    269             st_dev->st_callback(AUDIO_EVENT_SSR, &event);
    270         }
    271         else
    272             ALOGE("%s: unknown snd_card_status", __func__);
    273     }
    274 
    275     ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
    276     if (ret > 0) {
    277         if (strstr(value, "OFFLINE")) {
    278             event.u.status = CPE_STATUS_OFFLINE;
    279             st_dev->st_callback(AUDIO_EVENT_SSR, &event);
    280         }
    281         else if (strstr(value, "ONLINE")) {
    282             event.u.status = CPE_STATUS_ONLINE;
    283             st_dev->st_callback(AUDIO_EVENT_SSR, &event);
    284         }
    285         else
    286             ALOGE("%s: unknown CPE status", __func__);
    287     }
    288 
    289     ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
    290     if (ret >= 0) {
    291         event.u.value = val;
    292         st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
    293     }
    294 }
    295 
    296 int audio_extn_sound_trigger_init(struct audio_device *adev)
    297 {
    298     int status = 0;
    299     char sound_trigger_lib[100];
    300     void *lib_handle;
    301 
    302     ALOGV("%s: Enter", __func__);
    303 
    304     st_dev = (struct sound_trigger_audio_device*)
    305                         calloc(1, sizeof(struct sound_trigger_audio_device));
    306     if (!st_dev) {
    307         ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
    308         return -ENOMEM;
    309     }
    310 
    311     snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
    312              SOUND_TRIGGER_LIBRARY_PATH,
    313               XSTR(SOUND_TRIGGER_PLATFORM_NAME));
    314 
    315     st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
    316 
    317     if (st_dev->lib_handle == NULL) {
    318         ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
    319                 dlerror());
    320         status = -EINVAL;
    321         goto cleanup;
    322     }
    323     ALOGV("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
    324 
    325     st_dev->st_callback = (sound_trigger_hw_call_back_t)
    326               dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
    327 
    328     if (st_dev->st_callback == NULL) {
    329        ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
    330                dlerror());
    331        goto cleanup;
    332     }
    333 
    334     st_dev->adev = adev;
    335     list_init(&st_dev->st_ses_list);
    336 
    337     return 0;
    338 
    339 cleanup:
    340     if (st_dev->lib_handle)
    341         dlclose(st_dev->lib_handle);
    342     free(st_dev);
    343     st_dev = NULL;
    344     return status;
    345 
    346 }
    347 
    348 void audio_extn_sound_trigger_deinit(struct audio_device *adev)
    349 {
    350     ALOGV("%s: Enter", __func__);
    351     if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
    352         dlclose(st_dev->lib_handle);
    353         free(st_dev);
    354         st_dev = NULL;
    355     }
    356 }
    357