1 /*
2  * Copyright 2018 Google Inc. All Rights Reserved.
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 "oslo_sound_model"
18 
19 #include <ctype.h>
20 #include <cutils/properties.h>
21 #include <hardware/sound_trigger.h>
22 #include <inttypes.h>
23 #include <log/log.h>
24 #include <pthread.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
32 
33 #include "oslo_sound_model_control.h"
34 #include "sound_trigger_hw_iaxxx.h"
35 
36 using android::sp;
37 using android::hardware::Return;
38 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
39 using android::hardware::soundtrigger::V2_0::SoundModelHandle;
40 using android::hardware::soundtrigger::V2_0::SoundModelType;
41 
42 #define OSLO_SOUND_MODEL_HANDLE_PROP "vendor.oslo.sm.hndl"
43 
44 static SoundModelHandle osloSoundModelHandle = 0;
45 
strToUuid(const char * uuid_str,sound_trigger_uuid_t * uuid)46 static bool strToUuid(const char* uuid_str, sound_trigger_uuid_t* uuid) {
47   if (uuid_str == NULL) {
48     ALOGI("Invalid str_to_uuid input.");
49     return false;
50   }
51 
52   int tmp[10];
53   if (sscanf(uuid_str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
54              tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5,
55              tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
56     ALOGI("Invalid UUID, got: %s", uuid_str);
57     return false;
58   }
59   uuid->timeLow = (unsigned int)tmp[0];
60   uuid->timeMid = (unsigned short)tmp[1];
61   uuid->timeHiAndVersion = (unsigned short)tmp[2];
62   uuid->clockSeq = (unsigned short)tmp[3];
63   uuid->node[0] = (unsigned char)tmp[4];
64   uuid->node[1] = (unsigned char)tmp[5];
65   uuid->node[2] = (unsigned char)tmp[6];
66   uuid->node[3] = (unsigned char)tmp[7];
67   uuid->node[4] = (unsigned char)tmp[8];
68   uuid->node[5] = (unsigned char)tmp[9];
69 
70   return true;
71 }
72 
73 /**
74  * Loads oslo sound model via the SoundTrigger HAL HIDL service.
75  *
76  * @return true if oslo was enabled successfully, false otherwise.
77  */
osloLoadSoundModel(SoundModelHandle * hndl)78 static bool osloLoadSoundModel(SoundModelHandle *hndl) {
79   ALOGD("Loading oslo sound model");
80 
81   sound_trigger_uuid_t uuid;
82   strToUuid(SENSOR_MANAGER_MODEL, &uuid);
83   ISoundTriggerHw::SoundModel soundModel;
84   soundModel.type = SoundModelType::GENERIC;
85   soundModel.vendorUuid.timeLow = uuid.timeLow;
86   soundModel.vendorUuid.timeMid = uuid.timeMid;
87   soundModel.vendorUuid.versionAndTimeHigh = uuid.timeHiAndVersion;
88   soundModel.vendorUuid.variantAndClockSeqHigh = uuid.clockSeq;
89 
90   memcpy(&soundModel.vendorUuid.node[0], &uuid.node[0], sizeof(uuid.node));
91   soundModel.data.resize(1);  // Insert a dummy byte to bypass HAL NULL checks.
92 
93   bool loaded = false;
94   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
95   if (stHal == nullptr) {
96     ALOGE("Failed to get ST HAL service for oslo load");
97   } else {
98     int32_t loadResult;
99     Return<void> hidlResult = stHal->loadSoundModel(soundModel, NULL, 0,
100         [&](int32_t retval, SoundModelHandle handle) {
101             loadResult = retval;
102             *hndl = handle;
103         });
104 
105     if (hidlResult.isOk()) {
106       if (loadResult == 0) {
107         ALOGI("Loaded oslo %d", *hndl);
108         loaded = true;
109       } else {
110         ALOGE("Failed to load oslo with %" PRId32, loadResult);
111       }
112     } else {
113       ALOGE("Failed to load oslo due to hidl error %s",
114             hidlResult.description().c_str());
115     }
116   }
117 
118   return loaded;
119 }
120 
121 /**
122  * Unloads oslo sound model via the SoundTrigger HAL HIDL service.
123  */
osloUnloadSoundModel(SoundModelHandle hndl)124 static void osloUnloadSoundModel(SoundModelHandle hndl) {
125   ALOGD("Unloading oslo sound model %d", hndl);
126 
127   sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
128   if (stHal == nullptr) {
129     ALOGE("Failed to get ST HAL service for oslo unload");
130   } else {
131     Return<int32_t> hidlResult = stHal->unloadSoundModel(hndl);
132 
133     if (hidlResult.isOk()) {
134       if (hidlResult == 0) {
135         ALOGI("Unloaded oslo");
136       } else {
137         ALOGE("Failed to unload oslo with %" PRId32, int32_t(hidlResult));
138       }
139     } else {
140       ALOGE("Failed to unload oslo due to hidl error %s",
141             hidlResult.description().c_str());
142     }
143   }
144 }
145 
osloSoundModelEnable(bool enable)146 void osloSoundModelEnable(bool enable) {
147   if (enable) {
148     if (!osloLoadSoundModel(&osloSoundModelHandle)) {
149       ALOGE("%s: Failed to load oslo sound model", __func__);
150     }
151   }
152   else {
153     if (osloSoundModelHandle == 0) {
154       char prop[PROPERTY_VALUE_MAX];
155       property_get(OSLO_SOUND_MODEL_HANDLE_PROP, prop, "0");
156       osloSoundModelHandle = atoi(prop);
157     }
158 
159     if (osloSoundModelHandle != 0) {
160       osloUnloadSoundModel(osloSoundModelHandle);
161       osloSoundModelHandle = 0;
162     }
163   }
164 
165   property_set(OSLO_SOUND_MODEL_HANDLE_PROP,
166                std::to_string(osloSoundModelHandle).c_str());
167 }
168