• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }