Loading media/liboboe/src/Android.mk +67 −29 Original line number Diff line number Diff line Loading @@ -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")))' Loading @@ -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) media/liboboe/src/binding/AudioEndpointParcelable.cpp 0 → 100644 +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"); } media/liboboe/src/binding/IOboeAudioService.cpp 0 → 100644 +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 */ media/liboboe/src/binding/OboeServiceDefinitions.h +16 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading media/liboboe/src/binding/OboeServiceMessage.h 0 → 100644 +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
media/liboboe/src/Android.mk +67 −29 Original line number Diff line number Diff line Loading @@ -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")))' Loading @@ -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)
media/liboboe/src/binding/AudioEndpointParcelable.cpp 0 → 100644 +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"); }
media/liboboe/src/binding/IOboeAudioService.cpp 0 → 100644 +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 */
media/liboboe/src/binding/OboeServiceDefinitions.h +16 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading
media/liboboe/src/binding/OboeServiceMessage.h 0 → 100644 +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