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