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 #define LOG_TAG "AAudioMixer" 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #define ATRACE_TAG ATRACE_TAG_AUDIO 22 23 #include <cstring> 24 #include <utils/Trace.h> 25 26 #include "AAudioMixer.h" 27 28 #ifndef AAUDIO_MIXER_ATRACE_ENABLED 29 #define AAUDIO_MIXER_ATRACE_ENABLED 1 30 #endif 31 32 using android::WrappingBuffer; 33 using android::FifoBuffer; 34 using android::fifo_frames_t; 35 36 AAudioMixer::~AAudioMixer() { 37 delete[] mOutputBuffer; 38 } 39 40 void AAudioMixer::allocate(int32_t samplesPerFrame, int32_t framesPerBurst) { 41 mSamplesPerFrame = samplesPerFrame; 42 mFramesPerBurst = framesPerBurst; 43 int32_t samplesPerBuffer = samplesPerFrame * framesPerBurst; 44 mOutputBuffer = new float[samplesPerBuffer]; 45 mBufferSizeInBytes = samplesPerBuffer * sizeof(float); 46 } 47 48 void AAudioMixer::clear() { 49 memset(mOutputBuffer, 0, mBufferSizeInBytes); 50 } 51 52 int32_t AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) { 53 WrappingBuffer wrappingBuffer; 54 float *destination = mOutputBuffer; 55 56 #if AAUDIO_MIXER_ATRACE_ENABLED 57 ATRACE_BEGIN("aaMix"); 58 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */ 59 60 // Gather the data from the client. May be in two parts. 61 fifo_frames_t fullFrames = fifo->getFullDataAvailable(&wrappingBuffer); 62 #if AAUDIO_MIXER_ATRACE_ENABLED 63 if (ATRACE_ENABLED()) { 64 char rdyText[] = "aaMixRdy#"; 65 char letter = 'A' + (streamIndex % 26); 66 rdyText[sizeof(rdyText) - 2] = letter; 67 ATRACE_INT(rdyText, fullFrames); 68 } 69 #else /* MIXER_ATRACE_ENABLED */ 70 (void) trackIndex; 71 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */ 72 73 // If allowUnderflow then always advance by one burst even if we do not have the data. 74 // Otherwise the stream timing will drift whenever there is an underflow. 75 // This actual underflow can then be detected by the client for XRun counting. 76 // 77 // Generally, allowUnderflow will be false when stopping a stream and we want to 78 // use up whatever data is in the queue. 79 fifo_frames_t framesDesired = mFramesPerBurst; 80 if (!allowUnderflow && fullFrames < framesDesired) { 81 framesDesired = fullFrames; // just use what is available then stop 82 } 83 84 // Mix data in one or two parts. 85 int partIndex = 0; 86 int32_t framesLeft = framesDesired; 87 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 88 fifo_frames_t framesToMixFromPart = framesLeft; 89 fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex]; 90 if (framesAvailableFromPart > 0) { 91 if (framesToMixFromPart > framesAvailableFromPart) { 92 framesToMixFromPart = framesAvailableFromPart; 93 } 94 mixPart(destination, (float *)wrappingBuffer.data[partIndex], 95 framesToMixFromPart); 96 97 destination += framesToMixFromPart * mSamplesPerFrame; 98 framesLeft -= framesToMixFromPart; 99 } 100 partIndex++; 101 } 102 fifo->advanceReadIndex(framesDesired); 103 104 #if AAUDIO_MIXER_ATRACE_ENABLED 105 ATRACE_END(); 106 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */ 107 108 return (framesDesired - framesLeft); // framesRead 109 } 110 111 void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) { 112 int32_t numSamples = numFrames * mSamplesPerFrame; 113 // TODO maybe optimize using SIMD 114 for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) { 115 *destination++ += *source++; 116 } 117 } 118 119 float *AAudioMixer::getOutputBuffer() { 120 return mOutputBuffer; 121 } 122