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

Commit d8bdcabb authored by Phil Burk's avatar Phil Burk
Browse files

liboboe: general cleanup of core code, register threads



Simplify audio format.
Cleaner includes.
Some debug printing.
Add registration of audio threads with server.

Bug: 33347409
Test: test_oboe_api
Change-Id: I342eb745830d6623681ce55cb510513e7c5e2ead
Signed-off-by: default avatarPhil Burk <philburk@google.com>
parent 1acece4c
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@
extern "C" {
#endif

typedef int32_t OboeDeviceId;
typedef oboe_handle_t OboeStream;
typedef oboe_handle_t OboeStreamBuilder;

@@ -92,10 +91,18 @@ OBOE_API oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder);
 *
 * By default, the primary device will be used.
 *
 * @param builder handle provided by Oboe_createStreamBuilder()
 * @param deviceId platform specific identifier or OBOE_DEVICE_UNSPECIFIED
 * @return OBOE_OK or a negative error.
 */
OBOE_API oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder,
                                                     OboeDeviceId deviceId);
                                                     oboe_device_id_t deviceId);
/**
 * Passes back requested device ID.
 * @return OBOE_OK or a negative error.
 */
OBOE_API oboe_result_t OboeStreamBuilder_getDeviceId(OboeStreamBuilder builder,
                                                     oboe_device_id_t *deviceId);

/**
 * Request a sample rate in Hz.
@@ -362,6 +369,8 @@ OBOE_API oboe_result_t OboeStream_write(OboeStream stream,
// High priority audio threads
// ============================================================

typedef void *(oboe_audio_thread_proc_t)(void *);

/**
 * Create a thread associated with a stream. The thread has special properties for
 * low latency audio performance. This thread can be used to implement a callback API.
@@ -378,7 +387,8 @@ OBOE_API oboe_result_t OboeStream_write(OboeStream stream,
 */
OBOE_API oboe_result_t OboeStream_createThread(OboeStream stream,
                                     oboe_nanoseconds_t periodNanoseconds,
                                     void *(*startRoutine)(void *), void *arg);
                                     oboe_audio_thread_proc_t *threadProc,
                                     void *arg);

/**
 * Wait until the thread exits or an error occurs.
@@ -473,6 +483,13 @@ OBOE_API oboe_result_t OboeStream_getSampleRate(OboeStream stream, oboe_sample_r
 */
OBOE_API oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame);

/**
 * @param stream handle provided by OboeStreamBuilder_openStream()
 * @param deviceId pointer to variable to receive the actual device ID
 * @return OBOE_OK or a negative error.
 */
OBOE_API oboe_result_t OboeStream_getDeviceId(OboeStream stream, oboe_device_id_t *deviceId);

/**
 * @param stream handle provided by OboeStreamBuilder_openStream()
 * @param format pointer to variable to receive the actual data format
@@ -554,4 +571,4 @@ OBOE_API oboe_result_t OboeStream_getTimestamp(OboeStream stream,
}
#endif

#endif //NATIVEOBOE_OBOEAUDIO_H
#endif //OBOE_OBOEAUDIO_H
+12 −53
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@ extern "C" {

typedef int32_t  oboe_handle_t; // negative handles are error codes
typedef int32_t  oboe_result_t;
/**
 * A platform specific identifier for a device.
 */
typedef int32_t  oboe_device_id_t;
typedef int32_t  oboe_sample_rate_t;
/** This is used for small quantities such as the number of frames in a buffer. */
typedef int32_t  oboe_size_frames_t;
@@ -38,7 +42,6 @@ typedef int32_t oboe_size_bytes_t;
typedef int64_t  oboe_position_frames_t;

typedef int64_t  oboe_nanoseconds_t;
typedef uint32_t oboe_audio_format_t;

/**
 * This is used to represent a value that has not been specified.
@@ -47,6 +50,7 @@ typedef uint32_t oboe_audio_format_t;
 * and would accept whatever it was given.
 */
#define OBOE_UNSPECIFIED           0
#define OBOE_DEVICE_UNSPECIFIED    ((oboe_device_id_t) -1)
#define OBOE_NANOS_PER_MICROSECOND ((int64_t)1000)
#define OBOE_NANOS_PER_MILLISECOND (OBOE_NANOS_PER_MICROSECOND * 1000)
#define OBOE_MILLIS_PER_SECOND     1000
@@ -60,60 +64,15 @@ enum oboe_direction_t {
    OBOE_DIRECTION_COUNT // This should always be last.
};

enum oboe_datatype_t {
    OBOE_AUDIO_DATATYPE_INT16,
    OBOE_AUDIO_DATATYPE_INT32,
    OBOE_AUDIO_DATATYPE_INT824,
    OBOE_AUDIO_DATATYPE_UINT8,
    OBOE_AUDIO_DATATYPE_FLOAT32, // Add new values below.
    OBOE_AUDIO_DATATYPE_COUNT // This should always be last.
};

enum oboe_content_t {
    OBOE_AUDIO_CONTENT_PCM,
    OBOE_AUDIO_CONTENT_MP3,
    OBOE_AUDIO_CONTENT_AAC,
    OBOE_AUDIO_CONTENT_AC3,
    OBOE_AUDIO_CONTENT_EAC3,
    OBOE_AUDIO_CONTENT_DTS,
    OBOE_AUDIO_CONTENT_DTSHD, // Add new values below.
    OBOE_AUDIO_CONTENT_COUNT // This should always be last.
};

enum oboe_wrapper_t {
    OBOE_AUDIO_WRAPPER_NONE,
    OBOE_AUDIO_WRAPPER_IEC61937, // Add new values below.
    OBOE_AUDIO_WRAPPER_COUNT // This should always be last.
enum oboe_audio_format_t {
    OBOE_AUDIO_FORMAT_INVALID = -1,
    OBOE_AUDIO_FORMAT_UNSPECIFIED = 0,
    OBOE_AUDIO_FORMAT_PCM16, // TODO rename to _PCM_I16
    OBOE_AUDIO_FORMAT_PCM_FLOAT,
    OBOE_AUDIO_FORMAT_PCM824, // TODO rename to _PCM_I8_24
    OBOE_AUDIO_FORMAT_PCM32  // TODO rename to _PCM_I32
};

/**
 * Fields packed into oboe_audio_format_t, from most to least significant bits.
 *   Invalid:1
 *   Reserved:7
 *   Wrapper:8
 *   Content:8
 *   Data Type:8
 */
#define OBOE_AUDIO_FORMAT(dataType, content, wrapper) \
    ((oboe_audio_format_t)((wrapper << 16) | (content << 8) | dataType))

#define OBOE_AUDIO_FORMAT_RAW(dataType, content) \
                OBOE_AUDIO_FORMAT(dataType, content, OBOE_AUDIO_WRAPPER_NONE)

#define OBOE_AUDIO_FORMAT_DATA_TYPE(format) \
    ((oboe_datatype_t)(format & 0x0FF))

// Define some common formats.
#define OBOE_AUDIO_FORMAT_PCM16  \
                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT16, OBOE_AUDIO_CONTENT_PCM)
#define OBOE_AUDIO_FORMAT_PCM_FLOAT \
                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_FLOAT32, OBOE_AUDIO_CONTENT_PCM)
#define OBOE_AUDIO_FORMAT_PCM824 \
                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT824, OBOE_AUDIO_CONTENT_PCM)
#define OBOE_AUDIO_FORMAT_PCM32 \
                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT32, OBOE_AUDIO_CONTENT_PCM)
#define OBOE_AUDIO_FORMAT_INVALID ((oboe_audio_format_t)-1)

enum {
    OBOE_OK,
    OBOE_ERROR_BASE = -900, // TODO review
+39 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <atomic>
#include <stdint.h>
#include <oboe/OboeAudio.h>

@@ -27,10 +28,10 @@

using namespace oboe;

/*
 * AudioStream
 */
AudioStream::AudioStream() {
    // mThread is a pthread_t of unknown size so we need memset.
    memset(&mThread, 0, sizeof(mThread));
    setPeriodNanoseconds(0);
}

oboe_result_t AudioStream::open(const AudioStreamBuilder& builder)
@@ -91,23 +92,51 @@ oboe_result_t AudioStream::waitForStateChange(oboe_stream_state_t currentState,

        state = getState();
    }
    if (nextState != NULL) {
    if (nextState != nullptr) {
        *nextState = state;
    }
    return (state == currentState) ? OBOE_ERROR_TIMEOUT : OBOE_OK;
}

// This registers the app's background audio thread with the server before
// passing control to the app. This gives the server an opportunity to boost
// the thread's performance characteristics.
void* AudioStream::wrapUserThread() {
    void* procResult = nullptr;
    mThreadRegistrationResult = registerThread();
    if (mThreadRegistrationResult == OBOE_OK) {
        // Call application procedure. This may take a very long time.
        procResult = mThreadProc(mThreadArg);
        ALOGD("AudioStream::mThreadProc() returned");
        mThreadRegistrationResult = unregisterThread();
    }
    return procResult;
}

// This is the entry point for the new thread created by createThread().
// It converts the 'C' function call to a C++ method call.
static void* AudioStream_internalThreadProc(void* threadArg) {
    AudioStream *audioStream = (AudioStream *) threadArg;
    return audioStream->wrapUserThread();
}

oboe_result_t AudioStream::createThread(oboe_nanoseconds_t periodNanoseconds,
                                     void *(*startRoutine)(void *), void *arg)
                                     oboe_audio_thread_proc_t *threadProc,
                                     void* threadArg)
{
    if (mHasThread) {
        return OBOE_ERROR_INVALID_STATE;
    }
    if (startRoutine == NULL) {
    if (threadProc == nullptr) {
        return OBOE_ERROR_NULL;
    }
    int err = pthread_create(&mThread, NULL, startRoutine, arg);
    // Pass input parameters to the background thread.
    mThreadProc = threadProc;
    mThreadArg = threadArg;
    setPeriodNanoseconds(periodNanoseconds);
    int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
    if (err != 0) {
        // TODO convert errno to oboe_result_t
        return OBOE_ERROR_INTERNAL;
    } else {
        mHasThread = true;
@@ -128,7 +157,7 @@ oboe_result_t AudioStream::joinThread(void **returnArg, oboe_nanoseconds_t timeo
    int err = pthread_join(mThread, returnArg);
#endif
    mHasThread = false;
    // TODO Just leaked a thread?
    return err ? OBOE_ERROR_INTERNAL : OBOE_OK;
    // TODO convert errno to oboe_result_t
    return err ? OBOE_ERROR_INTERNAL : mThreadRegistrationResult;
}
+45 −7
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
#ifndef OBOE_AUDIOSTREAM_H
#define OBOE_AUDIOSTREAM_H

#include <unistd.h>
#include <sys/types.h>
#include <atomic>
#include <stdint.h>
#include <oboe/OboeDefinitions.h>
#include <oboe/OboeAudio.h>

#include "OboeUtilities.h"
#include "MonotonicCounter.h"

@@ -83,10 +85,25 @@ public:
    }

    virtual oboe_result_t createThread(oboe_nanoseconds_t periodNanoseconds,
                                     void *(*start_routine)(void *), void *arg);
                                       oboe_audio_thread_proc_t *threadProc,
                                       void *threadArg);

    virtual oboe_result_t joinThread(void **returnArg, oboe_nanoseconds_t timeoutNanoseconds);

    virtual oboe_result_t registerThread() {
        return OBOE_OK;
    }

    virtual oboe_result_t unregisterThread() {
        return OBOE_OK;
    }

    /**
     * Internal function used to call the audio thread passed by the user.
     * It is unfortunately public because it needs to be called by a static 'C' function.
     */
    void* wrapUserThread();

    // ============== Queries ===========================

    virtual oboe_stream_state_t getState() const {
@@ -125,7 +142,7 @@ public:
        return mSamplesPerFrame;
    }

    OboeDeviceId getDeviceId() const {
    oboe_device_id_t getDeviceId() const {
        return mDeviceId;
    }

@@ -220,21 +237,42 @@ protected:
        mState = state;
    }



protected:
    MonotonicCounter     mFramesWritten;
    MonotonicCounter     mFramesRead;

    void setPeriodNanoseconds(oboe_nanoseconds_t periodNanoseconds) {
        mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
    }

    oboe_nanoseconds_t getPeriodNanoseconds() {
        return mPeriodNanoseconds.load(std::memory_order_acquire);
    }

private:
    // These do not change after open().
    int32_t              mSamplesPerFrame = OBOE_UNSPECIFIED;
    oboe_sample_rate_t   mSampleRate = OBOE_UNSPECIFIED;
    oboe_stream_state_t  mState = OBOE_STREAM_STATE_UNINITIALIZED;
    OboeDeviceId         mDeviceId = OBOE_UNSPECIFIED;
    oboe_device_id_t     mDeviceId = OBOE_UNSPECIFIED;
    oboe_sharing_mode_t  mSharingMode = OBOE_SHARING_MODE_LEGACY;
    oboe_audio_format_t  mFormat = OBOE_UNSPECIFIED;
    oboe_audio_format_t  mFormat = OBOE_AUDIO_FORMAT_UNSPECIFIED;
    oboe_direction_t     mDirection = OBOE_DIRECTION_OUTPUT;

    // background thread ----------------------------------
    bool                 mHasThread = false;
    pthread_t            mThread;
    pthread_t            mThread; // initialized in constructor

    // These are set by the application thread and then read by the audio pthread.
    std::atomic<oboe_nanoseconds_t>  mPeriodNanoseconds; // for tuning SCHED_FIFO threads
    // TODO make atomic?
    oboe_audio_thread_proc_t* mThreadProc = nullptr;
    void*                mThreadArg = nullptr;
    oboe_result_t        mThreadRegistrationResult = OBOE_OK;


};

} /* namespace oboe */
+18 −9
Original line number Diff line number Diff line
@@ -18,11 +18,17 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <sys/types.h>
#include "AudioStream.h"
#include "AudioStreamBuilder.h"
#include "AudioStreamRecord.h"
#include "AudioStreamTrack.h"
#include <new>
#include <stdint.h>

#include <oboe/OboeDefinitions.h>
#include <oboe/OboeAudio.h>

#include "client/AudioStreamInternal.h"
#include "core/AudioStream.h"
#include "core/AudioStreamBuilder.h"
#include "legacy/AudioStreamRecord.h"
#include "legacy/AudioStreamTrack.h"

using namespace oboe;

@@ -43,7 +49,7 @@ oboe_result_t AudioStreamBuilder::build(AudioStream **streamPtr) {
    case OBOE_DIRECTION_INPUT:
        switch (sharingMode) {
            case OBOE_SHARING_MODE_LEGACY:
                audioStream = new AudioStreamRecord();
                audioStream = new(std::nothrow) AudioStreamRecord();
                break;
            default:
                ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
@@ -54,7 +60,10 @@ oboe_result_t AudioStreamBuilder::build(AudioStream **streamPtr) {
    case OBOE_DIRECTION_OUTPUT:
        switch (sharingMode) {
            case OBOE_SHARING_MODE_LEGACY:
                audioStream = new AudioStreamTrack();
                audioStream = new(std::nothrow) AudioStreamTrack();
                break;
            case OBOE_SHARING_MODE_EXCLUSIVE:
                audioStream = new(std::nothrow) AudioStreamInternal();
                break;
            default:
                ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
Loading