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

Commit 2d887649 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "refactor AudioRecord and AudioFlinger openRecord()"

parents ad95755f 3e1acc0c
Loading
Loading
Loading
Loading
+104 −174
Original line number Diff line number Diff line
@@ -69,8 +69,7 @@ AudioRecord::AudioRecord(const String16 &opPackageName)
    : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
      mSessionId(AUDIO_SESSION_ALLOCATE),
      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mPortId(AUDIO_PORT_HANDLE_NONE)
      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
{
}

@@ -97,10 +96,9 @@ AudioRecord::AudioRecord(
      mSessionId(AUDIO_SESSION_ALLOCATE),
      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
      mPreviousSchedulingGroup(SP_DEFAULT),
      mProxy(NULL),
      mPortId(AUDIO_PORT_HANDLE_NONE)
      mProxy(NULL)
{
    mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
    (void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
            notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
            uid, pid, pAttributes, selectedDeviceId);
}
@@ -151,6 +149,11 @@ status_t AudioRecord::set(
        const audio_attributes_t* pAttributes,
        audio_port_handle_t selectedDeviceId)
{
    status_t status = NO_ERROR;
    uint32_t channelCount;
    pid_t callingPid;
    pid_t myPid;

    ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
          "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
          "uid %d, pid %d",
@@ -170,7 +173,8 @@ status_t AudioRecord::set(
    case TRANSFER_CALLBACK:
        if (cbf == NULL) {
            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL");
            return BAD_VALUE;
            status = BAD_VALUE;
            goto exit;
        }
        break;
    case TRANSFER_OBTAIN:
@@ -178,14 +182,16 @@ status_t AudioRecord::set(
        break;
    default:
        ALOGE("Invalid transfer type %d", transferType);
        return BAD_VALUE;
        status = BAD_VALUE;
        goto exit;
    }
    mTransfer = transferType;

    // invariant that mAudioRecord != 0 is true only after set() returns successfully
    if (mAudioRecord != 0) {
        ALOGE("Track already in use");
        return INVALID_OPERATION;
        status = INVALID_OPERATION;
        goto exit;
    }

    if (pAttributes == NULL) {
@@ -209,16 +215,18 @@ status_t AudioRecord::set(
    // AudioFlinger capture only supports linear PCM
    if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
        ALOGE("Format %#x is not linear pcm", format);
        return BAD_VALUE;
        status = BAD_VALUE;
        goto exit;
    }
    mFormat = format;

    if (!audio_is_input_channel(channelMask)) {
        ALOGE("Invalid channel mask %#x", channelMask);
        return BAD_VALUE;
        status = BAD_VALUE;
        goto exit;
    }
    mChannelMask = channelMask;
    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
    channelCount = audio_channel_count_from_in_mask(channelMask);
    mChannelCount = channelCount;

    if (audio_is_linear_pcm(format)) {
@@ -227,28 +235,24 @@ status_t AudioRecord::set(
        mFrameSize = sizeof(uint8_t);
    }

    // mFrameCount is initialized in openRecord_l
    // mFrameCount is initialized in createRecord_l
    mReqFrameCount = frameCount;

    mNotificationFramesReq = notificationFrames;
    // mNotificationFramesAct is initialized in openRecord_l
    // mNotificationFramesAct is initialized in createRecord_l

    if (sessionId == AUDIO_SESSION_ALLOCATE) {
        mSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    } else {
    mSessionId = sessionId;
    }
    ALOGV("set(): mSessionId %d", mSessionId);

    int callingpid = IPCThreadState::self()->getCallingPid();
    int mypid = getpid();
    if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) {
    callingPid = IPCThreadState::self()->getCallingPid();
    myPid = getpid();
    if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
        mClientUid = IPCThreadState::self()->getCallingUid();
    } else {
        mClientUid = uid;
    }
    if (pid == -1 || (callingpid != mypid)) {
        mClientPid = callingpid;
    if (pid == -1 || (callingPid != myPid)) {
        mClientPid = callingPid;
    } else {
        mClientPid = pid;
    }
@@ -263,7 +267,7 @@ status_t AudioRecord::set(
    }

    // create the IAudioRecord
    status_t status = openRecord_l(0 /*epoch*/, mOpPackageName);
    status = createRecord_l(0 /*epoch*/, mOpPackageName);

    if (status != NO_ERROR) {
        if (mAudioRecordThread != 0) {
@@ -271,10 +275,9 @@ status_t AudioRecord::set(
            mAudioRecordThread->requestExitAndWait();
            mAudioRecordThread.clear();
        }
        return status;
        goto exit;
    }

    mStatus = NO_ERROR;
    mUserData = user;
    // TODO: add audio hardware input latency here
    mLatency = (1000LL * mFrameCount) / mSampleRate;
@@ -289,7 +292,9 @@ status_t AudioRecord::set(
    mFramesRead = 0;
    mFramesReadServerOffset = 0;

    return NO_ERROR;
exit:
    mStatus = status;
    return status;
}

// -------------------------------------------------------------------------
@@ -540,70 +545,29 @@ const char * AudioRecord::convertTransferToText(transfer_type transferType) {
}

// must be called with mLock held
status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
    IAudioFlinger::CreateRecordInput input;
    IAudioFlinger::CreateRecordOutput output;
    audio_session_t originalSessionId;
    sp<media::IAudioRecord> record;
    void *iMemPointer;
    audio_track_cblk_t* cblk;
    status_t status;

    if (audioFlinger == 0) {
        ALOGE("Could not get audioflinger");
        return NO_INIT;
        status = NO_INIT;
        goto exit;
    }

    audio_io_handle_t input;

    // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
    // After fast request is denied, we will request again if IAudioRecord is re-created.

    status_t status;

    // Not a conventional loop, but a retry loop for at most two iterations total.
    // Try first maybe with FAST flag then try again without FAST flag if that fails.
    // Exits loop normally via a return at the bottom, or with error via a break.
    // The sp<> references will be dropped when re-entering scope.
    // The lack of indentation is deliberate, to reduce code churn and ease merges.
    for (;;) {
    audio_config_base_t config  = {
            .sample_rate = mSampleRate,
            .channel_mask = mChannelMask,
            .format = mFormat
        };
    mRoutedDeviceId = mSelectedDeviceId;
    status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                        mSessionId,
                                        // FIXME compare to AudioTrack
                                        mClientPid,
                                        mClientUid,
                                        &config,
                                        mFlags, &mRoutedDeviceId, &mPortId);

    if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
        ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
              "format %#x, channel mask %#x, flags %#x",
              mSessionId, mAttributes.source, mSampleRate, mFormat, mChannelMask, mFlags);
        return BAD_VALUE;
    }

    // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
    // we must release it ourselves if anything goes wrong.

#if 0
    size_t afFrameCount;
    status = AudioSystem::getFrameCount(input, &afFrameCount);
    if (status != NO_ERROR) {
        ALOGE("getFrameCount(input=%d) status %d", input, status);
        break;
    }
#endif

    uint32_t afSampleRate;
    status = AudioSystem::getSamplingRate(input, &afSampleRate);
    if (status != NO_ERROR) {
        ALOGE("getSamplingRate(input=%d) status %d", input, status);
        break;
    }
    if (mSampleRate == 0) {
        mSampleRate = afSampleRate;
    }

    // Client can only express a preference for FAST.  Server will perform additional tests.
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        bool useCaseAllowed =
@@ -622,66 +586,41 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        if (!useCaseAllowed) {
            ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
                  convertTransferToText(mTransfer));
        }

        // sample rates must also match
        bool sampleRateAllowed = mSampleRate == afSampleRate;
        if (!sampleRateAllowed) {
            ALOGW("AUDIO_INPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
                  mSampleRate, afSampleRate);
        }

        bool fastAllowed = useCaseAllowed && sampleRateAllowed;
        if (!fastAllowed) {
            mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
                    AUDIO_INPUT_FLAG_RAW));
            AudioSystem::releaseInput(input, mSessionId);
            continue;   // retry
        }
    }

    // The notification frame count is the period between callbacks, as suggested by the client
    // but moderated by the server.  For record, the calculations are done entirely on server side.
    size_t notificationFrames = mNotificationFramesReq;
    size_t frameCount = mReqFrameCount;

    audio_input_flags_t flags = mFlags;

    pid_t tid = -1;
    input.attr = mAttributes;
    input.config.sample_rate = mSampleRate;
    input.config.channel_mask = mChannelMask;
    input.config.format = mFormat;
    input.clientInfo.clientUid = mClientUid;
    input.clientInfo.clientPid = mClientPid;
    input.clientInfo.clientTid = -1;
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        if (mAudioRecordThread != 0) {
            tid = mAudioRecordThread->getTid();
            input.clientInfo.clientTid = mAudioRecordThread->getTid();
        }
    }
    input.opPackageName = opPackageName;

    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
                                // but we will still need the original value also
    audio_session_t originalSessionId = mSessionId;
    input.flags = mFlags;
    // The notification frame count is the period between callbacks, as suggested by the client
    // but moderated by the server.  For record, the calculations are done entirely on server side.
    input.frameCount = mReqFrameCount;
    input.notificationFrameCount = mNotificationFramesReq;
    input.selectedDeviceId = mSelectedDeviceId;
    input.sessionId = mSessionId;
    originalSessionId = mSessionId;

    sp<IMemory> iMem;           // for cblk
    sp<IMemory> bufferMem;
    sp<media::IAudioRecord> record = audioFlinger->openRecord(input,
                                                              mSampleRate,
                                                              mFormat,
                                                              mChannelMask,
                                                              opPackageName,
                                                              &temp,
                                                              &flags,
                                                              mClientPid,
                                                              tid,
                                                              mClientUid,
                                                              &mSessionId,
                                                              &notificationFrames,
                                                              iMem,
                                                              bufferMem,
                                                              &status,
                                                              mPortId);
    ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
            "session ID changed from %d to %d", originalSessionId, mSessionId);
    record = audioFlinger->createRecord(input,
                                                              output,
                                                              &status);

    if (status != NO_ERROR) {
        ALOGE("AudioFlinger could not create record track, status: %d", status);
        break;
        goto exit;
    }
    ALOG_ASSERT(record != 0);

@@ -689,41 +628,41 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
    // so we are no longer responsible for releasing it.

    mAwaitBoost = false;
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        if (flags & AUDIO_INPUT_FLAG_FAST) {
            ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", frameCount, temp);
    if (output.flags & AUDIO_INPUT_FLAG_FAST) {
        ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
              mReqFrameCount, output.frameCount);
        mAwaitBoost = true;
        } else {
            ALOGW("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", frameCount, temp);
            mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
                    AUDIO_INPUT_FLAG_RAW));
            continue;   // retry
        }
    }
    mFlags = flags;
    mFlags = output.flags;
    mRoutedDeviceId = output.selectedDeviceId;
    mSessionId = output.sessionId;
    mSampleRate = output.sampleRate;

    if (iMem == 0) {
    if (output.cblk == 0) {
        ALOGE("Could not get control block");
        return NO_INIT;
        status = NO_INIT;
        goto exit;
    }
    void *iMemPointer = iMem->pointer();
    iMemPointer = output.cblk ->pointer();
    if (iMemPointer == NULL) {
        ALOGE("Could not get control block pointer");
        return NO_INIT;
        status = NO_INIT;
        goto exit;
    }
    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
    cblk = static_cast<audio_track_cblk_t*>(iMemPointer);

    // Starting address of buffers in shared memory.
    // The buffers are either immediately after the control block,
    // or in a separate area at discretion of server.
    void *buffers;
    if (bufferMem == 0) {
    if (output.buffers == 0) {
        buffers = cblk + 1;
    } else {
        buffers = bufferMem->pointer();
        buffers = output.buffers->pointer();
        if (buffers == NULL) {
            ALOGE("Could not get buffer pointer");
            return NO_INIT;
            status = NO_INIT;
            goto exit;
        }
    }

@@ -733,43 +672,42 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        mDeathNotifier.clear();
    }
    mAudioRecord = record;
    mCblkMemory = iMem;
    mBufferMemory = bufferMem;
    mCblkMemory = output.cblk;
    mBufferMemory = output.buffers;
    IPCThreadState::self()->flushCommands();

    mCblk = cblk;
    // note that temp is the (possibly revised) value of frameCount
    if (temp < frameCount || (frameCount == 0 && temp == 0)) {
        ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp);
    // note that output.frameCount is the (possibly revised) value of mReqFrameCount
    if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) {
        ALOGW("Requested frameCount %zu but received frameCount %zu",
              mReqFrameCount,  output.frameCount);
    }
    frameCount = temp;

    // Make sure that application is notified with sufficient margin before overrun.
    // The computation is done on server side.
    if (mNotificationFramesReq > 0 && notificationFrames != mNotificationFramesReq) {
    if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
        ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu",
                mNotificationFramesReq, notificationFrames, frameCount);
                mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
    }
    mNotificationFramesAct = (uint32_t) notificationFrames;

    mNotificationFramesAct = (uint32_t)output.notificationFrameCount;

    //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
    if (mDeviceCallback != 0 && mInput != input) {
    if (mDeviceCallback != 0 && mInput != output.inputId) {
        if (mInput != AUDIO_IO_HANDLE_NONE) {
            AudioSystem::removeAudioDeviceCallback(this, mInput);
        }
        AudioSystem::addAudioDeviceCallback(this, input);
        AudioSystem::addAudioDeviceCallback(this, output.inputId);
    }

    // We retain a copy of the I/O handle, but don't own the reference
    mInput = input;
    mInput = output.inputId;
    mRefreshRemaining = true;

    mFrameCount = frameCount;
    mFrameCount = output.frameCount;
    // If IAudioRecord is re-created, don't let the requested frameCount
    // decrease.  This can confuse clients that cache frameCount().
    if (frameCount > mReqFrameCount) {
        mReqFrameCount = frameCount;
    if (mFrameCount > mReqFrameCount) {
        mReqFrameCount = mFrameCount;
    }

    // update proxy
@@ -780,17 +718,9 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
    mDeathNotifier = new DeathNotifier(this);
    IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);

    return NO_ERROR;

    // End of retry loop.
    // The lack of indentation is deliberate, to reduce code churn and ease merges.
    }

// Arrive here on error, via a break
    AudioSystem::releaseInput(input, mSessionId);
    if (status == NO_ERROR) {
        status = NO_INIT;
    }
exit:
    mStatus = status;
    // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
    return status;
}

@@ -1222,12 +1152,12 @@ status_t AudioRecord::restoreRecord_l(const char *from)

    mFlags = mOrigFlags;

    // if the new IAudioRecord is created, openRecord_l() will modify the
    // if the new IAudioRecord is created, createRecord_l() will modify the
    // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
    // It will also delete the strong references on previous IAudioRecord and IMemory
    Modulo<uint32_t> position(mProxy->getPosition());
    mNewPosition = position + mUpdatePeriod;
    status_t result = openRecord_l(position, mOpPackageName);
    status_t result = createRecord_l(position, mOpPackageName);
    if (result == NO_ERROR) {
        if (mActive) {
            // callback thread or sync event hasn't changed
+46 −117

File changed.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.media;

/* Native code must specify namespace media (media::IAudioRecord) when referring to this class */
interface IAudioRecord {

  /* After it's created the track is not active. Call start() to
+4 −3
Original line number Diff line number Diff line
@@ -19,12 +19,13 @@
#define ANDROID_AUDIO_CLIENT_H

#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <system/audio.h>
#include <utils/String16.h>

namespace android {

class AudioClient {
class AudioClient : public Parcelable {
 public:
    AudioClient() :
        clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {}
@@ -34,7 +35,7 @@ class AudioClient {
    pid_t clientTid;
    String16 packageName;

    status_t readFromParcel(Parcel *parcel) {
    status_t readFromParcel(const Parcel *parcel) override {
        clientUid = parcel->readInt32();
        clientPid = parcel->readInt32();
        clientTid = parcel->readInt32();
@@ -42,7 +43,7 @@ class AudioClient {
        return NO_ERROR;
    }

    status_t writeToParcel(Parcel *parcel) const {
    status_t writeToParcel(Parcel *parcel) const override {
        parcel->writeInt32(clientUid);
        parcel->writeInt32(clientPid);
        parcel->writeInt32(clientTid);
+1 −2
Original line number Diff line number Diff line
@@ -570,7 +570,7 @@ private:

            // caller must hold lock on mLock for all _l methods

            status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
            status_t createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);

            // FIXME enum is faster than strcmp() for parameter 'from'
            status_t restoreRecord_l(const char *from);
@@ -682,7 +682,6 @@ private:
                                              // May not match the app selection depending on other
                                              // activity and connected devices
    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
    audio_port_handle_t    mPortId;  // unique ID allocated by audio policy

};

Loading