Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0127c1be authored by Phil Burk's avatar Phil Burk
Browse files

aaudio: use new flowgraph to simplify processing

Construct a flowgraph based on the source and destination
format and channelCount. This is groundwork for supporting 24-bit
PCM formats.

Also cleaned up handling of device related format.

This CL removes more code than it adds.

Bug: 65067568
Test: write_sine_callback.cpp -pl
Test: write_sine_callback.cpp -pl -x
Test: input_monitor -pl
Test: input_monitor -pl -x
Change-Id: Ia155bff0164912011d09b61b54f983ccf4490bd1
parent fdfae289
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -26,9 +26,9 @@ cc_library {
        "utility/FixedBlockAdapter.cpp",
        "utility/FixedBlockReader.cpp",
        "utility/FixedBlockWriter.cpp",
        "utility/LinearRamp.cpp",
        "fifo/FifoBuffer.cpp",
        "fifo/FifoControllerBase.cpp",
        "client/AAudioFlowGraph.cpp",
        "client/AudioEndpoint.cpp",
        "client/AudioStreamInternal.cpp",
        "client/AudioStreamInternalCapture.cpp",
+11 −3
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * limitations under the License.
 */

#define LOG_TAG "AAudioStreamConfiguration"
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <stdint.h>

#include <sys/mman.h>
@@ -36,6 +40,7 @@ AAudioStreamConfiguration::~AAudioStreamConfiguration() {}

status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
    status_t status;

    status = parcel->writeInt32(getDeviceId());
    if (status != NO_ERROR) goto error;
    status = parcel->writeInt32(getSampleRate());
@@ -46,6 +51,7 @@ status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
    if (status != NO_ERROR) goto error;
    status = parcel->writeInt32((int32_t) getFormat());
    if (status != NO_ERROR) goto error;

    status = parcel->writeInt32((int32_t) getDirection());
    if (status != NO_ERROR) goto error;
    status = parcel->writeInt32(getBufferCapacity());
@@ -60,7 +66,7 @@ status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
    if (status != NO_ERROR) goto error;
    return NO_ERROR;
error:
    ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
    ALOGE("%s(): write failed = %d", __func__, status);
    return status;
}

@@ -80,7 +86,8 @@ status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
    setSharingMode((aaudio_sharing_mode_t) value);
    status = parcel->readInt32(&value);
    if (status != NO_ERROR) goto error;
    setFormat((aaudio_format_t) value);
    setFormat((audio_format_t) value);

    status = parcel->readInt32(&value);
    if (status != NO_ERROR) goto error;
    setDirection((aaudio_direction_t) value);
@@ -99,8 +106,9 @@ status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
    status = parcel->readInt32(&value);
    if (status != NO_ERROR) goto error;
    setSessionId(value);

    return NO_ERROR;
error:
    ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
    ALOGE("%s(): read failed = %d", __func__, status);
    return status;
}
+3 −2
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ SharedMemoryParcelable::~SharedMemoryParcelable() {};

void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
    mFd.reset(dup(fd.get())); // store a duplicate fd
    ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
    ALOGV("setup(fd = %d -> %d, size = %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
    mSizeInBytes = sizeInBytes;
}

@@ -104,7 +104,8 @@ aaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd)
    mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
                                        MAP_SHARED, fd.get(), 0);
    if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
        ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
        ALOGE("mmap() failed for fd = %d, nBytes = %d, errno = %s",
              fd.get(), mSizeInBytes, strerror(errno));
        return AAUDIO_ERROR_INTERNAL;
    }
    return AAUDIO_OK;
+116 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "AAudioFlowGraph"
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include "AAudioFlowGraph.h"

#include <flowgraph/ClipToRange.h>
#include <flowgraph/MonoToMultiConverter.h>
#include <flowgraph/RampLinear.h>
#include <flowgraph/SinkFloat.h>
#include <flowgraph/SinkI16.h>
#include <flowgraph/SinkI24.h>
#include <flowgraph/SourceFloat.h>
#include <flowgraph/SourceI16.h>
#include <flowgraph/SourceI24.h>

using namespace flowgraph;

aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat,
                          int32_t sourceChannelCount,
                          audio_format_t sinkFormat,
                          int32_t sinkChannelCount) {
    AudioFloatOutputPort *lastOutput = nullptr;

    ALOGD("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
          __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);

    switch (sourceFormat) {
        case AUDIO_FORMAT_PCM_FLOAT:
            mSource = std::make_unique<SourceFloat>(sourceChannelCount);
            break;
        case AUDIO_FORMAT_PCM_16_BIT:
            mSource = std::make_unique<SourceI16>(sourceChannelCount);
            break;
        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
            mSource = std::make_unique<SourceI24>(sourceChannelCount);
            break;
        default: // TODO add I32
            ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
            return AAUDIO_ERROR_UNIMPLEMENTED;
    }
    lastOutput = &mSource->output;

    // Apply volume as a ramp to avoid pops.
    mVolumeRamp = std::make_unique<RampLinear>(sourceChannelCount);
    lastOutput->connect(&mVolumeRamp->input);
    lastOutput = &mVolumeRamp->output;

    // For a pure float graph, there is chance that the data range may be very large.
    // So we should clip to a reasonable value that allows a little headroom.
    if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) {
        mClipper = std::make_unique<ClipToRange>(sourceChannelCount);
        lastOutput->connect(&mClipper->input);
        lastOutput = &mClipper->output;
    }

    // Expand the number of channels if required.
    if (sourceChannelCount == 1 && sinkChannelCount > 1) {
        mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
        lastOutput->connect(&mChannelConverter->input);
        lastOutput = &mChannelConverter->output;
    } else if (sourceChannelCount != sinkChannelCount) {
        ALOGE("%s() Channel reduction not supported.", __func__);
        return AAUDIO_ERROR_UNIMPLEMENTED;
    }

    switch (sinkFormat) {
        case AUDIO_FORMAT_PCM_FLOAT:
            mSink = std::make_unique<SinkFloat>(sinkChannelCount);
            break;
        case AUDIO_FORMAT_PCM_16_BIT:
            mSink = std::make_unique<SinkI16>(sinkChannelCount);
            break;
        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
            mSink = std::make_unique<SinkI24>(sinkChannelCount);
            break;
        default: // TODO add I32
            ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
            return AAUDIO_ERROR_UNIMPLEMENTED;
    }
    lastOutput->connect(&mSink->input);

    return AAUDIO_OK;
}

void AAudioFlowGraph::process(const void *source, void *destination, int32_t numFrames) {
    mSource->setData(source, numFrames);
    mSink->read(destination, numFrames);
}

/**
 * @param volume between 0.0 and 1.0
 */
void AAudioFlowGraph::setTargetVolume(float volume) {
    mVolumeRamp->setTarget(volume);
}

void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
    mVolumeRamp->setLengthInFrames(numFrames);
}
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_AAUDIO_FLOW_GRAPH_H
#define ANDROID_AAUDIO_FLOW_GRAPH_H

#include <memory>
#include <stdint.h>
#include <sys/types.h>
#include <system/audio.h>

#include <aaudio/AAudio.h>
#include <flowgraph/ClipToRange.h>
#include <flowgraph/MonoToMultiConverter.h>
#include <flowgraph/RampLinear.h>

class AAudioFlowGraph {
public:
    /** Connect several modules together to convert from source to sink.
     * This should only be called once for each instance.
     *
     * @param sourceFormat
     * @param sourceChannelCount
     * @param sinkFormat
     * @param sinkChannelCount
     * @return
     */
    aaudio_result_t configure(audio_format_t sourceFormat,
                              int32_t sourceChannelCount,
                              audio_format_t sinkFormat,
                              int32_t sinkChannelCount);

    void process(const void *source, void *destination, int32_t numFrames);

    /**
     * @param volume between 0.0 and 1.0
     */
    void setTargetVolume(float volume);

    void setRampLengthInFrames(int32_t numFrames);

private:
    std::unique_ptr<flowgraph::AudioSource>          mSource;
    std::unique_ptr<flowgraph::RampLinear>           mVolumeRamp;
    std::unique_ptr<flowgraph::ClipToRange>          mClipper;
    std::unique_ptr<flowgraph::MonoToMultiConverter> mChannelConverter;
    std::unique_ptr<flowgraph::AudioSink>            mSink;
};


#endif //ANDROID_AAUDIO_FLOW_GRAPH_H
Loading