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

Commit 9d91ad5d authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix issue 1795088 Improve audio routing code

Initial commit for review.
Integrated comments after patch set 1 review.
Fixed lockup in AudioFlinger::ThreadBase::exit()
Fixed lockup when playing tone with AudioPlocyService startTone()
parent eba4009d
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#include "CameraService.h"

#include <cutils/atomic.h>
#include <cutils/properties.h>

namespace android {

@@ -199,13 +198,7 @@ static sp<MediaPlayer> newMediaPlayer(const char *file)
{
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp->setDataSource(file) == NO_ERROR) {
        char value[PROPERTY_VALUE_MAX];
        property_get("ro.camera.sound.forced", value, "0");
        if (atoi(value)) {
        mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
        } else {
            mp->setAudioStreamType(AudioSystem::SYSTEM);            
        }
        mp->prepare();
    } else {
        mp.clear();
+2 −2
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ enum tts_callback_status {
// @param [inout] void *&       - The userdata pointer set in the original
//                                 synth call
// @param [in]    uint32_t      - Track sampling rate in Hz
// @param [in]    audio_format  - The AudioSystem::audio_format enum
// @param [in]    uint32_t      - The audio format
// @param [in]    int           - The number of channels
// @param [inout] int8_t *&     - A buffer of audio data only valid during the
//                                execution of the callback
@@ -54,7 +54,7 @@ enum tts_callback_status {
//         TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
//            there is more data to produce.
typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
        AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
        uint32_t, int, int8_t *&, size_t&, tts_synth_status);

class TtsEngine;
extern "C" TtsEngine* getTtsEngine();
+183 −41
Original line number Diff line number Diff line
@@ -29,25 +29,41 @@ namespace android {

// ----------------------------------------------------------------------------

A2dpAudioInterface::A2dpAudioInterface() :
    mOutput(0)
//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
//{
//    AudioHardwareInterface* hw = 0;
//
//    hw = AudioHardwareInterface::create();
//    LOGD("new A2dpAudioInterface(hw: %p)", hw);
//    hw = new A2dpAudioInterface(hw);
//    return hw;
//}

A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
    mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true)
{
}

A2dpAudioInterface::~A2dpAudioInterface()
{
    delete mOutput;
    closeOutputStream((AudioStreamOut *)mOutput);
    delete mHardwareInterface;
}

status_t A2dpAudioInterface::initCheck()
{
    return 0;
    if (mHardwareInterface == 0) return NO_INIT;
    return mHardwareInterface->initCheck();
}

AudioStreamOut* A2dpAudioInterface::openOutputStream(
        int format, int channelCount, uint32_t sampleRate, status_t *status)
        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
    LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
    if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
        LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
        return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
    }

    status_t err = 0;

    // only one output stream allowed
@@ -59,8 +75,9 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(

    // create new output stream
    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
    if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
    if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
        mOutput = out;
        mOutput->setBluetoothEnabled(mBluetoothEnabled);
    } else {
        delete out;
    }
@@ -70,60 +87,115 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(
    return mOutput;
}

void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
    if (mOutput == 0 || mOutput != out) {
        LOGW("Attempt to close invalid output stream");
    }
    else {
        delete mOutput;
        mOutput = 0;
    }
}


AudioStreamIn* A2dpAudioInterface::openInputStream(
        int inputSource, int format, int channelCount, uint32_t sampleRate,
        status_t *status, AudioSystem::audio_in_acoustics acoustics)
        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
        AudioSystem::audio_in_acoustics acoustics)
{
    if (status)
        *status = -1;
    return NULL;
    return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
}

void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
{
    return mHardwareInterface->closeInputStream(in);
}

status_t A2dpAudioInterface::setMode(int mode)
{
    return mHardwareInterface->setMode(mode);
}

status_t A2dpAudioInterface::setMicMute(bool state)
{
    return 0;
    return mHardwareInterface->setMicMute(state);
}

status_t A2dpAudioInterface::getMicMute(bool* state)
{
    return 0;
    return mHardwareInterface->getMicMute(state);
}

status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
{
    LOGD("setParameter %s,%s\n", key, value);
    AudioParameter param = AudioParameter(keyValuePairs);
    String8 value;
    String8 key;
    status_t status = NO_ERROR;

    if (!key || !value)
        return -EINVAL;
    LOGV("setParameters() %s", keyValuePairs.string());

    if (strcmp(key, "a2dp_sink_address") == 0) {
        return mOutput->setAddress(value);
    key = "bluetooth_enabled";
    if (param.get(key, value) == NO_ERROR) {
        mBluetoothEnabled = (value == "true");
        if (mOutput) {
            mOutput->setBluetoothEnabled(mBluetoothEnabled);
        }
    if (strcmp(key, "bluetooth_enabled") == 0) {
        mOutput->setBluetoothEnabled(strcmp(value, "true") == 0);
        param.remove(key);
    }

    return 0;
    if (param.size()) {
        status_t hwStatus = mHardwareInterface->setParameters(param.toString());
        if (status == NO_ERROR) {
            status = hwStatus;
        }
    }

status_t A2dpAudioInterface::setVoiceVolume(float v)
    return status;
}

String8 A2dpAudioInterface::getParameters(const String8& keys)
{
    return 0;
    AudioParameter param = AudioParameter(keys);
    AudioParameter a2dpParam = AudioParameter();
    String8 value;
    String8 key;

    key = "bluetooth_enabled";
    if (param.get(key, value) == NO_ERROR) {
        value = mBluetoothEnabled ? "true" : "false";
        a2dpParam.add(key, value);
        param.remove(key);
    }

status_t A2dpAudioInterface::setMasterVolume(float v)
    String8 keyValuePairs  = a2dpParam.toString();

    if (param.size()) {
        keyValuePairs += ";";
        keyValuePairs += mHardwareInterface->getParameters(param.toString());
    }

    LOGV("getParameters() %s", keyValuePairs.string());
    return keyValuePairs;
}

size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
    return 0;
    return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
}

status_t A2dpAudioInterface::doRouting()
status_t A2dpAudioInterface::setVoiceVolume(float v)
{
    return 0;
    return mHardwareInterface->setVoiceVolume(v);
}

status_t A2dpAudioInterface::setMasterVolume(float v)
{
    return mHardwareInterface->setMasterVolume(v);
}

status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
{
    return 0;
    return mHardwareInterface->dumpState(fd, args);
}

// ----------------------------------------------------------------------------
@@ -132,7 +204,7 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
    // assume BT enabled to start, this is safe because its only the
    // enabled->disabled transition we are worried about
    mBluetoothEnabled(true)
    mBluetoothEnabled(true), mDevice(0)
{
    // use any address by default
    strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -140,27 +212,43 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
        int format, int channels, uint32_t rate)
        uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
    LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
    int lFormat = pFormat ? *pFormat : 0;
    uint32_t lChannels = pChannels ? *pChannels : 0;
    uint32_t lRate = pRate ? *pRate : 0;

    LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);

    // fix up defaults
    if (format == 0) format = AudioSystem::PCM_16_BIT;
    if (channels == 0) channels = channelCount();
    if (rate == 0) rate = sampleRate();
    if (lFormat == 0) lFormat = format();
    if (lChannels == 0) lChannels = channels();
    if (lRate == 0) lRate = sampleRate();

    // check values
    if ((format != AudioSystem::PCM_16_BIT) ||
            (channels != channelCount()) ||
            (rate != sampleRate()))
    if ((lFormat != format()) ||
            (lChannels != channels()) ||
            (lRate != sampleRate())){
        if (pFormat) *pFormat = format();
        if (pChannels) *pChannels = channels();
        if (pRate) *pRate = sampleRate();
        return BAD_VALUE;
    }

    if (pFormat) *pFormat = lFormat;
    if (pChannels) *pChannels = lChannels;
    if (pRate) *pRate = lRate;

    mDevice = device;
    return NO_ERROR;
}

A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
    LOGV("A2dpAudioStreamOut destructor");
    standby();
    close();
    LOGV("A2dpAudioStreamOut destructor returning from close()");
}

ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
@@ -230,6 +318,59 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
    return result;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
{
    AudioParameter param = AudioParameter(keyValuePairs);
    String8 value;
    String8 key = String8("a2dp_sink_address");
    status_t status = NO_ERROR;
    int device;
    LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());

    if (param.get(key, value) == NO_ERROR) {
        if (value.length() != strlen("00:00:00:00:00:00")) {
            status = BAD_VALUE;
        } else {
            setAddress(value.string());
        }
        param.remove(key);
    }
    key = AudioParameter::keyRouting;
    if (param.getInt(key, device) == NO_ERROR) {
        if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
            mDevice = device;
            status = NO_ERROR;
        } else {
            status = BAD_VALUE;
        }
        param.remove(key);
    }

    if (param.size()) {
        status = BAD_VALUE;
    }
    return status;
}

String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
{
    AudioParameter param = AudioParameter(keys);
    String8 value;
    String8 key = String8("a2dp_sink_address");

    if (param.get(key, value) == NO_ERROR) {
        value = mA2dpAddress;
        param.add(key, value);
    }
    key = AudioParameter::keyRouting;
    if (param.get(key, value) == NO_ERROR) {
        param.addInt(key, (int)mDevice);
    }

    LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
    return param.toString();
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
    Mutex::Autolock lock(mLock);
@@ -260,12 +401,14 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enable
status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
{
    Mutex::Autolock lock(mLock);
    LOGV("A2dpAudioStreamOut::close() calling close_l()");
    return close_l();
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
{
    if (mData) {
        LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
        a2dp_cleanup(mData);
        mData = NULL;
    }
@@ -277,5 +420,4 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<Strin
    return NO_ERROR;
}


}; // namespace android
+33 −17
Original line number Diff line number Diff line
@@ -32,38 +32,44 @@ class A2dpAudioInterface : public AudioHardwareBase
    class A2dpAudioStreamOut;

public:
                        A2dpAudioInterface();
                        A2dpAudioInterface(AudioHardwareInterface* hw);
    virtual             ~A2dpAudioInterface();
    virtual status_t    initCheck();

    virtual status_t    setVoiceVolume(float volume);
    virtual status_t    setMasterVolume(float volume);

    virtual status_t    setMode(int mode);

    // mic mute
    virtual status_t    setMicMute(bool state);
    virtual status_t    getMicMute(bool* state);

    // Temporary interface, do not use
    // TODO: Replace with a more generic key:value get/set mechanism
    virtual status_t    setParameter(const char *key, const char *value);
    virtual status_t    setParameters(const String8& keyValuePairs);
    virtual String8     getParameters(const String8& keys);

    virtual size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);

    // create I/O streams
    virtual AudioStreamOut* openOutputStream(
                                int format=0,
                                int channelCount=0,
                                uint32_t sampleRate=0,
                                uint32_t devices,
                                int *format=0,
                                uint32_t *channels=0,
                                uint32_t *sampleRate=0,
                                status_t *status=0);
    virtual    void        closeOutputStream(AudioStreamOut* out);

    virtual AudioStreamIn* openInputStream(
                                int inputSource,
                                int format,
                                int channelCount,
                                uint32_t sampleRate,
                                uint32_t devices,
                                int *format,
                                uint32_t *channels,
                                uint32_t *sampleRate,
                                status_t *status,
                                AudioSystem::audio_in_acoustics acoustics);
    virtual    void        closeInputStream(AudioStreamIn* in);
//    static AudioHardwareInterface* createA2dpInterface();

protected:
    virtual status_t    doRouting();
    virtual status_t    dump(int fd, const Vector<String16>& args);

private:
@@ -71,19 +77,22 @@ private:
    public:
                            A2dpAudioStreamOut();
        virtual             ~A2dpAudioStreamOut();
                status_t    set(int format,
                                int channelCount,
                                uint32_t sampleRate);
                status_t    set(uint32_t device,
                                int *pFormat,
                                uint32_t *pChannels,
                                uint32_t *pRate);
        virtual uint32_t    sampleRate() const { return 44100; }
        // SBC codec wants a multiple of 512
        virtual size_t      bufferSize() const { return 512 * 20; }
        virtual int         channelCount() const { return 2; }
        virtual uint32_t    channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
        virtual uint32_t    latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
        virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
        virtual status_t    setVolume(float left, float right) { return INVALID_OPERATION; }
        virtual ssize_t     write(const void* buffer, size_t bytes);
                status_t    standby();
        virtual status_t    dump(int fd, const Vector<String16>& args);
        virtual status_t    setParameters(const String8& keyValuePairs);
        virtual String8     getParameters(const String8& keys);

    private:
        friend class A2dpAudioInterface;
@@ -102,11 +111,18 @@ private:
                void*       mData;
                Mutex       mLock;
                bool        mBluetoothEnabled;
                uint32_t    mDevice;
    };

    friend class A2dpAudioStreamOut;

    A2dpAudioStreamOut*     mOutput;
    AudioHardwareInterface  *mHardwareInterface;
    char        mA2dpAddress[20];
    bool        mBluetoothEnabled;
};


// ----------------------------------------------------------------------------

}; // namespace android
+59 −5
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)

#AUDIO_POLICY_TEST := true
#ENABLE_AUDIO_DUMP := true

include $(CLEAR_VARS)


ifeq ($(AUDIO_POLICY_TEST),true)
  ENABLE_AUDIO_DUMP := true
endif


LOCAL_SRC_FILES:= \
    AudioHardwareGeneric.cpp \
    AudioHardwareStub.cpp \
    AudioDumpInterface.cpp \
    AudioHardwareInterface.cpp

ifeq ($(ENABLE_AUDIO_DUMP),true)
  LOCAL_SRC_FILES += AudioDumpInterface.cpp
  LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
endif

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
@@ -21,8 +34,40 @@ endif

LOCAL_MODULE:= libaudiointerface

ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
  LOCAL_SHARED_LIBRARIES += liba2dp
  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  LOCAL_C_INCLUDES += $(call include-path-for, bluez)
endif

include $(BUILD_STATIC_LIBRARY)


include $(CLEAR_VARS)

LOCAL_SRC_FILES:=               \
    AudioPolicyManagerGeneric.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    libmedia

LOCAL_MODULE:= libaudiopolicygeneric

ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_CFLAGS += -DWITH_A2DP
endif

ifeq ($(AUDIO_POLICY_TEST),true)
  LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=               \
@@ -30,7 +75,8 @@ LOCAL_SRC_FILES:= \
    AudioMixer.cpp.arm          \
    AudioResampler.cpp.arm      \
    AudioResamplerSinc.cpp.arm  \
    AudioResamplerCubic.cpp.arm
    AudioResamplerCubic.cpp.arm \
    AudioPolicyService.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
@@ -41,17 +87,25 @@ LOCAL_SHARED_LIBRARIES := \

ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  LOCAL_STATIC_LIBRARIES += libaudiointerface
  LOCAL_CFLAGS += -DGENERIC_AUDIO
else
  LOCAL_SHARED_LIBRARIES += libaudio
endif

ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_LDLIBS += -ldl
else
 LOCAL_SHARED_LIBRARIES += libdl
endif

LOCAL_MODULE:= libaudioflinger

ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
  LOCAL_SHARED_LIBRARIES += liba2dp
  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  LOCAL_C_INCLUDES += $(call include-path-for, bluez)
endif

ifeq ($(AUDIO_POLICY_TEST),true)
  LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif

ifeq ($(TARGET_SIMULATOR),true)
Loading