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