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

Commit 153f92d5 authored by Kevin Rocard's avatar Kevin Rocard
Browse files

Add secondary output to audio tracks

The secondary are returned from mixes (from DAP loopback&render),
from getOutputForAttr.
All getOutputForAttr* of the stack are update.
Internal getOutputForAttr use descriptor, external one use handles.

The secondary output are saved in each track and the track is
invalidated if the list of secondary output changes.

In audio flinger, create a pair of recordTrack & patchTrack to pipe
the intercepted audio audio to the secondary output.

Test: adb shell audiorecorder --target /data/file.raw
Bug: 111453086
Change-Id: Id6523d9e383c15a0e39313d5f355df809b7e72fe
parent 45986c74
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -872,13 +872,14 @@ status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
                                        const audio_config_t *config,
                                        audio_output_flags_t flags,
                                        audio_port_handle_t *selectedDeviceId,
                                        audio_port_handle_t *portId)
                                        audio_port_handle_t *portId,
                                        std::vector<audio_io_handle_t> *secondaryOutputs)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return NO_INIT;
    return aps->getOutputForAttr(attr, output, session, stream, pid, uid,
                                 config,
                                 flags, selectedDeviceId, portId);
                                 flags, selectedDeviceId, portId, secondaryOutputs);
}

status_t AudioSystem::startOutput(audio_port_handle_t portId)
+23 −13
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ public:
        return static_cast <audio_io_handle_t> (reply.readInt32());
    }

    virtual status_t getOutputForAttr(const audio_attributes_t *attr,
    status_t getOutputForAttr(const audio_attributes_t *attr,
                              audio_io_handle_t *output,
                              audio_session_t session,
                              audio_stream_type_t *stream,
@@ -198,7 +198,8 @@ public:
                              const audio_config_t *config,
                              audio_output_flags_t flags,
                              audio_port_handle_t *selectedDeviceId,
                                        audio_port_handle_t *portId)
                              audio_port_handle_t *portId,
                              std::vector<audio_io_handle_t> *secondaryOutputs) override
        {
            Parcel data, reply;
            data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -224,6 +225,10 @@ public:
                ALOGE("getOutputForAttr NULL portId - shouldn't happen");
                return BAD_VALUE;
            }
            if (secondaryOutputs == NULL) {
                ALOGE("getOutputForAttr NULL secondaryOutputs - shouldn't happen");
                return BAD_VALUE;
            }
            if (attr == NULL) {
                data.writeInt32(0);
            } else {
@@ -258,7 +263,9 @@ public:
            }
            *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
            *portId = (audio_port_handle_t)reply.readInt32();
            return status;
            secondaryOutputs->resize(reply.readInt32());
            return reply.read(secondaryOutputs->data(),
                              secondaryOutputs->size() * sizeof(audio_io_handle_t));
        }

    virtual status_t startOutput(audio_port_handle_t portId)
@@ -1300,16 +1307,19 @@ status_t BnAudioPolicyService::onTransact(
            audio_port_handle_t selectedDeviceId = data.readInt32();
            audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
            audio_io_handle_t output = 0;
            std::vector<audio_io_handle_t> secondaryOutputs;
            status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
                    &output, session, &stream, pid, uid,
                    &config,
                    flags, &selectedDeviceId, &portId);
                    flags, &selectedDeviceId, &portId, &secondaryOutputs);
            reply->writeInt32(status);
            reply->writeInt32(output);
            reply->writeInt32(stream);
            reply->writeInt32(selectedDeviceId);
            reply->writeInt32(portId);
            return NO_ERROR;
            reply->writeInt32(secondaryOutputs.size());
            return reply->write(secondaryOutputs.data(),
                                secondaryOutputs.size() * sizeof(audio_io_handle_t));
        } break;

        case START_OUTPUT: {
+2 −1
Original line number Diff line number Diff line
@@ -231,7 +231,8 @@ public:
                                     const audio_config_t *config,
                                     audio_output_flags_t flags,
                                     audio_port_handle_t *selectedDeviceId,
                                     audio_port_handle_t *portId);
                                     audio_port_handle_t *portId,
                                     std::vector<audio_io_handle_t> *secondaryOutputs);
    static status_t startOutput(audio_port_handle_t portId);
    static status_t stopOutput(audio_port_handle_t portId);
    static void releaseOutput(audio_port_handle_t portId);
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ public:
                                      const audio_config_t *config,
                                      audio_output_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId) = 0;
                                      audio_port_handle_t *portId,
                                      std::vector<audio_io_handle_t> *secondaryOutputs) = 0;
    virtual status_t startOutput(audio_port_handle_t portId) = 0;
    virtual status_t stopOutput(audio_port_handle_t portId) = 0;
    virtual void releaseOutput(audio_port_handle_t portId) = 0;
+61 −2
Original line number Diff line number Diff line
@@ -292,13 +292,16 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di
        fullConfig.sample_rate = config->sample_rate;
        fullConfig.channel_mask = config->channel_mask;
        fullConfig.format = config->format;
        std::vector<audio_io_handle_t> secondaryOutputs;
        ret = AudioSystem::getOutputForAttr(attr, &io,
                                            actualSessionId,
                                            &streamType, client.clientPid, client.clientUid,
                                            &fullConfig,
                                            (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                    AUDIO_OUTPUT_FLAG_DIRECT),
                                            deviceId, &portId);
                                            deviceId, &portId, &secondaryOutputs);
        ALOGW_IF(!secondaryOutputs.empty(),
                 "%s does not support secondary outputs, ignoring them", __func__);
    } else {
        ret = AudioSystem::getInputForAttr(attr, &io,
                                              actualSessionId,
@@ -678,6 +681,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
    status_t lStatus;
    audio_stream_type_t streamType;
    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
    std::vector<audio_io_handle_t> secondaryOutputs;

    bool updatePid = (input.clientInfo.clientPid == -1);
    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -712,7 +716,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,

    lStatus = AudioSystem::getOutputForAttr(&input.attr, &output.outputId, sessionId, &streamType,
                                            clientPid, clientUid, &input.config, input.flags,
                                            &output.selectedDeviceId, &portId);
                                            &output.selectedDeviceId, &portId, &secondaryOutputs);

    if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
        ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
@@ -785,6 +789,61 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
        output.afLatencyMs = thread->latency();
        output.portId = portId;

        if (lStatus == NO_ERROR) {
            // Connect secondary outputs. Failure on a secondary output must not imped the primary
            // Any secondary output setup failure will lead to a desync between the AP and AF until
            // the track is destroyed.
            TeePatches teePatches;
            for (audio_io_handle_t secondaryOutput : secondaryOutputs) {
                PlaybackThread *secondaryThread = checkPlaybackThread_l(secondaryOutput);
                if (secondaryThread == NULL) {
                    ALOGE("no playback thread found for secondary output %d", output.outputId);
                    continue;
                }

                size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount());

                using namespace std::chrono_literals;
                auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
                sp patchRecord = new RecordThread::PatchRecord(nullptr /* thread */,
                                                               output.sampleRate,
                                                               inChannelMask,
                                                               input.config.format,
                                                               frameCount,
                                                               NULL /* buffer */,
                                                               (size_t)0 /* bufferSize */,
                                                               AUDIO_INPUT_FLAG_DIRECT,
                                                               0ns /* timeout */);
                status_t status = patchRecord->initCheck();
                if (status != NO_ERROR) {
                    ALOGE("Secondary output patchRecord init failed: %d", status);
                    continue;
                }
                sp patchTrack = new PlaybackThread::PatchTrack(secondaryThread,
                                                               streamType,
                                                               output.sampleRate,
                                                               input.config.channel_mask,
                                                               input.config.format,
                                                               frameCount,
                                                               patchRecord->buffer(),
                                                               patchRecord->bufferSize(),
                                                               output.flags,
                                                               0ns /* timeout */);
                status = patchTrack->initCheck();
                if (status != NO_ERROR) {
                    ALOGE("Secondary output patchTrack init failed: %d", status);
                    continue;
                }
                teePatches.push_back({patchRecord, patchTrack});
                secondaryThread->addPatchTrack(patchTrack);
                patchTrack->setPeerProxy(patchRecord.get());
                patchRecord->setPeerProxy(patchTrack.get());

                patchTrack->start(); // patchRecord is NOT started as it has no thread
            }
            track->setTeePatches(std::move(teePatches));
        }

        // move effect chain to this output thread if an effect on same session was waiting
        // for a track to be created
        if (lStatus == NO_ERROR && effectThread != NULL) {
Loading