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