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_request_manager.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 27 namespace chre { 28 29 namespace { 30 31 //! The fixed sampling rate for audio data when running CHRE on Android. 32 constexpr uint32_t kAndroidAudioSampleRate = 16000; 33 34 //! The minimum buffer size in samples. 35 constexpr uint32_t kAndroidAudioMinBufferSize = kAndroidAudioSampleRate / 10; 36 37 //! The maximum buffer size in samples. 38 constexpr uint32_t kAndroidAudioMaxBufferSize = kAndroidAudioSampleRate * 10; 39 40 } // namespace 41 42 void PlatformAudioBase::audioReadCallback(void *cookie) { 43 auto *platformAudio = static_cast<PlatformAudio *>(cookie); 44 45 auto &dataEvent = platformAudio->mDataEvent; 46 Nanoseconds samplingTime = 47 AudioRequestManager::getDurationFromSampleCountAndRate( 48 platformAudio->mNumSamples, kAndroidAudioSampleRate); 49 dataEvent.timestamp = 50 (SystemTime::getMonotonicTime() - samplingTime).toRawNanoseconds(); 51 52 if (dataEvent.format == CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM) { 53 uint32_t intervalNumSamples = 54 AudioRequestManager::getSampleCountFromRateAndDuration( 55 kAndroidAudioSampleRate, platformAudio->mEventDelay); 56 57 // Determine how much new audio data is required to be read from the device. 58 // Samples that are already buffered by this implementation may be reused. 59 int16_t *audioBuffer = platformAudio->mBuffer.data(); 60 uint32_t readAmount = platformAudio->mNumSamples; 61 if (intervalNumSamples > platformAudio->mNumSamples) { 62 uint32_t seekAmount = intervalNumSamples - platformAudio->mNumSamples; 63 audioBuffer = &platformAudio->mBuffer.data()[seekAmount]; 64 readAmount = platformAudio->mNumSamples - seekAmount; 65 } 66 67 // Perform a blocking read. A timeout of 1 nanoasecond is passed here to 68 // ensure that we read exactly the amount of requested audio frames. The 69 // timer ensures that we wait approximately long enough to read the 70 // requested number of samples and the timeout ensures that they match 71 // exactly. 72 int32_t framesRead = 73 AAudioStream_read(platformAudio->mStream, audioBuffer, readAmount, 1); 74 if (framesRead != static_cast<int32_t>(platformAudio->mNumSamples)) { 75 FATAL_ERROR("Failed to read requested number of audio samples"); 76 } else { 77 EventLoopManagerSingleton::get() 78 ->getAudioRequestManager() 79 .handleAudioDataEvent(&dataEvent); 80 } 81 } else { 82 FATAL_ERROR("Unimplemented data format"); 83 } 84 } 85 86 PlatformAudio::PlatformAudio() { 87 if (!mTimer.init()) { 88 FATAL_ERROR("Failed to initialize audio timer"); 89 } 90 91 aaudio_result_t result = AAudio_createStreamBuilder(&mStreamBuilder); 92 if (result != AAUDIO_OK) { 93 FATAL_ERROR("Failed to create audio stream builder with %" PRId32, result); 94 } 95 96 AAudioStreamBuilder_setDirection(mStreamBuilder, AAUDIO_DIRECTION_INPUT); 97 AAudioStreamBuilder_setSharingMode(mStreamBuilder, 98 AAUDIO_SHARING_MODE_SHARED); 99 AAudioStreamBuilder_setSampleRate(mStreamBuilder, kAndroidAudioSampleRate); 100 AAudioStreamBuilder_setChannelCount(mStreamBuilder, 1); 101 AAudioStreamBuilder_setFormat(mStreamBuilder, AAUDIO_FORMAT_PCM_I16); 102 AAudioStreamBuilder_setBufferCapacityInFrames(mStreamBuilder, 103 kAndroidAudioMaxBufferSize); 104 105 result = AAudioStreamBuilder_openStream(mStreamBuilder, &mStream); 106 if (result != AAUDIO_OK) { 107 FATAL_ERROR("Failed to create audio stream with %" PRId32, result); 108 } 109 110 int32_t bufferSize = AAudioStream_getBufferCapacityInFrames(mStream); 111 LOGD("Created audio stream with %" PRId32 " frames buffer size", bufferSize); 112 113 mMinBufferDuration = AudioRequestManager::getDurationFromSampleCountAndRate( 114 kAndroidAudioMinBufferSize, kAndroidAudioSampleRate) 115 .toRawNanoseconds(); 116 mMaxBufferDuration = AudioRequestManager::getDurationFromSampleCountAndRate( 117 bufferSize, kAndroidAudioSampleRate) 118 .toRawNanoseconds(); 119 120 result = AAudioStream_requestStart(mStream); 121 if (result != AAUDIO_OK) { 122 FATAL_ERROR("Failed to start audio stream with %" PRId32, result); 123 } 124 125 mBuffer.resize(bufferSize); 126 initAudioDataEvent(); 127 } 128 129 PlatformAudio::~PlatformAudio() { 130 AAudioStream_close(mStream); 131 AAudioStreamBuilder_delete(mStreamBuilder); 132 } 133 134 void PlatformAudio::init() { 135 // TODO: Implement this. 136 } 137 138 void PlatformAudio::setHandleEnabled(uint32_t handle, bool enabled) { 139 // TODO: Implement this. 140 } 141 142 bool PlatformAudio::requestAudioDataEvent(uint32_t handle, uint32_t numSamples, 143 Nanoseconds eventDelay) { 144 mNumSamples = numSamples; 145 mEventDelay = eventDelay; 146 mDataEvent.sampleCount = numSamples; 147 return mTimer.set(audioReadCallback, this, eventDelay); 148 } 149 150 void PlatformAudio::cancelAudioDataEventRequest(uint32_t handle) { 151 mTimer.cancel(); 152 } 153 154 void PlatformAudio::releaseAudioDataEvent(struct chreAudioDataEvent *event) {} 155 156 size_t PlatformAudio::getSourceCount() { 157 // Hardcoded at one as the Android platform only surfaces the default mic. 158 return 1; 159 } 160 161 bool PlatformAudio::getAudioSource(uint32_t handle, 162 chreAudioSource *audioSource) const { 163 bool success = false; 164 if (handle == 0) { 165 audioSource->name = "Default Android Audio Input"; 166 audioSource->sampleRate = kAndroidAudioSampleRate; 167 audioSource->minBufferDuration = mMinBufferDuration; 168 audioSource->maxBufferDuration = mMaxBufferDuration; 169 audioSource->format = mDataEvent.format; 170 success = true; 171 } 172 173 return success; 174 } 175 176 void PlatformAudioBase::initAudioDataEvent() { 177 mDataEvent.version = CHRE_AUDIO_DATA_EVENT_VERSION; 178 memset(mDataEvent.reserved, 0, sizeof(mDataEvent.reserved)); 179 mDataEvent.handle = 0; 180 mDataEvent.sampleRate = kAndroidAudioSampleRate; 181 mDataEvent.format = CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM; 182 mDataEvent.samplesS16 = mBuffer.data(); 183 } 184 185 } // namespace chre 186