1c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk/*
2c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Copyright (C) 2017 The Android Open Source Project
3c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
4c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Licensed under the Apache License, Version 2.0 (the "License");
5c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * you may not use this file except in compliance with the License.
6c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * You may obtain a copy of the License at
7c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
8c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *      http://www.apache.org/licenses/LICENSE-2.0
9c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
10c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Unless required by applicable law or agreed to in writing, software
11c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * distributed under the License is distributed on an "AS IS" BASIS,
12c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * See the License for the specific language governing permissions and
14c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * limitations under the License.
15c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk */
16c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
17c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#define LOG_TAG "AAudioService"
18c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk//#define LOG_NDEBUG 0
19c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utils/Log.h>
20c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
21c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <cstring>
22c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AAudioMixer.h"
23c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
24c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::WrappingBuffer;
25c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::FifoBuffer;
26c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::fifo_frames_t;
27c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
28c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil BurkAAudioMixer::~AAudioMixer() {
29c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    delete[] mOutputBuffer;
30c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
31c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
32c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkvoid AAudioMixer::allocate(int32_t samplesPerFrame, int32_t framesPerBurst) {
33c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    mSamplesPerFrame = samplesPerFrame;
34c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    mFramesPerBurst = framesPerBurst;
35c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    int32_t samplesPerBuffer = samplesPerFrame * framesPerBurst;
36c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    mOutputBuffer = new float[samplesPerBuffer];
37c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    mBufferSizeInBytes = samplesPerBuffer * sizeof(float);
38c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
39c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
40c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkvoid AAudioMixer::clear() {
41c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    memset(mOutputBuffer, 0, mBufferSizeInBytes);
42c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
43c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
4471f35bb687476694882a617ba4a810a0bb56fe23Phil Burkbool AAudioMixer::mix(FifoBuffer *fifo, float volume) {
45c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    WrappingBuffer wrappingBuffer;
46c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    float *destination = mOutputBuffer;
47c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    fifo_frames_t framesLeft = mFramesPerBurst;
48c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
49c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    // Gather the data from the client. May be in two parts.
50c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    fifo->getFullDataAvailable(&wrappingBuffer);
51c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
52c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    // Mix data in one or two parts.
53c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    int partIndex = 0;
54c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
55c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        fifo_frames_t framesToMix = framesLeft;
56c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
57c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        if (framesAvailable > 0) {
58c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            if (framesToMix > framesAvailable) {
59c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                framesToMix = framesAvailable;
60c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            }
61c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume);
62c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
63c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            destination += framesToMix * mSamplesPerFrame;
64c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            framesLeft -= framesToMix;
65c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        }
66c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        partIndex++;
67c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
68c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst - framesLeft);
69c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    if (framesLeft > 0) {
7071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        //ALOGW("AAudioMixer::mix() UNDERFLOW by %d / %d frames ----- UNDERFLOW !!!!!!!!!!",
7171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        //      framesLeft, mFramesPerBurst);
72c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
7371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
74c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
75c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
76c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkvoid AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) {
77c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    int32_t numSamples = numFrames * mSamplesPerFrame;
78c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    // TODO maybe optimize using SIMD
79c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
80c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        *destination++ += *source++ * volume;
81c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
82c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
83c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
84c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkfloat *AAudioMixer::getOutputBuffer() {
85c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return mOutputBuffer;
86c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
87