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

Commit 7f6b40d7 authored by Phil Burk's avatar Phil Burk
Browse files

AAudioService: integrated with audioserver



Call the MmapStreamInterface from AudioFlinger instead of the FakeHAL.
Fix sending timestamps from the thread.
Add shared mode in service.

Bug: 35260844
Test: CTS test_aaudio.cpp
Change-Id: I44c7e4ecae4ce205611b6b73a72e0ae8a5b243e5
Signed-off-by: default avatarPhil Burk <philburk@google.com>
parent a2e1b6df
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES := \
	main_audioserver.cpp
	main_audioserver.cpp


LOCAL_SHARED_LIBRARIES := \
LOCAL_SHARED_LIBRARIES := \
	libaaudioservice \
	libaudioflinger \
	libaudioflinger \
	libaudiopolicyservice \
	libaudiopolicyservice \
	libbinder \
	libbinder \
@@ -18,6 +19,7 @@ LOCAL_SHARED_LIBRARIES := \
	libutils \
	libutils \
	libhwbinder
	libhwbinder


# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES := \
	frameworks/av/services/audioflinger \
	frameworks/av/services/audioflinger \
	frameworks/av/services/audiopolicy \
	frameworks/av/services/audiopolicy \
@@ -26,8 +28,12 @@ LOCAL_C_INCLUDES := \
	frameworks/av/services/audiopolicy/engine/interface \
	frameworks/av/services/audiopolicy/engine/interface \
	frameworks/av/services/audiopolicy/service \
	frameworks/av/services/audiopolicy/service \
	frameworks/av/services/medialog \
	frameworks/av/services/medialog \
	frameworks/av/services/oboeservice \
	frameworks/av/services/radio \
	frameworks/av/services/radio \
	frameworks/av/services/soundtrigger \
	frameworks/av/services/soundtrigger \
	frameworks/av/media/libaaudio/include \
	frameworks/av/media/libaaudio/src \
	frameworks/av/media/libaaudio/src/binding \
	$(call include-path-for, audio-utils) \
	$(call include-path-for, audio-utils) \
	external/sonic \
	external/sonic \


+2 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
// from LOCAL_C_INCLUDES
// from LOCAL_C_INCLUDES
#include "AudioFlinger.h"
#include "AudioFlinger.h"
#include "AudioPolicyService.h"
#include "AudioPolicyService.h"
#include "AAudioService.h"
#include "MediaLogService.h"
#include "MediaLogService.h"
#include "RadioService.h"
#include "RadioService.h"
#include "SoundTriggerHwService.h"
#include "SoundTriggerHwService.h"
@@ -131,6 +132,7 @@ int main(int argc __unused, char **argv)
        ALOGI("ServiceManager: %p", sm.get());
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        AudioFlinger::instantiate();
        AudioPolicyService::instantiate();
        AudioPolicyService::instantiate();
        AAudioService::instantiate();
        RadioService::instantiate();
        RadioService::instantiate();
        SoundTriggerHwService::instantiate();
        SoundTriggerHwService::instantiate();
        ProcessState::self()->startThreadPool();
        ProcessState::self()->startThreadPool();
+1 −6
Original line number Original line Diff line number Diff line
# include $(call all-subdir-makefiles)
include $(call all-subdir-makefiles)

# Just include static/ for now.
LOCAL_PATH := $(call my-dir)
#include $(LOCAL_PATH)/jni/Android.mk
include $(LOCAL_PATH)/static/Android.mk
+9 −14
Original line number Original line Diff line number Diff line
@@ -4,32 +4,27 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_TAGS := tests
LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES := \
    $(call include-path-for, audio-utils) \
    $(call include-path-for, audio-utils) \
    frameworks/av/media/liboboe/include
    frameworks/av/media/libaaudio/include


LOCAL_SRC_FILES:= frameworks/av/media/liboboe/src/write_sine.cpp
# NDK recommends using this kind of relative path instead of an absolute path.
LOCAL_SHARED_LIBRARIES := libaudioutils libmedia libtinyalsa \
LOCAL_SRC_FILES:= ../src/write_sine.cpp
        libbinder libcutils libutils
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_STATIC_LIBRARIES := libsndfile
LOCAL_MODULE := write_sine_ndk
LOCAL_MODULE := write_sine_ndk
LOCAL_SHARED_LIBRARIES += liboboe_prebuilt
include $(BUILD_EXECUTABLE)
include $(BUILD_EXECUTABLE)


include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_TAGS := tests
LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES := \
    $(call include-path-for, audio-utils) \
    $(call include-path-for, audio-utils) \
    frameworks/av/media/liboboe/include
    frameworks/av/media/libaaudio/include


LOCAL_SRC_FILES:= frameworks/av/media/liboboe/src/write_sine_threaded.cpp
LOCAL_SRC_FILES:= ../src/write_sine_threaded.cpp
LOCAL_SHARED_LIBRARIES := libaudioutils libmedia libtinyalsa \
LOCAL_SHARED_LIBRARIES := libaaudio
        libbinder libcutils libutils
LOCAL_STATIC_LIBRARIES := libsndfile
LOCAL_MODULE := write_sine_threaded_ndk
LOCAL_MODULE := write_sine_threaded_ndk
LOCAL_SHARED_LIBRARIES += liboboe_prebuilt
include $(BUILD_EXECUTABLE)
include $(BUILD_EXECUTABLE)


include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_MODULE := liboboe_prebuilt
LOCAL_MODULE := libaaudio_prebuilt
LOCAL_SRC_FILES := liboboe.so
LOCAL_SRC_FILES := libaaudio.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(PREBUILT_SHARED_LIBRARY)
+103 −34
Original line number Original line Diff line number Diff line
@@ -16,7 +16,8 @@


// Play sine waves using an AAudio background thread.
// Play sine waves using an AAudio background thread.


#include <assert.h>
//#include <assert.h>
#include <atomic>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
@@ -25,14 +26,14 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudio.h>
#include "SineGenerator.h"
#include "SineGenerator.h"


#define NUM_SECONDS           10
#define NUM_SECONDS           5
#define NANOS_PER_MICROSECOND ((int64_t)1000)
#define NANOS_PER_MICROSECOND ((int64_t)1000)
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define MILLIS_PER_SECOND     1000
#define MILLIS_PER_SECOND     1000
#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)


//#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
#define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
//#define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED


// Prototype for a callback.
// Prototype for a callback.
typedef int audio_callback_proc_t(float *outputBuffer,
typedef int audio_callback_proc_t(float *outputBuffer,
@@ -41,6 +42,16 @@ typedef int audio_callback_proc_t(float *outputBuffer,


static void *SimpleAAudioPlayerThreadProc(void *arg);
static void *SimpleAAudioPlayerThreadProc(void *arg);


// TODO merge into common code
static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
    struct timespec time;
    int result = clock_gettime(clockId, &time);
    if (result < 0) {
        return -errno; // TODO standardize return value
    }
    return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
}

/**
/**
 * Simple wrapper for AAudio that opens a default stream and then calls
 * Simple wrapper for AAudio that opens a default stream and then calls
 * a callback function to fill the output buffers.
 * a callback function to fill the output buffers.
@@ -79,21 +90,25 @@ public:
        if (result != AAUDIO_OK) return result;
        if (result != AAUDIO_OK) return result;


        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
        AAudioStreamBuilder_setSampleRate(mBuilder, 48000);


        // Open an AAudioStream using the Builder.
        // Open an AAudioStream using the Builder.
        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
        if (result != AAUDIO_OK) goto error;
        if (result != AAUDIO_OK) goto error;


        printf("Requested sharing mode = %d\n", mRequestedSharingMode);
        printf("Actual    sharing mode = %d\n", AAudioStream_getSharingMode(mStream));

        // Check to see what kind of stream we actually got.
        // Check to see what kind of stream we actually got.
        mFramesPerSecond = AAudioStream_getSampleRate(mStream);
        mFramesPerSecond = AAudioStream_getSampleRate(mStream);
        printf("open() mFramesPerSecond = %d\n", mFramesPerSecond);
        printf("Actual    framesPerSecond = %d\n", mFramesPerSecond);


        mSamplesPerFrame = AAudioStream_getSamplesPerFrame(mStream);
        mSamplesPerFrame = AAudioStream_getSamplesPerFrame(mStream);
        printf("open() mSamplesPerFrame = %d\n", mSamplesPerFrame);
        printf("Actual    samplesPerFrame = %d\n", mSamplesPerFrame);


        {
        {
            int32_t bufferCapacity = AAudioStream_getBufferCapacityInFrames(mStream);
            int32_t bufferCapacity = AAudioStream_getBufferCapacityInFrames(mStream);
            printf("open() got bufferCapacity = %d\n", bufferCapacity);
            printf("Actual    bufferCapacity = %d\n", bufferCapacity);
        }
        }


        // This is the number of frames that are read in one chunk by a DMA controller
        // This is the number of frames that are read in one chunk by a DMA controller
@@ -104,9 +119,10 @@ public:
        while (mFramesPerBurst < 48) {
        while (mFramesPerBurst < 48) {
            mFramesPerBurst *= 2;
            mFramesPerBurst *= 2;
        }
        }
        printf("DataFormat: final framesPerBurst = %d\n",mFramesPerBurst);
        printf("Actual    framesPerBurst = %d\n",mFramesPerBurst);


        mDataFormat = AAudioStream_getFormat(mStream);
        mDataFormat = AAudioStream_getFormat(mStream);
        printf("Actual    dataFormat = %d\n", mDataFormat);


        // Allocate a buffer for the audio data.
        // Allocate a buffer for the audio data.
        mOutputBuffer = new float[mFramesPerBurst * mSamplesPerFrame];
        mOutputBuffer = new float[mFramesPerBurst * mSamplesPerFrame];
@@ -117,6 +133,7 @@ public:


        // If needed allocate a buffer for converting float to int16_t.
        // If needed allocate a buffer for converting float to int16_t.
        if (mDataFormat == AAUDIO_FORMAT_PCM_I16) {
        if (mDataFormat == AAUDIO_FORMAT_PCM_I16) {
            printf("Allocate data conversion buffer for float=>pcm16\n");
            mConversionBuffer = new int16_t[mFramesPerBurst * mSamplesPerFrame];
            mConversionBuffer = new int16_t[mFramesPerBurst * mSamplesPerFrame];
            if (mConversionBuffer == nullptr) {
            if (mConversionBuffer == nullptr) {
                fprintf(stderr, "ERROR - could not allocate conversion buffer\n");
                fprintf(stderr, "ERROR - could not allocate conversion buffer\n");
@@ -149,7 +166,7 @@ public:


    // Start a thread that will call the callback proc.
    // Start a thread that will call the callback proc.
    aaudio_result_t start() {
    aaudio_result_t start() {
        mEnabled = true;
        mEnabled.store(true);
        int64_t nanosPerBurst = mFramesPerBurst * NANOS_PER_SECOND
        int64_t nanosPerBurst = mFramesPerBurst * NANOS_PER_SECOND
                                           / mFramesPerSecond;
                                           / mFramesPerSecond;
        return AAudioStream_createThread(mStream, nanosPerBurst,
        return AAudioStream_createThread(mStream, nanosPerBurst,
@@ -159,56 +176,106 @@ public:


    // Tell the thread to stop.
    // Tell the thread to stop.
    aaudio_result_t stop() {
    aaudio_result_t stop() {
        mEnabled = false;
        mEnabled.store(false);
        return AAudioStream_joinThread(mStream, nullptr, 2 * NANOS_PER_SECOND);
        return AAudioStream_joinThread(mStream, nullptr, 2 * NANOS_PER_SECOND);
    }
    }


    bool isEnabled() const {
        return mEnabled.load();
    }

    aaudio_result_t callbackLoop() {
    aaudio_result_t callbackLoop() {
        int32_t framesWritten = 0;
        aaudio_result_t result = 0;
        int64_t framesWritten = 0;
        int32_t xRunCount = 0;
        int32_t xRunCount = 0;
        aaudio_result_t result = AAUDIO_OK;
        bool    started = false;
        int64_t framesInBuffer =
                AAudioStream_getFramesWritten(mStream) -
                AAudioStream_getFramesRead(mStream);
        int64_t framesAvailable =
                AAudioStream_getBufferSizeInFrames(mStream) - framesInBuffer;


        result = AAudioStream_requestStart(mStream);
        int64_t startTime = 0;
        if (result != AAUDIO_OK) {
        int64_t startPosition = 0;
            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
        int32_t loopCount = 0;
            return result;
        }


        // Give up after several burst periods have passed.
        // Give up after several burst periods have passed.
        const int burstsPerTimeout = 8;
        const int burstsPerTimeout = 8;
        int64_t nanosPerTimeout =
        int64_t nanosPerTimeout = 0;
                        burstsPerTimeout * mFramesPerBurst * NANOS_PER_SECOND
        int64_t runningNanosPerTimeout = 500 * NANOS_PER_MILLISECOND;
                        / mFramesPerSecond;


        while (mEnabled && result >= 0) {
        while (isEnabled() && result >= 0) {
            // Call application's callback function to fill the buffer.
            // Call application's callback function to fill the buffer.
            if (mCallbackProc(mOutputBuffer, mFramesPerBurst, mUserContext)) {
            if (mCallbackProc(mOutputBuffer, mFramesPerBurst, mUserContext)) {
                mEnabled = false;
                mEnabled.store(false);
            }
            }

            // if needed, convert from float to int16_t PCM
            // if needed, convert from float to int16_t PCM
            //printf("app callbackLoop writing %d frames, state = %s\n", mFramesPerBurst,
            //       AAudio_convertStreamStateToText(AAudioStream_getState(mStream)));
            if (mConversionBuffer != nullptr) {
            if (mConversionBuffer != nullptr) {
                int32_t numSamples = mFramesPerBurst * mSamplesPerFrame;
                int32_t numSamples = mFramesPerBurst * mSamplesPerFrame;
                for (int i = 0; i < numSamples; i++) {
                for (int i = 0; i < numSamples; i++) {
                    mConversionBuffer[i] = (int16_t)(32767.0 * mOutputBuffer[i]);
                    mConversionBuffer[i] = (int16_t)(32767.0 * mOutputBuffer[i]);
                }
                }
                // Write the application data to stream.
                // Write the application data to stream.
                result = AAudioStream_write(mStream, mConversionBuffer, mFramesPerBurst, nanosPerTimeout);
                result = AAudioStream_write(mStream, mConversionBuffer,
                                            mFramesPerBurst, nanosPerTimeout);
            } else {
            } else {
                // Write the application data to stream.
                // Write the application data to stream.
                result = AAudioStream_write(mStream, mOutputBuffer, mFramesPerBurst, nanosPerTimeout);
                result = AAudioStream_write(mStream, mOutputBuffer,
                                            mFramesPerBurst, nanosPerTimeout);
            }
            }
            framesWritten += result;

            if (result < 0) {
            if (result < 0) {
                fprintf(stderr, "ERROR - AAudioStream_write() returned %zd\n", result);
                fprintf(stderr, "ERROR - AAudioStream_write() returned %d %s\n", result,
                        AAudio_convertResultToText(result));
                break;
            } else if (started && result != mFramesPerBurst) {
                fprintf(stderr, "ERROR - AAudioStream_write() timed out! %d\n", result);
                break;
            } else {
                framesWritten += result;
            }
            }

            if (startTime > 0 && ((loopCount & 0x01FF) == 0)) {
                double elapsedFrames = (double)(framesWritten - startPosition);
                int64_t elapsedTime = getNanoseconds() - startTime;
                double measuredRate = elapsedFrames * NANOS_PER_SECOND / elapsedTime;
                printf("app callbackLoop write() measured rate %f\n", measuredRate);
            }
            }
            loopCount++;


        xRunCount = AAudioStream_getXRunCount(mStream);
            if (!started && framesWritten >= framesAvailable) {
        printf("AAudioStream_getXRunCount %d\n", xRunCount);
                // Start buffer if fully primed.{
                result = AAudioStream_requestStart(mStream);
                printf("app callbackLoop requestStart returned %d\n", result);
                if (result != AAUDIO_OK) {
                    fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n", result,
                            AAudio_convertResultToText(result));
                    mEnabled.store(false);
                    return result;
                }
                started = true;
                nanosPerTimeout = runningNanosPerTimeout;
                startPosition = framesWritten;
                startTime = getNanoseconds();
            }

            {
                int32_t tempXRunCount = AAudioStream_getXRunCount(mStream);
                if (tempXRunCount != xRunCount) {
                    xRunCount = tempXRunCount;
                    printf("AAudioStream_getXRunCount returns %d at frame %d\n",
                           xRunCount, (int) framesWritten);
                }
            }
        }


        result = AAudioStream_requestStop(mStream);
        result = AAudioStream_requestStop(mStream);
        if (result != AAUDIO_OK) {
        if (result != AAUDIO_OK) {
            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
            fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n", result,
                    AAudio_convertResultToText(result));
            return result;
            return result;
        }
        }


@@ -229,7 +296,7 @@ private:
    int32_t               mFramesPerBurst = 0;
    int32_t               mFramesPerBurst = 0;
    aaudio_audio_format_t mDataFormat = AAUDIO_FORMAT_PCM_I16;
    aaudio_audio_format_t mDataFormat = AAUDIO_FORMAT_PCM_I16;


    volatile bool         mEnabled = false; // used to request that callback exit its loop
    std::atomic<bool>     mEnabled; // used to request that callback exit its loop
};
};


static void *SimpleAAudioPlayerThreadProc(void *arg) {
static void *SimpleAAudioPlayerThreadProc(void *arg) {
@@ -288,19 +355,21 @@ int main(int argc, char **argv)
    }
    }


    printf("Sleep for %d seconds while audio plays in a background thread.\n", NUM_SECONDS);
    printf("Sleep for %d seconds while audio plays in a background thread.\n", NUM_SECONDS);
    {
    for (int i = 0; i < NUM_SECONDS && player.isEnabled(); i++) {
        // FIXME sleep is not an NDK API
        // FIXME sleep is not an NDK API
        // sleep(NUM_SECONDS);
        // sleep(NUM_SECONDS);
        const struct timespec request = { .tv_sec = NUM_SECONDS, .tv_nsec = 0 };
        const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
        (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
        (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
    }
    }
    printf("Woke up now.\n");
    printf("Woke up now!\n");


    result = player.stop();
    result = player.stop();
    if (result != AAUDIO_OK) {
    if (result != AAUDIO_OK) {
        fprintf(stderr, "ERROR -  player.stop() returned %d\n", result);
        fprintf(stderr, "ERROR -  player.stop() returned %d\n", result);
        goto error;
        goto error;
    }
    }

    printf("Player stopped.\n");
    result = player.close();
    result = player.close();
    if (result != AAUDIO_OK) {
    if (result != AAUDIO_OK) {
        fprintf(stderr, "ERROR -  player.close() returned %d\n", result);
        fprintf(stderr, "ERROR -  player.close() returned %d\n", result);
Loading