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