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

Commit e3dcd057 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge "audio: Allow "dynamic" profiles for device ports" into main

parents fa2dd8e2 84bcc049
Loading
Loading
Loading
Loading
+57 −49
Original line number Diff line number Diff line
@@ -105,15 +105,11 @@ static AudioPort createPort(int32_t id, const std::string& name, int32_t flags,
    return port;
}

static AudioPortConfig createPortConfig(int32_t id, int32_t portId, PcmType pcmType, int32_t layout,
                                        int32_t sampleRate, int32_t flags, bool isInput,
                                        const AudioPortExt& ext) {
static AudioPortConfig createDynamicPortConfig(int32_t id, int32_t portId, int32_t flags,
                                               bool isInput, const AudioPortExt& ext) {
    AudioPortConfig config;
    config.id = id;
    config.portId = portId;
    config.sampleRate = Int{.value = sampleRate};
    config.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
    config.format = AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
    config.gain = AudioGainConfig();
    config.flags = isInput ? AudioIoFlags::make<AudioIoFlags::Tag::input>(flags)
                           : AudioIoFlags::make<AudioIoFlags::Tag::output>(flags);
@@ -121,6 +117,16 @@ static AudioPortConfig createPortConfig(int32_t id, int32_t portId, PcmType pcmT
    return config;
}

static AudioPortConfig createPortConfig(int32_t id, int32_t portId, PcmType pcmType, int32_t layout,
                                        int32_t sampleRate, int32_t flags, bool isInput,
                                        const AudioPortExt& ext) {
    AudioPortConfig config = createDynamicPortConfig(id, portId, flags, isInput, ext);
    config.sampleRate = Int{.value = sampleRate};
    config.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
    config.format = AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
    return config;
}

static AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
    AudioRoute route;
    route.sinkPortId = sink.id;
@@ -147,8 +153,7 @@ static AudioRoute createRoute(const std::vector<AudioPort>& sources, const Audio
//  * "primary output", PRIMARY, 1 max open, 1 max active stream
//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//  * "primary input", 1 max open, 1 max active stream
//    - profile PCM 16-bit; MONO, STEREO;
//        8000, 11025, 16000, 32000, 44100, 48000
//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//  * "telephony_tx", 1 max open, 1 max active stream
//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//  * "telephony_rx", 1 max open, 1 max active stream
@@ -164,11 +169,11 @@ static AudioRoute createRoute(const std::vector<AudioPort>& sources, const Audio
//  "FM Tuner" -> "fm_tuner"
//
// Initial port configs:
//  * "Speaker" device port: PCM 16-bit; STEREO; 48000
//  * "Built-In Mic" device port: PCM 16-bit; MONO; 48000
//  * "Telephony Tx" device port: PCM 16-bit; MONO; 48000
//  * "Telephony Rx" device port: PCM 16-bit; MONO; 48000
//  * "FM Tuner" device port: PCM 16-bit; STEREO; 48000
//  * "Speaker" device port: dynamic configuration
//  * "Built-In Mic" device port: dynamic configuration
//  * "Telephony Tx" device port: dynamic configuration
//  * "Telephony Rx" device port: dynamic configuration
//  * "FM Tuner" device port: dynamic configuration
//
std::unique_ptr<Configuration> getPrimaryConfiguration() {
    static const Configuration configuration = []() {
@@ -186,8 +191,7 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
                                           1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
        c.ports.push_back(speakerOutDevice);
        c.initialConfigs.push_back(
                createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT,
                                 AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
                createDynamicPortConfig(speakerOutDevice.id, speakerOutDevice.id, 0, false,
                                        createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));

        AudioPort micInDevice =
@@ -196,8 +200,7 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
                                           1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
        c.ports.push_back(micInDevice);
        c.initialConfigs.push_back(
                createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT,
                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
                createDynamicPortConfig(micInDevice.id, micInDevice.id, 0, true,
                                        createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));

        AudioPort telephonyTxOutDevice =
@@ -205,25 +208,22 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
                           createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0));
        c.ports.push_back(telephonyTxOutDevice);
        c.initialConfigs.push_back(
                createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
                                 false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
                createDynamicPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id, 0, false,
                                        createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));

        AudioPort telephonyRxInDevice =
                createPort(c.nextPortId++, "Telephony Rx", 0, true,
                           createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0));
        c.ports.push_back(telephonyRxInDevice);
        c.initialConfigs.push_back(
                createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
                                 true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
                createDynamicPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id, 0, true,
                                        createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));

        AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
                                               createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
        c.ports.push_back(fmTunerInDevice);
        c.initialConfigs.push_back(
                createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT,
                                 AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
                createDynamicPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, 0, true,
                                        createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));

        // Mix ports
@@ -287,13 +287,15 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {

// Note: When transitioning to loading of XML configs, either keep the configuration
// of the remote submix sources from this static configuration, or update the XML
// config to match it. There are two reasons for that:
//   1. The canonical r_submix configuration only lists 'STEREO' and '48000',
// config to match it. There are several reasons for that:
//   1. The "Remote Submix In" device is listed in the XML config as "attached",
//      however in the AIDL scheme its device type has a "virtual" connection.
//   2. The canonical r_submix configuration only lists 'STEREO' and '48000',
//      however the framework attempts to open streams for other sample rates
//      as well. The legacy r_submix implementation allowed that, but libaudiohal@aidl
//      will not find a mix port to use. Because of that, list all channel
//      masks and sample rates that the legacy implementation allowed.
//   2. The legacy implementation had a hard limit on the number of routes (10),
//   3. The legacy implementation had a hard limit on the number of routes (10),
//      and this is checked indirectly by AudioPlaybackCaptureTest#testPlaybackCaptureDoS
//      CTS test. Instead of hardcoding the number of routes, we can use
//      "maxOpen/ActiveStreamCount" to enforce a similar limit. However, the canonical
@@ -331,15 +333,15 @@ std::unique_ptr<Configuration> getRSubmixConfiguration() {
                createPort(c.nextPortId++, "Remote Submix Out", 0, false,
                           createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
                                           AudioDeviceDescription::CONNECTION_VIRTUAL));
        rsubmixOutDevice.profiles = standardPcmAudioProfiles;
        c.ports.push_back(rsubmixOutDevice);
        c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;

        AudioPort rsubmixInDevice =
                createPort(c.nextPortId++, "Remote Submix In", 0, true,
                           createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
                                           AudioDeviceDescription::CONNECTION_VIRTUAL));
        rsubmixInDevice.profiles = standardPcmAudioProfiles;
        c.ports.push_back(rsubmixInDevice);
        c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;

        // Mix ports

@@ -384,7 +386,7 @@ std::unique_ptr<Configuration> getRSubmixConfiguration() {
//  * "usb_device output" -> "USB Headset Out"
//  * "USB Device In", "USB Headset In" -> "usb_device input"
//
// Profiles for device port connected state:
// Profiles for device port connected state (when simulating connections):
//  * "USB Device Out", "USB Headset Out":
//    - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
//    - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
@@ -461,9 +463,9 @@ std::unique_ptr<Configuration> getUsbConfiguration() {
//  * "Test In", IN_AFE_PROXY
//    - no profiles specified
//  * "Wired Headset", OUT_HEADSET
//    - profile PCM 24-bit; STEREO; 48000
//    - no profiles specified
//  * "Wired Headset Mic", IN_HEADSET
//    - profile PCM 24-bit; MONO; 48000
//    - no profiles specified
//
// Mix ports:
//  * "test output", 1 max open, 1 max active stream
@@ -486,6 +488,10 @@ std::unique_ptr<Configuration> getUsbConfiguration() {
//  * "Test Out" device port: PCM 24-bit; STEREO; 48000
//  * "Test In" device port: PCM 24-bit; MONO; 48000
//
// Profiles for device port connected state (when simulating connections):
//  * "Wired Headset": dynamic profiles
//  * "Wired Headset Mic": dynamic profiles
//
std::unique_ptr<Configuration> getStubConfiguration() {
    static const Configuration configuration = []() {
        Configuration c;
@@ -504,8 +510,6 @@ std::unique_ptr<Configuration> getStubConfiguration() {
                createPort(c.nextPortId++, "Wired Headset", 0, false,
                           createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
                                           AudioDeviceDescription::CONNECTION_ANALOG));
        headsetOutDevice.profiles.push_back(
                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
        c.ports.push_back(headsetOutDevice);

        AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true,
@@ -520,8 +524,6 @@ std::unique_ptr<Configuration> getStubConfiguration() {
                createPort(c.nextPortId++, "Wired Headset Mic", 0, true,
                           createDeviceExt(AudioDeviceType::IN_HEADSET, 0,
                                           AudioDeviceDescription::CONNECTION_ANALOG));
        headsetInDevice.profiles.push_back(
                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO}, {48000}));
        c.ports.push_back(headsetInDevice);

        // Mix ports
@@ -553,24 +555,24 @@ std::unique_ptr<Configuration> getStubConfiguration() {
                              {44100, 48000}));
        c.ports.push_back(compressedOffloadOutMix);

        AudioPort testInMIx =
        AudioPort testInMix =
                createPort(c.nextPortId++, "test input", 0, true, createPortMixExt(2, 2));
        testInMIx.profiles.push_back(
        testInMix.profiles.push_back(
                createProfile(PcmType::INT_16_BIT,
                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                               AudioChannelLayout::LAYOUT_FRONT_BACK},
                              {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
        testInMIx.profiles.push_back(
        testInMix.profiles.push_back(
                createProfile(PcmType::INT_24_BIT,
                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                               AudioChannelLayout::LAYOUT_FRONT_BACK},
                              {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
        c.ports.push_back(testInMIx);
        c.ports.push_back(testInMix);

        c.routes.push_back(
                createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
        c.routes.push_back(createRoute({testOutMix}, headsetOutDevice));
        c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMIx));
        c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMix));

        c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());

@@ -603,11 +605,19 @@ std::unique_ptr<Configuration> getStubConfiguration() {
//  "a2dp output" -> "BT A2DP Speaker"
//  "hearing aid output" -> "BT Hearing Aid Out"
//
// Profiles for device port connected state (when simulating connections):
//  * "BT A2DP Out", "BT A2DP Headphones", "BT A2DP Speaker":
//    - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
//  * "BT Hearing Aid Out":
//    - profile PCM 16-bit; STEREO; 16000, 24000
//
std::unique_ptr<Configuration> getBluetoothConfiguration() {
    static const Configuration configuration = []() {
        const std::vector<AudioProfile> standardPcmAudioProfiles = {
                createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
                              {44100, 48000, 88200, 96000})};
        const std::vector<AudioProfile> hearingAidAudioProfiles = {createProfile(
                PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000})};
        Configuration c;

        // Device ports
@@ -645,8 +655,7 @@ std::unique_ptr<Configuration> getBluetoothConfiguration() {
                           createDeviceExt(AudioDeviceType::OUT_HEARING_AID, 0,
                                           AudioDeviceDescription::CONNECTION_WIRELESS));
        c.ports.push_back(btOutHearingAid);
        c.connectedProfiles[btOutHearingAid.id] = std::vector<AudioProfile>(
                {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
        c.connectedProfiles[btOutHearingAid.id] = hearingAidAudioProfiles;

        // Mix ports
        AudioPort btOutMix =
@@ -655,8 +664,7 @@ std::unique_ptr<Configuration> getBluetoothConfiguration() {

        AudioPort btHearingOutMix =
                createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1));
        btHearingOutMix.profiles.push_back(createProfile(
                PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000}));
        btHearingOutMix.profiles = hearingAidAudioProfiles;
        c.ports.push_back(btHearingOutMix);

        c.routes.push_back(createRoute({btOutMix}, btOutDevice));
+171 −86

File changed.

Preview size limit exceeded, changes collapsed.

+55 −4
Original line number Diff line number Diff line
@@ -18,15 +18,23 @@

#include <android-base/logging.h>

#include "BluetoothAudioSessionControl.h"
#include "core-impl/ModuleBluetooth.h"
#include "core-impl/StreamBluetooth.h"

namespace aidl::android::hardware::audio::core {

using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::MicrophoneInfo;
using ::aidl::android::hardware::audio::common::SinkMetadata;
using ::aidl::android::hardware::audio::common::SourceMetadata;
using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession;
using ::aidl::android::media::audio::common::AudioDeviceDescription;
using ::aidl::android::media::audio::common::AudioDeviceType;
using ::aidl::android::media::audio::common::AudioOffloadInfo;
using ::aidl::android::media::audio::common::AudioPort;
using ::aidl::android::media::audio::common::AudioPortExt;
using ::aidl::android::media::audio::common::MicrophoneInfo;
using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;

ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
        std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
@@ -80,6 +88,49 @@ ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
                                                    offloadInfo, getBtProfileManagerHandles());
}

ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort) {
    if (audioPort->ext.getTag() != AudioPortExt::device) {
        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
    const auto& description = devicePort.device.type;
    // Since the configuration of the BT module is static, there is nothing to populate here.
    // However, this method must return an error when the device can not be connected,
    // this is determined by the status of BT profiles.
    if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
        bool isA2dpEnabled = false;
        if (!!mBluetoothA2dp) {
            RETURN_STATUS_IF_ERROR(mBluetoothA2dp.getInstance()->isEnabled(&isA2dpEnabled));
        }
        return isA2dpEnabled ? ndk::ScopedAStatus::ok()
                             : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
        bool isLeEnabled = false;
        if (!!mBluetoothLe) {
            RETURN_STATUS_IF_ERROR(mBluetoothLe.getInstance()->isEnabled(&isLeEnabled));
        }
        return isLeEnabled ? ndk::ScopedAStatus::ok()
                           : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
               description.type == AudioDeviceType::OUT_HEARING_AID) {
        // Hearing aids can use a number of profiles, thus the only way to check
        // connectivity is to try to talk to the BT HAL.
        if (!BluetoothAudioSession::IsAidlAvailable()) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
        std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
                std::make_shared<BluetoothAudioPortAidlOut>());
        if (proxy->registerPort(description)) {
            proxy->unregisterPort();
            return ndk::ScopedAStatus::ok();
        }
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}

ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
    LOG(DEBUG) << __func__ << ": is not supported";
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+3 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ class Module : public BnModule {
    std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
    ndk::ScopedAStatus findPortIdForNewStream(
            int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
    std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
    virtual BtProfileHandles getBtProfileManagerHandles();
    internal::Configuration& getConfig();
    const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
@@ -209,6 +210,8 @@ class Module : public BnModule {
    bool getMasterVolume() const { return mMasterVolume; }
    bool getMicMute() const { return mMicMute; }
    const Patches& getPatches() const { return mPatches; }
    std::set<int32_t> getRoutableAudioPortIds(int32_t portId,
                                              std::vector<AudioRoute*>* routes = nullptr);
    const Streams& getStreams() const { return mStreams; }
    Type getType() const { return mType; }
    bool isMmapSupported();
+3 −1
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ class ModuleBluetooth final : public Module {
            const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                    offloadInfo,
            std::shared_ptr<StreamOut>* result) override;
    ndk::ScopedAStatus populateConnectedDevicePort(
            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
    ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
    ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;

Loading