1 /*
2 * Copyright (C) 2022 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 #include "chre/pal/audio.h"
18
19 #include "chre/platform/linux/task_util/task_manager.h"
20 #include "chre/platform/memory.h"
21 #include "chre/util/macros.h"
22 #include "chre/util/memory.h"
23 #include "chre/util/unique_ptr.h"
24
25 #include <chrono>
26 #include <cinttypes>
27 #include <cstdint>
28
29 /**
30 * A simulated implementation of the audio PAL for the linux platform.
31 */
32 namespace {
33
34 using ::chre::TaskManagerSingleton;
35
36 const struct chrePalSystemApi *gSystemApi = nullptr;
37 const struct chrePalAudioCallbacks *gCallbacks = nullptr;
38
39 constexpr uint32_t kHandle0SampleRate = 16000;
40
41 //! Whether the handle 0 is currently enabled.
42 std::optional<uint32_t> gHandle0TaskId;
43 bool gIsHandle0Enabled = false;
44
stopHandle0Task()45 void stopHandle0Task() {
46 if (gHandle0TaskId.has_value()) {
47 TaskManagerSingleton::get()->cancelTask(gHandle0TaskId.value());
48 gHandle0TaskId.reset();
49 }
50 }
51
chrePalAudioApiClose(void)52 void chrePalAudioApiClose(void) {
53 stopHandle0Task();
54 }
55
chrePalAudioApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalAudioCallbacks * callbacks)56 bool chrePalAudioApiOpen(const struct chrePalSystemApi *systemApi,
57 const struct chrePalAudioCallbacks *callbacks) {
58 chrePalAudioApiClose();
59
60 bool success = false;
61 if (systemApi != nullptr && callbacks != nullptr) {
62 gSystemApi = systemApi;
63 gCallbacks = callbacks;
64 callbacks->audioAvailabilityCallback(0 /*handle*/, true /*available*/);
65 success = true;
66 }
67
68 return success;
69 }
70
sendHandle0Events(uint32_t numSamples)71 void sendHandle0Events(uint32_t numSamples) {
72 auto data = chre::MakeUniqueZeroFill<struct chreAudioDataEvent>();
73
74 data->version = CHRE_AUDIO_DATA_EVENT_VERSION;
75 data->handle = 0;
76 data->timestamp = gSystemApi->getCurrentTime();
77 data->sampleRate = kHandle0SampleRate;
78 data->sampleCount = numSamples;
79 data->format = CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW;
80 data->samplesULaw8 =
81 static_cast<const uint8_t *>(chre::memoryAlloc(numSamples));
82
83 gCallbacks->audioDataEventCallback(data.release());
84 }
85
chrePalAudioApiRequestAudioDataEvent(uint32_t handle,uint32_t numSamples,uint64_t eventDelayNs)86 bool chrePalAudioApiRequestAudioDataEvent(uint32_t handle, uint32_t numSamples,
87 uint64_t eventDelayNs) {
88 if (handle != 0) {
89 return false;
90 }
91
92 stopHandle0Task();
93 if (numSamples > 0) {
94 gIsHandle0Enabled = true;
95 gHandle0TaskId = TaskManagerSingleton::get()->addTask(
96 [numSamples]() { sendHandle0Events(numSamples); },
97 std::chrono::nanoseconds(eventDelayNs), true /*isOneShot*/);
98 if (!gHandle0TaskId.has_value()) {
99 return false;
100 }
101 }
102
103 return true;
104 }
105
chrePalAudioApiCancelAudioDataEvent(uint32_t handle)106 void chrePalAudioApiCancelAudioDataEvent(uint32_t handle) {
107 if (handle == 0) {
108 gIsHandle0Enabled = false;
109 stopHandle0Task();
110 }
111 }
112
chrePalAudioApiReleaseAudioDataEvent(struct chreAudioDataEvent * event)113 void chrePalAudioApiReleaseAudioDataEvent(struct chreAudioDataEvent *event) {
114 if (event->format == CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW) {
115 chre::memoryFree((void *)event->samplesULaw8);
116 } else if (event->format == CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM) {
117 chre::memoryFree((void *)event->samplesS16);
118 }
119 chre::memoryFree(event);
120 }
121
chrePalAudioApiGetSourceCount(void)122 uint32_t chrePalAudioApiGetSourceCount(void) {
123 return 1;
124 }
125
chrePalAudioApiGetAudioSource(uint32_t handle,struct chreAudioSource * audioSource)126 bool chrePalAudioApiGetAudioSource(uint32_t handle,
127 struct chreAudioSource *audioSource) {
128 if (handle != 0) {
129 return false;
130 }
131
132 *audioSource = {
133 .name = "Test Source",
134 .sampleRate = kHandle0SampleRate,
135 .minBufferDuration = 1,
136 .maxBufferDuration = 1000000000,
137 .format = CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW,
138 };
139
140 return true;
141 }
142
143 } // namespace
144
chrePalAudioIsHandle0Enabled()145 bool chrePalAudioIsHandle0Enabled() {
146 return gIsHandle0Enabled;
147 }
148
chrePalAudioGetApi(uint32_t requestedApiVersion)149 const chrePalAudioApi *chrePalAudioGetApi(uint32_t requestedApiVersion) {
150 static const struct chrePalAudioApi kApi = {
151 .moduleVersion = CHRE_PAL_AUDIO_API_CURRENT_VERSION,
152 .open = chrePalAudioApiOpen,
153 .close = chrePalAudioApiClose,
154 .requestAudioDataEvent = chrePalAudioApiRequestAudioDataEvent,
155 .cancelAudioDataEvent = chrePalAudioApiCancelAudioDataEvent,
156 .releaseAudioDataEvent = chrePalAudioApiReleaseAudioDataEvent,
157 .getSourceCount = chrePalAudioApiGetSourceCount,
158 .getAudioSource = chrePalAudioApiGetAudioSource,
159 };
160
161 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
162 requestedApiVersion)) {
163 return nullptr;
164 } else {
165 return &kApi;
166 }
167 }