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 <cinttypes>
20
21 #include "chre/core/audio_util.h"
22 #include "chre/core/event_loop_manager.h"
23 #include "chre/platform/fatal_error.h"
24 #include "chre/platform/log.h"
25 #include "chre/platform/system_time.h"
26 #include "chre/util/dynamic_vector.h"
27
28 namespace chre {
29 namespace {
30
31 //! The list of audio sources provided by the simulator.
32 DynamicVector<UniquePtr<AudioSource>> gAudioSources;
33
34 } // namespace
35
PlatformAudio()36 PlatformAudio::PlatformAudio() {}
37
~PlatformAudio()38 PlatformAudio::~PlatformAudio() {}
39
init()40 void PlatformAudio::init() {
41 // TODO: Implement this.
42 }
43
audioSourceCallback(void * cookie)44 void audioSourceCallback(void *cookie) {
45 auto *audioSource = static_cast<AudioSource *>(cookie);
46
47 auto &dataEvent = audioSource->dataEvent;
48 Nanoseconds samplingTime = AudioUtil::getDurationFromSampleCountAndRate(
49 audioSource->numSamples,
50 static_cast<uint32_t>(audioSource->audioInfo.samplerate));
51 dataEvent.timestamp =
52 (SystemTime::getMonotonicTime() - samplingTime).toRawNanoseconds();
53 dataEvent.sampleCount = audioSource->numSamples;
54
55 if (dataEvent.format == CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM) {
56 uint32_t intervalNumSamples = AudioUtil::getSampleCountFromRateAndDuration(
57 static_cast<uint32_t>(audioSource->audioInfo.samplerate),
58 audioSource->eventDelay);
59 if (intervalNumSamples > audioSource->numSamples) {
60 sf_count_t seekAmount = intervalNumSamples - audioSource->numSamples;
61 sf_seek(audioSource->audioFile, -seekAmount, SEEK_CUR);
62 }
63
64 sf_count_t readCount = sf_read_short(
65 audioSource->audioFile, const_cast<int16_t *>(dataEvent.samplesS16),
66 static_cast<sf_count_t>(dataEvent.sampleCount));
67 if (readCount != dataEvent.sampleCount) {
68 LOGI("TODO: File done, suspend the source");
69 } else {
70 EventLoopManagerSingleton::get()
71 ->getAudioRequestManager()
72 .handleAudioDataEvent(&audioSource->dataEvent);
73 }
74 } else {
75 FATAL_ERROR("Unimplemented data format");
76 }
77 }
78
setHandleEnabled(uint32_t handle,bool enabled)79 void PlatformAudio::setHandleEnabled(uint32_t handle, bool enabled) {
80 // TODO: Implement this.
81 }
82
requestAudioDataEvent(uint32_t handle,uint32_t numSamples,Nanoseconds eventDelay)83 bool PlatformAudio::requestAudioDataEvent(uint32_t handle, uint32_t numSamples,
84 Nanoseconds eventDelay) {
85 LOGD("Request for audio data made for handle %" PRIu32 " with %" PRIu32
86 " samples and %" PRIu64 " delivery interval",
87 handle, numSamples, eventDelay.toRawNanoseconds());
88 auto &source = gAudioSources[handle];
89 source->numSamples = numSamples;
90 source->eventDelay = eventDelay;
91 return source->timer.set(audioSourceCallback, source.get(), eventDelay);
92 }
93
cancelAudioDataEventRequest(uint32_t handle)94 void PlatformAudio::cancelAudioDataEventRequest(uint32_t handle) {
95 LOGD("Cancelling audio request for handle %" PRIu32, handle);
96 auto &source = gAudioSources[handle];
97 source->timer.cancel();
98 }
99
releaseAudioDataEvent(struct chreAudioDataEvent * event)100 void PlatformAudio::releaseAudioDataEvent(struct chreAudioDataEvent *event) {
101 // TODO(P1-41459d): Implement this API in terms of libsndfile.
102 }
103
getSourceCount()104 size_t PlatformAudio::getSourceCount() {
105 return gAudioSources.size();
106 }
107
getAudioSource(uint32_t handle,chreAudioSource * audioSource) const108 bool PlatformAudio::getAudioSource(uint32_t handle,
109 chreAudioSource *audioSource) const {
110 bool success = (handle < gAudioSources.size());
111 if (success) {
112 const auto &source = gAudioSources[handle];
113 // TODO(P1-b9ff35): Ensure that name never exceeds 40 bytes in length.
114 audioSource->name = source->audioFilename.c_str();
115 audioSource->sampleRate =
116 static_cast<uint32_t>(source->audioInfo.samplerate);
117 audioSource->minBufferDuration =
118 source->minBufferDuration.toRawNanoseconds();
119 audioSource->maxBufferDuration =
120 source->maxBufferDuration.toRawNanoseconds();
121 audioSource->format = source->dataEvent.format;
122 }
123
124 return success;
125 }
126
addAudioSource(UniquePtr<AudioSource> & source)127 void PlatformAudioBase::addAudioSource(UniquePtr<AudioSource> &source) {
128 LOGI("Adding audio source - filename: %s, min buf size: %" PRIu64
129 "ms, max buf size: %" PRIu64 "ms",
130 source->audioFilename.c_str(),
131 Milliseconds(source->minBufferDuration).getMilliseconds(),
132 Milliseconds(source->maxBufferDuration).getMilliseconds());
133 auto &audioInfo = source->audioInfo;
134 source->audioFile =
135 sf_open(source->audioFilename.c_str(), SFM_READ, &audioInfo);
136 auto sampleCount = AudioUtil::getSampleCountFromRateAndDuration(
137 static_cast<uint32_t>(source->audioInfo.samplerate),
138 source->maxBufferDuration);
139 if (source->audioFile == nullptr) {
140 FATAL_ERROR("Failed to open provided audio file %s",
141 source->audioFilename.c_str());
142 } else if ((audioInfo.format & SF_FORMAT_ULAW) == SF_FORMAT_ULAW) {
143 source->dataEvent.format = CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW;
144 source->dataEvent.samplesULaw8 =
145 static_cast<uint8_t *>(malloc(sizeof(uint8_t) * sampleCount));
146 } else if ((audioInfo.format & SF_FORMAT_PCM_16) == SF_FORMAT_PCM_16) {
147 source->dataEvent.format = CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM;
148 source->dataEvent.samplesS16 =
149 static_cast<int16_t *>(malloc(sizeof(uint16_t) * sampleCount));
150 } else {
151 FATAL_ERROR("Invalid format 0x%08x", audioInfo.format);
152 }
153
154 source->dataEvent.version = CHRE_AUDIO_DATA_EVENT_VERSION;
155 memset(source->dataEvent.reserved, 0, sizeof(source->dataEvent.reserved));
156 source->dataEvent.handle = static_cast<uint32_t>(gAudioSources.size());
157 source->dataEvent.sampleRate =
158 static_cast<uint32_t>(source->audioInfo.samplerate);
159 gAudioSources.push_back(std::move(source));
160 }
161
162 } // namespace chre
163