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

Commit 7a667f66 authored by Phil Burk's avatar Phil Burk Committed by Android (Google) Code Review
Browse files

Merge "liboboe: oboe MMAP client interface"

parents d8bdcabb 204a163c
Loading
Loading
Loading
Loading
+67 −29
Original line number Diff line number Diff line
@@ -8,28 +8,49 @@ include $(CLEAR_VARS)
LOCAL_MODULE := liboboe
LOCAL_MODULE_TAGS := optional

LIBOBOE_DIR := $(TOP)/frameworks/av/media/liboboe
LIBOBOE_SRC_DIR := $(LIBOBOE_DIR)/src

LOCAL_C_INCLUDES := \
    $(call include-path-for, audio-utils) \
    frameworks/native/include \
    system/core/base/include \
    frameworks/native/media/liboboe/include/include \
    frameworks/av/media/liboboe/include \
    frameworks/native/include \
    $(LOCAL_PATH) \
    $(LOCAL_PATH)/binding \
    $(LOCAL_PATH)/client \
    $(LOCAL_PATH)/core \
    $(LOCAL_PATH)/utility \
    $(LOCAL_PATH)/legacy

LOCAL_SRC_FILES += core/AudioStream.cpp
LOCAL_SRC_FILES += core/AudioStreamBuilder.cpp
LOCAL_SRC_FILES += core/OboeAudio.cpp
LOCAL_SRC_FILES += legacy/AudioStreamRecord.cpp
LOCAL_SRC_FILES += legacy/AudioStreamTrack.cpp
LOCAL_SRC_FILES += utility/HandleTracker.cpp
LOCAL_SRC_FILES += utility/OboeUtilities.cpp

LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror
    $(LOCAL_PATH)/fifo \
    $(LOCAL_PATH)/legacy \
    $(LOCAL_PATH)/utility

LOCAL_SRC_FILES = \
    core/AudioStream.cpp \
    core/AudioStreamBuilder.cpp \
    core/OboeAudio.cpp \
    legacy/AudioStreamRecord.cpp \
    legacy/AudioStreamTrack.cpp \
    utility/HandleTracker.cpp \
    utility/OboeUtilities.cpp \
    fifo/FifoBuffer.cpp \
    fifo/FifoControllerBase.cpp \
    client/AudioEndpoint.cpp \
    client/AudioStreamInternal.cpp \
    client/IsochronousClockModel.cpp \
    binding/SharedMemoryParcelable.cpp \
    binding/SharedRegionParcelable.cpp \
    binding/RingBufferParcelable.cpp \
    binding/AudioEndpointParcelable.cpp \
    binding/OboeStreamRequest.cpp \
    binding/OboeStreamConfiguration.cpp \
    binding/IOboeAudioService.cpp

LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror

# By default, all symbols are hidden.
LOCAL_CFLAGS += -fvisibility=hidden
# LOCAL_CFLAGS += -fvisibility=hidden
# OBOE_API is used to explicitly export a function or a variable as a visible symbol.
LOCAL_CFLAGS += -DOBOE_API='__attribute__((visibility("default")))'

@@ -47,24 +68,41 @@ LOCAL_C_INCLUDES := \
    system/core/base/include \
    frameworks/native/media/liboboe/include/include \
    frameworks/av/media/liboboe/include \
    $(LOCAL_PATH) \
    $(LOCAL_PATH)/binding \
    $(LOCAL_PATH)/client \
    $(LOCAL_PATH)/core \
    $(LOCAL_PATH)/utility \
    $(LOCAL_PATH)/legacy

LOCAL_SRC_FILES += core/AudioStream.cpp
LOCAL_SRC_FILES += core/AudioStreamBuilder.cpp
LOCAL_SRC_FILES += core/OboeAudio.cpp
LOCAL_SRC_FILES += legacy/AudioStreamRecord.cpp
LOCAL_SRC_FILES += legacy/AudioStreamTrack.cpp
LOCAL_SRC_FILES += utility/HandleTracker.cpp
LOCAL_SRC_FILES += utility/OboeUtilities.cpp

LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror
    $(LOCAL_PATH)/fifo \
    $(LOCAL_PATH)/legacy \
    $(LOCAL_PATH)/utility

LOCAL_SRC_FILES = core/AudioStream.cpp \
    core/AudioStreamBuilder.cpp \
    core/OboeAudio.cpp \
    legacy/AudioStreamRecord.cpp \
    legacy/AudioStreamTrack.cpp \
    utility/HandleTracker.cpp \
    utility/OboeUtilities.cpp \
    fifo/FifoBuffer.cpp \
    fifo/FifoControllerBase.cpp \
    client/AudioEndpoint.cpp \
    client/AudioStreamInternal.cpp \
    client/IsochronousClockModel.cpp \
    binding/SharedMemoryParcelable.cpp \
    binding/SharedRegionParcelable.cpp \
    binding/RingBufferParcelable.cpp \
    binding/AudioEndpointParcelable.cpp \
    binding/OboeStreamRequest.cpp \
    binding/OboeStreamConfiguration.cpp \
    binding/IOboeAudioService.cpp

LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror

# By default, all symbols are hidden.
LOCAL_CFLAGS += -fvisibility=hidden
# LOCAL_CFLAGS += -fvisibility=hidden
# OBOE_API is used to explicitly export a function or a variable as a visible symbol.
LOCAL_CFLAGS += -DOBOE_API='__attribute__((visibility("default")))'

LOCAL_SHARED_LIBRARIES := libaudioclient liblog libutils
LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder

include $(BUILD_SHARED_LIBRARY)
+141 −0
Original line number Diff line number Diff line
/*
 * Copyright 2016 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.
 */

#include <stdint.h>

#include <sys/mman.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>

#include "binding/OboeServiceDefinitions.h"
#include "binding/RingBufferParcelable.h"
#include "binding/AudioEndpointParcelable.h"

using android::NO_ERROR;
using android::status_t;
using android::Parcel;
using android::Parcelable;

using namespace oboe;

/**
 * Container for information about the message queues plus
 * general stream information needed by Oboe clients.
 * It contains no addresses, just sizes, offsets and file descriptors for
 * shared memory that can be passed through Binder.
 */
AudioEndpointParcelable::AudioEndpointParcelable() {}

AudioEndpointParcelable::~AudioEndpointParcelable() {}

/**
 * Add the file descriptor to the table.
 * @return index in table or negative error
 */
int32_t AudioEndpointParcelable::addFileDescriptor(int fd, int32_t sizeInBytes) {
    if (mNumSharedMemories >= MAX_SHARED_MEMORIES) {
        return OBOE_ERROR_OUT_OF_RANGE;
    }
    int32_t index = mNumSharedMemories++;
    mSharedMemories[index].setup(fd, sizeInBytes);
    return index;
}

/**
 * The read and write must be symmetric.
 */
status_t AudioEndpointParcelable::writeToParcel(Parcel* parcel) const {
    parcel->writeInt32(mNumSharedMemories);
    for (int i = 0; i < mNumSharedMemories; i++) {
        mSharedMemories[i].writeToParcel(parcel);
    }
    mUpMessageQueueParcelable.writeToParcel(parcel);
    mDownMessageQueueParcelable.writeToParcel(parcel);
    mUpDataQueueParcelable.writeToParcel(parcel);
    mDownDataQueueParcelable.writeToParcel(parcel);
    return NO_ERROR; // TODO check for errors above
}

status_t AudioEndpointParcelable::readFromParcel(const Parcel* parcel) {
    parcel->readInt32(&mNumSharedMemories);
    for (int i = 0; i < mNumSharedMemories; i++) {
        mSharedMemories[i].readFromParcel(parcel);
    }
    mUpMessageQueueParcelable.readFromParcel(parcel);
    mDownMessageQueueParcelable.readFromParcel(parcel);
    mUpDataQueueParcelable.readFromParcel(parcel);
    mDownDataQueueParcelable.readFromParcel(parcel);
    return NO_ERROR; // TODO check for errors above
}

oboe_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
    // TODO error check
    mUpMessageQueueParcelable.resolve(mSharedMemories, &descriptor->upMessageQueueDescriptor);
    mDownMessageQueueParcelable.resolve(mSharedMemories,
                                        &descriptor->downMessageQueueDescriptor);
    mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
    mDownDataQueueParcelable.resolve(mSharedMemories, &descriptor->downDataQueueDescriptor);
    return OBOE_OK;
}

oboe_result_t AudioEndpointParcelable::validate() {
    oboe_result_t result;
    if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
        ALOGE("AudioEndpointParcelable invalid mNumSharedMemories = %d", mNumSharedMemories);
        return OBOE_ERROR_INTERNAL;
    }
    for (int i = 0; i < mNumSharedMemories; i++) {
        result = mSharedMemories[i].validate();
        if (result != OBOE_OK) {
            return result;
        }
    }
    if ((result = mUpMessageQueueParcelable.validate()) != OBOE_OK) {
        ALOGE("AudioEndpointParcelable invalid mUpMessageQueueParcelable = %d", result);
        return result;
    }
    if ((result = mDownMessageQueueParcelable.validate()) != OBOE_OK) {
        ALOGE("AudioEndpointParcelable invalid mDownMessageQueueParcelable = %d", result);
        return result;
    }
    if ((result = mUpDataQueueParcelable.validate()) != OBOE_OK) {
        ALOGE("AudioEndpointParcelable invalid mUpDataQueueParcelable = %d", result);
        return result;
    }
    if ((result = mDownDataQueueParcelable.validate()) != OBOE_OK) {
        ALOGE("AudioEndpointParcelable invalid mDownDataQueueParcelable = %d", result);
        return result;
    }
    return OBOE_OK;
}

void AudioEndpointParcelable::dump() {
    ALOGD("AudioEndpointParcelable ======================================= BEGIN");
    ALOGD("AudioEndpointParcelable mNumSharedMemories = %d", mNumSharedMemories);
    for (int i = 0; i < mNumSharedMemories; i++) {
        mSharedMemories[i].dump();
    }
    ALOGD("AudioEndpointParcelable mUpMessageQueueParcelable =========");
    mUpMessageQueueParcelable.dump();
    ALOGD("AudioEndpointParcelable mDownMessageQueueParcelable =======");
    mDownMessageQueueParcelable.dump();
    ALOGD("AudioEndpointParcelable mUpDataQueueParcelable ============");
    mUpDataQueueParcelable.dump();
    ALOGD("AudioEndpointParcelable mDownDataQueueParcelable ==========");
    mDownDataQueueParcelable.dump();
    ALOGD("AudioEndpointParcelable ======================================= END");
}
+296 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */

#include <oboe/OboeDefinitions.h>

#include "binding/AudioEndpointParcelable.h"
#include "binding/OboeStreamRequest.h"
#include "binding/OboeStreamConfiguration.h"
#include "binding/IOboeAudioService.h"

namespace android {

/**
 * This is used by the Oboe Client to talk to the Oboe Service.
 *
 * The order of parameters in the Parcels must match with code in OboeAudioService.cpp.
 */
class BpOboeAudioService : public BpInterface<IOboeAudioService>
{
public:
    explicit BpOboeAudioService(const sp<IBinder>& impl)
        : BpInterface<IOboeAudioService>(impl)
    {
    }

    virtual oboe_handle_t openStream(oboe::OboeStreamRequest &request,
                                     oboe::OboeStreamConfiguration &configuration) override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        request.writeToParcel(&data);
        status_t err = remote()->transact(OPEN_STREAM, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_handle_t stream;
        reply.readInt32(&stream);
        configuration.readFromParcel(&reply);
        return stream;
    }

    virtual oboe_result_t closeStream(int32_t streamHandle) override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

    virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
                                               AudioEndpointParcelable &parcelable)   {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        parcelable.readFromParcel(&reply);
        parcelable.dump();
        oboe_result_t result = parcelable.validate();
        if (result != OBOE_OK) {
            return result;
        }
        reply.readInt32(&result);
        return result;
    }

    // TODO should we wait for a reply?
    virtual oboe_result_t startStream(oboe_handle_t streamHandle) override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        status_t err = remote()->transact(START_STREAM, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

    virtual oboe_result_t pauseStream(oboe_handle_t streamHandle) override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        status_t err = remote()->transact(PAUSE_STREAM, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

    virtual oboe_result_t flushStream(oboe_handle_t streamHandle) override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        status_t err = remote()->transact(FLUSH_STREAM, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

    virtual void tickle() override { // TODO remove after service thread implemented
        Parcel data;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        remote()->transact(TICKLE, data, nullptr);
    }

    virtual oboe_result_t registerAudioThread(oboe_handle_t streamHandle, pid_t clientThreadId,
                                              oboe_nanoseconds_t periodNanoseconds)
    override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        data.writeInt32((int32_t) clientThreadId);
        data.writeInt64(periodNanoseconds);
        status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

    virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle, pid_t clientThreadId)
    override {
        Parcel data, reply;
        // send command
        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
        data.writeInt32(streamHandle);
        data.writeInt32((int32_t) clientThreadId);
        status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
        if (err != NO_ERROR) {
            return OBOE_ERROR_INTERNAL; // TODO consider another error
        }
        // parse reply
        oboe_result_t res;
        reply.readInt32(&res);
        return res;
    }

};

// Implement an interface to the service.
// This is here so that you don't have to link with liboboe static library.
IMPLEMENT_META_INTERFACE(OboeAudioService, "IOboeAudioService");

// The order of parameters in the Parcels must match with code in BpOboeAudioService

status_t BnOboeAudioService::onTransact(uint32_t code, const Parcel& data,
                                        Parcel* reply, uint32_t flags) {
    OboeStream stream;
    OboeStreamRequest request;
    OboeStreamConfiguration configuration;
    pid_t pid;
    oboe_nanoseconds_t nanoseconds;
    oboe_result_t result;
    ALOGV("BnOboeAudioService::onTransact(%i) %i", code, flags);
    data.checkInterface(this);

    switch(code) {
        case OPEN_STREAM: {
            request.readFromParcel(&data);
            stream = openStream(request, configuration);
            ALOGD("BnOboeAudioService::onTransact OPEN_STREAM 0x%08X", stream);
            reply->writeInt32(stream);
            configuration.writeToParcel(reply);
            return NO_ERROR;
        } break;

        case CLOSE_STREAM: {
            data.readInt32(&stream);
            ALOGD("BnOboeAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
            result = closeStream(stream);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case GET_STREAM_DESCRIPTION: {
            data.readInt32(&stream);
            ALOGD("BnOboeAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", stream);
            oboe::AudioEndpointParcelable parcelable;
            result = getStreamDescription(stream, parcelable);
            if (result != OBOE_OK) {
                return -1; // FIXME
            }
            parcelable.dump();
            result = parcelable.validate();
            if (result != OBOE_OK) {
                return -1; // FIXME
            }
            parcelable.writeToParcel(reply);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case START_STREAM: {
            data.readInt32(&stream);
            result = startStream(stream);
            ALOGD("BnOboeAudioService::onTransact START_STREAM 0x%08X, result = %d",
                    stream, result);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case PAUSE_STREAM: {
            data.readInt32(&stream);
            result = pauseStream(stream);
            ALOGD("BnOboeAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
                    stream, result);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case FLUSH_STREAM: {
            data.readInt32(&stream);
            result = flushStream(stream);
            ALOGD("BnOboeAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
                    stream, result);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case REGISTER_AUDIO_THREAD: {
            data.readInt32(&stream);
            data.readInt32(&pid);
            data.readInt64(&nanoseconds);
            result = registerAudioThread(stream, pid, nanoseconds);
            ALOGD("BnOboeAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
                    stream, result);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case UNREGISTER_AUDIO_THREAD: {
            data.readInt32(&stream);
            data.readInt32(&pid);
            result = unregisterAudioThread(stream, pid);
            ALOGD("BnOboeAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
                    stream, result);
            reply->writeInt32(result);
            return NO_ERROR;
        } break;

        case TICKLE: {
            ALOGV("BnOboeAudioService::onTransact TICKLE");
            tickle();
            return NO_ERROR;
        } break;

        default:
            // ALOGW("BnOboeAudioService::onTransact not handled %u", code);
            return BBinder::onTransact(code, data, reply, flags);
    }
}

} /* namespace android */
+16 −0
Original line number Diff line number Diff line
@@ -27,6 +27,22 @@
using android::NO_ERROR;
using android::IBinder;

namespace android {

enum oboe_commands_t {
    OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
    CLOSE_STREAM,
    GET_STREAM_DESCRIPTION,
    START_STREAM,
    PAUSE_STREAM,
    FLUSH_STREAM,
    REGISTER_AUDIO_THREAD,
    UNREGISTER_AUDIO_THREAD,
    TICKLE
};

} // namespace android

namespace oboe {

enum oboe_commands_t {
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 OBOE_OBOE_SERVICE_MESSAGE_H
#define OBOE_OBOE_SERVICE_MESSAGE_H

#include <stdint.h>

#include <oboe/OboeDefinitions.h>

namespace oboe {

// TODO move this an "include" folder for the service.

struct OboeMessageTimestamp {
    oboe_position_frames_t position;
    int64_t                deviceOffset; // add to client position to get device position
    oboe_nanoseconds_t     timestamp;
};

typedef enum oboe_service_event_e : uint32_t {
    OBOE_SERVICE_EVENT_STARTED,
    OBOE_SERVICE_EVENT_PAUSED,
    OBOE_SERVICE_EVENT_FLUSHED,
    OBOE_SERVICE_EVENT_CLOSED,
    OBOE_SERVICE_EVENT_DISCONNECTED
} oboe_service_event_t;

struct OboeMessageEvent {
    oboe_service_event_t event;
    int32_t data1;
    int64_t data2;
};

typedef struct OboeServiceMessage_s {
    enum class code : uint32_t {
        NOTHING,
        TIMESTAMP,
        EVENT,
    };

    code what;
    union {
        OboeMessageTimestamp timestamp;
        OboeMessageEvent event;
    };
} OboeServiceMessage;


} /* namespace oboe */

#endif //OBOE_OBOE_SERVICE_MESSAGE_H
Loading