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 }
34 
PlatformAudio()35 PlatformAudio::PlatformAudio() {}
36 
~PlatformAudio()37 PlatformAudio::~PlatformAudio() {}
38 
init()39 void PlatformAudio::init() {
40   // TODO: Implement this.
41 }
42 
audioSourceCallback(void * cookie)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 = (SystemTime::getMonotonicTime() - samplingTime)
52       .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,
67         const_cast<int16_t *>(dataEvent.samplesS16),
68         static_cast<sf_count_t>(dataEvent.sampleCount));
69     if (readCount != dataEvent.sampleCount) {
70       LOGI("TODO: File done, suspend the source");
71     } else {
72       EventLoopManagerSingleton::get()->getAudioRequestManager()
73           .handleAudioDataEvent(&audioSource->dataEvent);
74     }
75   } else {
76     FATAL_ERROR("Unimplemented data format");
77   }
78 }
79 
setHandleEnabled(uint32_t handle,bool enabled)80 void PlatformAudio::setHandleEnabled(uint32_t handle, bool enabled) {
81   // TODO: Implement this.
82 }
83 
requestAudioDataEvent(uint32_t handle,uint32_t numSamples,Nanoseconds eventDelay)84 bool PlatformAudio::requestAudioDataEvent(uint32_t handle,
85                                           uint32_t numSamples,
86                                           Nanoseconds eventDelay) {
87   LOGD("Request for audio data made for handle %" PRIu32 " with %" PRIu32
88        " samples and %" PRIu64 " delivery interval", handle, numSamples,
89        eventDelay.toRawNanoseconds());
90   auto& source = gAudioSources[handle];
91   source->numSamples = numSamples;
92   source->eventDelay = eventDelay;
93   return source->timer.set(audioSourceCallback, source.get(), eventDelay);
94 }
95 
cancelAudioDataEventRequest(uint32_t handle)96 void PlatformAudio::cancelAudioDataEventRequest(uint32_t handle) {
97   LOGD("Cancelling audio request for handle %" PRIu32, handle);
98   auto& source = gAudioSources[handle];
99   source->timer.cancel();
100 }
101 
releaseAudioDataEvent(struct chreAudioDataEvent * event)102 void PlatformAudio::releaseAudioDataEvent(struct chreAudioDataEvent *event) {
103   // TODO(P1-41459d): Implement this API in terms of libsndfile.
104 }
105 
getSourceCount()106 size_t PlatformAudio::getSourceCount() {
107   return gAudioSources.size();
108 }
109 
getAudioSource(uint32_t handle,chreAudioSource * audioSource) const110 bool PlatformAudio::getAudioSource(uint32_t handle,
111                                    chreAudioSource *audioSource) const {
112   bool success = (handle < gAudioSources.size());
113   if (success) {
114     const auto& source = gAudioSources[handle];
115     // TODO(P1-b9ff35): Ensure that name never exceeds 40 bytes in length.
116     audioSource->name = source->audioFilename.c_str();
117     audioSource->sampleRate =
118         static_cast<uint32_t>(source->audioInfo.samplerate);
119     audioSource->minBufferDuration =
120         source->minBufferDuration.toRawNanoseconds();
121     audioSource->maxBufferDuration =
122         source->maxBufferDuration.toRawNanoseconds();
123     audioSource->format = source->dataEvent.format;
124   }
125 
126   return success;
127 }
128 
addAudioSource(UniquePtr<AudioSource> & source)129 void PlatformAudioBase::addAudioSource(UniquePtr<AudioSource>& source) {
130   LOGI("Adding audio source - filename: %s, min buf size: %" PRIu64 "ms, "
131        "max buf size: %" PRIu64 "ms", source->audioFilename.c_str(),
132        Milliseconds(source->minBufferDuration).getMilliseconds(),
133        Milliseconds(source->maxBufferDuration).getMilliseconds());
134   auto& audioInfo = source->audioInfo;
135   source->audioFile = sf_open(source->audioFilename.c_str(), SFM_READ,
136                               &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 = static_cast<uint8_t *>(
146         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 = static_cast<int16_t *>(
150         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