1 /*
2 * Copyright (C) 2017 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/platform/platform_audio.h"
18
19 #include <cstring>
20
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/platform/host_link.h"
23 #include "chre/platform/log.h"
24 #include "chre/platform/slpi/power_control_util.h"
25 #include "chre/util/memory.h"
26 #include "wcd_spi.h"
27
28 static_assert(
29 sizeof(wcd_spi_audio_source_s) == sizeof(struct chreAudioSource),
30 "WCD SPI/CHRE audio sources must be equal in size");
31 static_assert(
32 offsetof(wcd_spi_audio_source_s, name)
33 == offsetof(struct chreAudioSource, name),
34 "WCD SPI/CHRE audio source name must have the same offset");
35 static_assert(
36 offsetof(wcd_spi_audio_source_s, sample_rate_hz)
37 == offsetof(struct chreAudioSource, sampleRate),
38 "WCD SPI/CHRE audio source sample rate must have the same offset");
39 static_assert(
40 offsetof(wcd_spi_audio_source_s, min_buffer_duration_ns)
41 == offsetof(struct chreAudioSource, minBufferDuration),
42 "WCD SPI/CHRE audio source min buffer duration must have the same offset");
43 static_assert(
44 offsetof(wcd_spi_audio_source_s, max_buffer_duration_ns)
45 == offsetof(struct chreAudioSource, maxBufferDuration),
46 "WCD SPI/CHRE audio source max buffer duration must have the same offset");
47 static_assert(
48 offsetof(wcd_spi_audio_source_s, format)
49 == offsetof(struct chreAudioSource, format),
50 "WCD SPI/CHRE audio source format must have the same offset");
51
52 namespace chre {
53 namespace {
54
handleWcdSpiAudioDataEvent(const wcd_spi_audio_data_event_s * event)55 void handleWcdSpiAudioDataEvent(const wcd_spi_audio_data_event_s *event) {
56 LOGD("WCD SPI audio data callback");
57
58 auto *dataEvent = memoryAlloc<struct chreAudioDataEvent>();
59 if (dataEvent == nullptr) {
60 LOGE("Failed to allocate data event");
61 } else {
62 dataEvent->handle = event->handle;
63 dataEvent->timestamp = event->timestamp_ns;
64 dataEvent->sampleRate = event->sample_rate_hz;
65 dataEvent->sampleCount = event->sample_count;
66 dataEvent->format = event->format;
67
68 // The sample pointers are a union, so the value will be correct regardless
69 // of the sample format. This is just a shallow copy of the data pointer,
70 // not the contents of the buffer itself.
71 dataEvent->samplesULaw8 = event->samples_ulaw8;
72
73 EventLoopManagerSingleton::get()->getAudioRequestManager()
74 .handleAudioDataEvent(dataEvent);
75 }
76 }
77
handleWcdSpiAudioAvailability(uint32_t handle,bool available)78 void handleWcdSpiAudioAvailability(uint32_t handle, bool available) {
79 LOGD("WCD SPI audio handle %" PRIu32 " available: %d", handle, available);
80 EventLoopManagerSingleton::get()->getAudioRequestManager()
81 .handleAudioAvailability(handle, available);
82 }
83
84 } // anonymous namespace
85
PlatformAudio()86 PlatformAudio::PlatformAudio() {}
87
~PlatformAudio()88 PlatformAudio::~PlatformAudio() {
89 wcd_spi_client_deinit();
90 }
91
init()92 void PlatformAudio::init() {
93 wcd_spi_client_init(handleWcdSpiAudioDataEvent,
94 handleWcdSpiAudioAvailability);
95 }
96
setHandleEnabled(uint32_t handle,bool enabled)97 void PlatformAudio::setHandleEnabled(uint32_t handle, bool enabled) {
98 uint32_t lastNumAudioClients = mNumAudioClients;
99
100 if (enabled) {
101 mNumAudioClients++;
102 } else if (mNumAudioClients > 0) {
103 mNumAudioClients--;
104 } else {
105 LOGE("Invalid request to change handle enabled state");
106 }
107
108 if (lastNumAudioClients == 0 && mNumAudioClients > 0) {
109 LOGD("Enabling WCD SLPI");
110 sendAudioRequest();
111 } else if (lastNumAudioClients > 0 && mNumAudioClients == 0) {
112 LOGD("Disabling WCD SLPI");
113 sendAudioRelease();
114 }
115 }
116
requestAudioDataEvent(uint32_t handle,uint32_t numSamples,Nanoseconds eventDelay)117 bool PlatformAudio::requestAudioDataEvent(uint32_t handle,
118 uint32_t numSamples,
119 Nanoseconds eventDelay) {
120 slpiForceBigImage();
121 return wcd_spi_client_request_audio_data_event(handle, numSamples,
122 eventDelay.toRawNanoseconds());
123 }
124
cancelAudioDataEventRequest(uint32_t handle)125 void PlatformAudio::cancelAudioDataEventRequest(uint32_t handle) {
126 slpiForceBigImage();
127 wcd_spi_client_cancel_audio_data_event(handle);
128 }
129
releaseAudioDataEvent(struct chreAudioDataEvent * event)130 void PlatformAudio::releaseAudioDataEvent(struct chreAudioDataEvent *event) {
131 wcd_spi_client_release_audio_data_event(event->handle);
132 memoryFree(event);
133 }
134
getSourceCount()135 size_t PlatformAudio::getSourceCount() {
136 slpiForceBigImage();
137 return wcd_spi_client_get_source_count();
138 }
139
getAudioSource(uint32_t handle,chreAudioSource * source)140 bool PlatformAudio::getAudioSource(uint32_t handle,
141 chreAudioSource *source) {
142 slpiForceBigImage();
143 wcd_spi_audio_source_s wcd_spi_audio_source;
144 bool result = wcd_spi_client_get_source(handle, &wcd_spi_audio_source);
145 if (result) {
146 // The WCD SPI and CHRE source definitions are binary compatible so a simple
147 // memcpy will suffice.
148 memcpy(source, &wcd_spi_audio_source, sizeof(*source));
149 }
150
151 return result;
152 }
153
154 } // namespace chre
155