xref: /aosp_15_r20/system/chre/platform/linux/pal_audio.cc (revision 84e339476a462649f82315436d70fd732297a399)
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 }