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

Commit 397435cb authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "Refactor AudioTrack callback to Interface"

parents ceed2a8e f86d269d
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -103,7 +103,7 @@ aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
            : getFormat();
            : getFormat();


    // Setup the callback if there is one.
    // Setup the callback if there is one.
    AudioTrack::callback_t callback = nullptr;
    AudioTrack::legacy_callback_t callback = nullptr;
    void *callbackData = nullptr;
    void *callbackData = nullptr;
    // Note that TRANSFER_SYNC does not allow FAST track
    // Note that TRANSFER_SYNC does not allow FAST track
    AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC;
    AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC;
+189 −40
Original line number Original line Diff line number Diff line
@@ -254,8 +254,7 @@ AudioTrack::AudioTrack(
        audio_channel_mask_t channelMask,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        size_t frameCount,
        audio_output_flags_t flags,
        audio_output_flags_t flags,
        callback_t cbf,
        const wp<IAudioTrackCallback> & callback,
        void* user,
        int32_t notificationFrames,
        int32_t notificationFrames,
        audio_session_t sessionId,
        audio_session_t sessionId,
        transfer_type transferType,
        transfer_type transferType,
@@ -275,19 +274,60 @@ AudioTrack::AudioTrack(
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;


    (void)set(streamType, sampleRate, format, channelMask,
    (void)set(streamType, sampleRate, format, channelMask,
            frameCount, flags, cbf, user, notificationFrames,
            frameCount, flags, callback, notificationFrames,
            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
}


namespace {
    class LegacyCallbackWrapper : public AudioTrack::IAudioTrackCallback {
      const AudioTrack::legacy_callback_t mCallback;
      void * const mData;
      public:
        LegacyCallbackWrapper(AudioTrack::legacy_callback_t callback, void* user)
            : mCallback(callback), mData(user) {}
        size_t onMoreData(const AudioTrack::Buffer & buffer) override {
          AudioTrack::Buffer copy = buffer;
          mCallback(AudioTrack::EVENT_MORE_DATA, mData, static_cast<void*>(&copy));
          return copy.size;
        }
        void onUnderrun() override {
            mCallback(AudioTrack::EVENT_UNDERRUN, mData, nullptr);
        }
        void onLoopEnd(int32_t loopsRemaining) override {
            mCallback(AudioTrack::EVENT_LOOP_END, mData, &loopsRemaining);
        }
        void onMarker(uint32_t markerPosition) override {
            mCallback(AudioTrack::EVENT_MARKER, mData, &markerPosition);
        }
        void onNewPos(uint32_t newPos) override {
            mCallback(AudioTrack::EVENT_NEW_POS, mData, &newPos);
        }
        void onBufferEnd() override {
            mCallback(AudioTrack::EVENT_BUFFER_END, mData, nullptr);
        }
        void onNewIAudioTrack() override {
            mCallback(AudioTrack::EVENT_NEW_IAUDIOTRACK, mData, nullptr);
        }
        void onStreamEnd() override {
            mCallback(AudioTrack::EVENT_STREAM_END, mData, nullptr);
        }
        size_t onCanWriteMoreData(const AudioTrack::Buffer & buffer) override {
          AudioTrack::Buffer copy = buffer;
          mCallback(AudioTrack::EVENT_CAN_WRITE_MORE_DATA, mData, static_cast<void*>(&copy));
          return copy.size;
        }
    };
}

AudioTrack::AudioTrack(
AudioTrack::AudioTrack(
        audio_stream_type_t streamType,
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        uint32_t sampleRate,
        audio_format_t format,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        audio_channel_mask_t channelMask,
        const sp<IMemory>& sharedBuffer,
        size_t frameCount,
        audio_output_flags_t flags,
        audio_output_flags_t flags,
        callback_t cbf,
        legacy_callback_t callback,
        void* user,
        void* user,
        int32_t notificationFrames,
        int32_t notificationFrames,
        audio_session_t sessionId,
        audio_session_t sessionId,
@@ -296,6 +336,42 @@ AudioTrack::AudioTrack(
        const AttributionSourceState& attributionSource,
        const AttributionSourceState& attributionSource,
        const audio_attributes_t* pAttributes,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        bool doNotReconnect,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
    : mStatus(NO_INIT),
      mState(STATE_STOPPED),
      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
      mPreviousSchedulingGroup(SP_DEFAULT),
      mPausedPosition(0),
      mAudioTrackCallback(new AudioTrackCallback())
{
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    if (callback != nullptr) {
        mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
    }
    (void)set(streamType, sampleRate, format, channelMask,
            frameCount, flags, mLegacyCallbackWrapper, notificationFrames,
            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}

AudioTrack::AudioTrack(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        const sp<IMemory>& sharedBuffer,
        audio_output_flags_t flags,
        const wp<IAudioTrackCallback>& callback,
        int32_t notificationFrames,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        const AttributionSourceState& attributionSource,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed)
        float maxRequiredSpeed)
    : mStatus(NO_INIT),
    : mStatus(NO_INIT),
      mState(STATE_STOPPED),
      mState(STATE_STOPPED),
@@ -308,11 +384,49 @@ AudioTrack::AudioTrack(
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;


    (void)set(streamType, sampleRate, format, channelMask,
    (void)set(streamType, sampleRate, format, channelMask,
            0 /*frameCount*/, flags, cbf, user, notificationFrames,
            0 /*frameCount*/, flags, callback, notificationFrames,
            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed);
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed);
}
}


AudioTrack::AudioTrack(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        const sp<IMemory>& sharedBuffer,
        audio_output_flags_t flags,
        legacy_callback_t callback,
        void* user,
        int32_t notificationFrames,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        const AttributionSourceState& attributionSource,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed)
    : mStatus(NO_INIT),
      mState(STATE_STOPPED),
      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
      mPreviousSchedulingGroup(SP_DEFAULT),
      mPausedPosition(0),
      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mAudioTrackCallback(new AudioTrackCallback())
{
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    if (callback) {
        mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
    }

    (void)set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
              mLegacyCallbackWrapper, notificationFrames, sharedBuffer,
              false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, attributionSource,
              pAttributes, doNotReconnect, maxRequiredSpeed);
}

AudioTrack::~AudioTrack()
AudioTrack::~AudioTrack()
{
{
    // pull together the numbers, before we clean up our structures
    // pull together the numbers, before we clean up our structures
@@ -374,7 +488,7 @@ status_t AudioTrack::set(
        audio_channel_mask_t channelMask,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        size_t frameCount,
        audio_output_flags_t flags,
        audio_output_flags_t flags,
        callback_t cbf,
        legacy_callback_t callback,
        void * user,
        void * user,
        int32_t notificationFrames,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        const sp<IMemory>& sharedBuffer,
@@ -387,6 +501,36 @@ status_t AudioTrack::set(
        bool doNotReconnect,
        bool doNotReconnect,
        float maxRequiredSpeed,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
        audio_port_handle_t selectedDeviceId)
{
    if (callback) {
        mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
    }
    return set(streamType, sampleRate,format, channelMask, frameCount, flags,
               mLegacyCallbackWrapper, notificationFrames, sharedBuffer, threadCanCallJava,
               sessionId, transferType, offloadInfo, attributionSource, pAttributes,
               doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
status_t AudioTrack::set(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        audio_output_flags_t flags,
        const wp<IAudioTrackCallback>& callback,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        bool threadCanCallJava,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        const AttributionSourceState& attributionSource,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
{
{
    status_t status;
    status_t status;
    uint32_t channelCount;
    uint32_t channelCount;
@@ -394,7 +538,7 @@ status_t AudioTrack::set(
    pid_t myPid;
    pid_t myPid;
    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
    pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));

    sp<IAudioTrackCallback> _callback = callback.promote();
    // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
    // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
    ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
    ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
          "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
          "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -410,7 +554,7 @@ status_t AudioTrack::set(
    case TRANSFER_DEFAULT:
    case TRANSFER_DEFAULT:
        if (sharedBuffer != 0) {
        if (sharedBuffer != 0) {
            transferType = TRANSFER_SHARED;
            transferType = TRANSFER_SHARED;
        } else if (cbf == NULL || threadCanCallJava) {
        } else if (_callback == nullptr|| threadCanCallJava) {
            transferType = TRANSFER_SYNC;
            transferType = TRANSFER_SYNC;
        } else {
        } else {
            transferType = TRANSFER_CALLBACK;
            transferType = TRANSFER_CALLBACK;
@@ -418,8 +562,8 @@ status_t AudioTrack::set(
        break;
        break;
    case TRANSFER_CALLBACK:
    case TRANSFER_CALLBACK:
    case TRANSFER_SYNC_NOTIF_CALLBACK:
    case TRANSFER_SYNC_NOTIF_CALLBACK:
        if (cbf == NULL || sharedBuffer != 0) {
        if (_callback == nullptr || sharedBuffer != 0) {
            ALOGE("%s(): Transfer type %s but cbf == NULL || sharedBuffer != 0",
            ALOGE("%s(): Transfer type %s but callback == nullptr || sharedBuffer != 0",
                    convertTransferToText(transferType), __func__);
                    convertTransferToText(transferType), __func__);
            status = BAD_VALUE;
            status = BAD_VALUE;
            goto exit;
            goto exit;
@@ -609,10 +753,10 @@ status_t AudioTrack::set(
    }
    }
    mAuxEffectId = 0;
    mAuxEffectId = 0;
    mOrigFlags = mFlags = flags;
    mOrigFlags = mFlags = flags;
    mCbf = cbf;
    mCallback = callback;


    if (cbf != NULL) {
    if (_callback != nullptr) {
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread = sp<AudioTrackThread>::make(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        // thread begins in paused state, and will not reference us until start()
        // thread begins in paused state, and will not reference us until start()
    }
    }
@@ -631,7 +775,6 @@ status_t AudioTrack::set(
        goto exit;
        goto exit;
    }
    }


    mUserData = user;
    mLoopCount = 0;
    mLoopCount = 0;
    mLoopStart = 0;
    mLoopStart = 0;
    mLoopEnd = 0;
    mLoopEnd = 0;
@@ -675,7 +818,7 @@ status_t AudioTrack::set(
        uint32_t channelMask,
        uint32_t channelMask,
        size_t frameCount,
        size_t frameCount,
        audio_output_flags_t flags,
        audio_output_flags_t flags,
        callback_t cbf,
        legacy_callback_t callback,
        void* user,
        void* user,
        int32_t notificationFrames,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        const sp<IMemory>& sharedBuffer,
@@ -694,9 +837,13 @@ status_t AudioTrack::set(
    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
    attributionSource.token = sp<BBinder>::make();
    attributionSource.token = sp<BBinder>::make();
    return set(streamType, sampleRate, format,
    if (callback) {
            static_cast<audio_channel_mask_t>(channelMask),
        mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
            frameCount, flags, cbf, user, notificationFrames, sharedBuffer,
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
    }
    return set(streamType, sampleRate, format, static_cast<audio_channel_mask_t>(channelMask),
               frameCount, flags, mLegacyCallbackWrapper, notificationFrames, sharedBuffer,
               threadCanCallJava, sessionId, transferType, offloadInfo, attributionSource,
               threadCanCallJava, sessionId, transferType, offloadInfo, attributionSource,
               pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
               pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
}
@@ -1407,7 +1554,7 @@ void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
status_t AudioTrack::setMarkerPosition(uint32_t marker)
status_t AudioTrack::setMarkerPosition(uint32_t marker)
{
{
    // The only purpose of setting marker position is to get a callback
    // The only purpose of setting marker position is to get a callback
    if (mCbf == NULL || isOffloadedOrDirect()) {
    if (!mCallback.promote() || isOffloadedOrDirect()) {
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }


@@ -1440,7 +1587,7 @@ status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
{
{
    // The only purpose of setting position update period is to get a callback
    // The only purpose of setting position update period is to get a callback
    if (mCbf == NULL || isOffloadedOrDirect()) {
    if (!mCallback.promote() || isOffloadedOrDirect()) {
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }


@@ -2209,10 +2356,14 @@ nsecs_t AudioTrack::processAudioBuffer()
{
{
    // Currently the AudioTrack thread is not created if there are no callbacks.
    // Currently the AudioTrack thread is not created if there are no callbacks.
    // Would it ever make sense to run the thread, even without callbacks?
    // Would it ever make sense to run the thread, even without callbacks?
    // If so, then replace this by checks at each use for mCbf != NULL.
    // If so, then replace this by checks at each use for mCallback != NULL.
    LOG_ALWAYS_FATAL_IF(mCblk == NULL);
    LOG_ALWAYS_FATAL_IF(mCblk == NULL);

    mLock.lock();
    mLock.lock();
    sp<IAudioTrackCallback> callback = mCallback.promote();
    if (!callback) {
        mCallback = nullptr;
        return NS_NEVER;
    }
    if (mAwaitBoost) {
    if (mAwaitBoost) {
        mAwaitBoost = false;
        mAwaitBoost = false;
        mLock.unlock();
        mLock.unlock();
@@ -2310,7 +2461,7 @@ nsecs_t AudioTrack::processAudioBuffer()
    sp<AudioTrackClientProxy> proxy = mProxy;
    sp<AudioTrackClientProxy> proxy = mProxy;


    // Determine the number of new loop callback(s) that will be needed, while locked.
    // Determine the number of new loop callback(s) that will be needed, while locked.
    int loopCountNotifications = 0;
    uint32_t loopCountNotifications = 0;
    uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END
    uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END


    if (mLoopCount > 0) {
    if (mLoopCount > 0) {
@@ -2332,7 +2483,7 @@ nsecs_t AudioTrack::processAudioBuffer()
    }
    }


    // These fields don't need to be cached, because they are assigned only by set():
    // These fields don't need to be cached, because they are assigned only by set():
    //     mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFlags
    // mTransfer, mCallback, mUserData, mFormat, mFrameSize, mFlags
    // mFlags is also assigned by createTrack_l(), but not the bit we care about.
    // mFlags is also assigned by createTrack_l(), but not the bit we care about.


    mLock.unlock();
    mLock.unlock();
@@ -2357,7 +2508,7 @@ nsecs_t AudioTrack::processAudioBuffer()
            if (status != DEAD_OBJECT) {
            if (status != DEAD_OBJECT) {
                // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
                // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
                // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
                // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
                mCbf(EVENT_STREAM_END, mUserData, NULL);
                callback->onStreamEnd();
            }
            }
            {
            {
                AutoMutex lock(mLock);
                AutoMutex lock(mLock);
@@ -2380,28 +2531,27 @@ nsecs_t AudioTrack::processAudioBuffer()


    // perform callbacks while unlocked
    // perform callbacks while unlocked
    if (newUnderrun) {
    if (newUnderrun) {
        mCbf(EVENT_UNDERRUN, mUserData, NULL);
        callback->onUnderrun();
    }
    }
    while (loopCountNotifications > 0) {
    while (loopCountNotifications > 0) {
        mCbf(EVENT_LOOP_END, mUserData, NULL);
        --loopCountNotifications;
        --loopCountNotifications;
        callback->onLoopEnd(mLoopCount > 0 ? loopCountNotifications + mLoopCountNotified : -1);
    }
    }
    if (flags & CBLK_BUFFER_END) {
    if (flags & CBLK_BUFFER_END) {
        mCbf(EVENT_BUFFER_END, mUserData, NULL);
        callback->onBufferEnd();
    }
    }
    if (markerReached) {
    if (markerReached) {
        mCbf(EVENT_MARKER, mUserData, &markerPosition);
        callback->onMarker(markerPosition.value());
    }
    }
    while (newPosCount > 0) {
    while (newPosCount > 0) {
        size_t temp = newPosition.value(); // FIXME size_t != uint32_t
        callback->onNewPos(newPosition.value());
        mCbf(EVENT_NEW_POS, mUserData, &temp);
        newPosition += updatePeriod;
        newPosition += updatePeriod;
        newPosCount--;
        newPosCount--;
    }
    }


    if (mObservedSequence != sequence) {
    if (mObservedSequence != sequence) {
        mObservedSequence = sequence;
        mObservedSequence = sequence;
        mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL);
        callback->onNewIAudioTrack();
        // for offloaded tracks, just wait for the upper layers to recreate the track
        // for offloaded tracks, just wait for the upper layers to recreate the track
        if (isOffloadedOrDirect()) {
        if (isOffloadedOrDirect()) {
            return NS_INACTIVE;
            return NS_INACTIVE;
@@ -2539,10 +2689,9 @@ nsecs_t AudioTrack::processAudioBuffer()
            // written in the next write() call, since it's not passed through the callback
            // written in the next write() call, since it's not passed through the callback
            audioBuffer.size += nonContig;
            audioBuffer.size += nonContig;
        }
        }
        mCbf(mTransfer == TRANSFER_CALLBACK ? EVENT_MORE_DATA : EVENT_CAN_WRITE_MORE_DATA,
        size_t writtenSize = (mTransfer == TRANSFER_CALLBACK)
                mUserData, &audioBuffer);
                                      ? callback->onMoreData(audioBuffer)
        size_t writtenSize = audioBuffer.size;
                                      : callback->onCanWriteMoreData(audioBuffer);

        // Validate on returned size
        // Validate on returned size
        if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
        if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
            ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
            ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
+121 −21

File changed.

Preview size limit exceeded, changes collapsed.