fifo.cpp revision 547a99206f741bbe5adacd9bf8b75c2d6b2aff0d
19b4c805bc22842480690f14826b729845887963aGlenn Kasten/*
29b4c805bc22842480690f14826b729845887963aGlenn Kasten * Copyright (C) 2015 The Android Open Source Project
39b4c805bc22842480690f14826b729845887963aGlenn Kasten *
49b4c805bc22842480690f14826b729845887963aGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
59b4c805bc22842480690f14826b729845887963aGlenn Kasten * you may not use this file except in compliance with the License.
69b4c805bc22842480690f14826b729845887963aGlenn Kasten * You may obtain a copy of the License at
79b4c805bc22842480690f14826b729845887963aGlenn Kasten *
89b4c805bc22842480690f14826b729845887963aGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
99b4c805bc22842480690f14826b729845887963aGlenn Kasten *
109b4c805bc22842480690f14826b729845887963aGlenn Kasten * Unless required by applicable law or agreed to in writing, software
119b4c805bc22842480690f14826b729845887963aGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
129b4c805bc22842480690f14826b729845887963aGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139b4c805bc22842480690f14826b729845887963aGlenn Kasten * See the License for the specific language governing permissions and
149b4c805bc22842480690f14826b729845887963aGlenn Kasten * limitations under the License.
159b4c805bc22842480690f14826b729845887963aGlenn Kasten */
169b4c805bc22842480690f14826b729845887963aGlenn Kasten
179b4c805bc22842480690f14826b729845887963aGlenn Kasten//#define LOG_NDEBUG 0
189b4c805bc22842480690f14826b729845887963aGlenn Kasten#define LOG_TAG "audio_utils_fifo"
199b4c805bc22842480690f14826b729845887963aGlenn Kasten
209b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <stdlib.h>
219b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <string.h>
229b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/fifo.h>
239b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/roundup.h>
249b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <cutils/log.h>
259b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten#include <utils/Errors.h>
269b4c805bc22842480690f14826b729845887963aGlenn Kasten
279b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer) :
289b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
299b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    mFudgeFactor(mFrameCountP2 - mFrameCount), mFrameSize(frameSize), mBuffer(buffer),
30547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    mLocalFront(0), mLocalRear(0), mSharedFront(0), mSharedRear(0),
31547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    mReadObtained(0), mWriteObtained(0)
329b4c805bc22842480690f14826b729845887963aGlenn Kasten{
339b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
349b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    // be able to distinguish successful and error return values from read and write.
359b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    ALOG_ASSERT(frameCount > 0 && frameSize > 0 && buffer != NULL &&
369b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            frameCount <= ((uint32_t) INT_MAX) / frameSize);
379b4c805bc22842480690f14826b729845887963aGlenn Kasten}
389b4c805bc22842480690f14826b729845887963aGlenn Kasten
399b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenaudio_utils_fifo::~audio_utils_fifo()
409b4c805bc22842480690f14826b729845887963aGlenn Kasten{
419b4c805bc22842480690f14826b729845887963aGlenn Kasten}
429b4c805bc22842480690f14826b729845887963aGlenn Kasten
439b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenuint32_t audio_utils_fifo::sum(uint32_t index, uint32_t increment)
449b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
459b4c805bc22842480690f14826b729845887963aGlenn Kasten{
469b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
479b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
489b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
499b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT(increment <= mFrameCountP2);
509b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        if ((index & mask) + increment >= mFrameCount) {
519b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            increment += mFudgeFactor;
529b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
539b4c805bc22842480690f14826b729845887963aGlenn Kasten        index += increment;
549b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
559b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index;
569b4c805bc22842480690f14826b729845887963aGlenn Kasten    } else {
579b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index + increment;
589b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
599b4c805bc22842480690f14826b729845887963aGlenn Kasten}
609b4c805bc22842480690f14826b729845887963aGlenn Kasten
619b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenint32_t audio_utils_fifo::diff(uint32_t rear, uint32_t front)
629b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
639b4c805bc22842480690f14826b729845887963aGlenn Kasten{
649b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t diff = rear - front;
659b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
669b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
679b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t rearMasked = rear & mask;
689b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t frontMasked = front & mask;
699b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
709b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            return (int32_t) android::UNKNOWN_ERROR;
719b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        }
729b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t genDiff = (rear & ~mask) - (front & ~mask);
739b4c805bc22842480690f14826b729845887963aGlenn Kasten        if (genDiff != 0) {
749b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            if (genDiff > mFrameCountP2) {
759b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten                return (int32_t) android::UNKNOWN_ERROR;
769b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            }
779b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            diff -= mFudgeFactor;
789b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
799b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
809b4c805bc22842480690f14826b729845887963aGlenn Kasten    // FIFO should not be overfull
819b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (diff > mFrameCount) {
829b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        return (int32_t) android::UNKNOWN_ERROR;
839b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
849b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    return (int32_t) diff;
859b4c805bc22842480690f14826b729845887963aGlenn Kasten}
869b4c805bc22842480690f14826b729845887963aGlenn Kasten
879b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenssize_t audio_utils_fifo::write(const void *buffer, size_t count)
889b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
899b4c805bc22842480690f14826b729845887963aGlenn Kasten{
90547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
91547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    ssize_t availToWrite = writeObtain(iovec, count);
92547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToWrite > 0) {
93547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        memcpy(iovec[0].mBase, buffer, iovec[0].mLen * mFrameSize);
94547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        if (iovec[1].mLen > 0) {
95547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten            memcpy(iovec[1].mBase, (char *) buffer + (iovec[0].mLen * mFrameSize),
96547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten                    iovec[1].mLen * mFrameSize);
97547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
98547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        writeRelease(availToWrite);
99547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
100547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToWrite;
101547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
102547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
103547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kastenssize_t audio_utils_fifo::writeObtain(audio_utils_iovec iovec[2], size_t count)
104547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
105547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
1069b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t front = (uint32_t) atomic_load_explicit(&mSharedFront, std::memory_order_acquire);
1079b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t rear = mLocalRear;
1089b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    int32_t filled = diff(rear, front);
1099b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (filled < 0) {
110547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mWriteObtained = 0;
1119b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        return (ssize_t) filled;
1129b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
1139b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t availToWrite = (size_t) mFrameCount - (size_t) filled;
1149b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToWrite > count) {
1159b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToWrite = count;
1169b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1179b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t rearMasked = rear & (mFrameCountP2 - 1);
1189b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t part1 = mFrameCount - rearMasked;
1199b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToWrite) {
1209b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToWrite;
1219b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
122547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
123547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[0].mLen = part1;
124547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (rearMasked * mFrameSize) : NULL;
125547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[1].mLen = part2;
126547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
127547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    mWriteObtained = availToWrite;
128547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToWrite;
129547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
130547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
131547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kastenvoid audio_utils_fifo::writeRelease(size_t count)
132547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
133547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (count > 0) {
134547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        ALOG_ASSERT(count <= mWriteObtained);
135547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mLocalRear = sum(mLocalRear, count);
1369b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        atomic_store_explicit(&mSharedRear, (uint_fast32_t) mLocalRear,
1379b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten                std::memory_order_release);
138547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mWriteObtained -= count;
1399b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1409b4c805bc22842480690f14826b729845887963aGlenn Kasten}
1419b4c805bc22842480690f14826b729845887963aGlenn Kasten
1429b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kastenssize_t audio_utils_fifo::read(void *buffer, size_t count)
1439b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
1449b4c805bc22842480690f14826b729845887963aGlenn Kasten{
145547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
146547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    ssize_t availToRead = readObtain(iovec, count);
147547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToRead > 0) {
148547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        memcpy(buffer, iovec[0].mBase, iovec[0].mLen * mFrameSize);
149547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        if (iovec[1].mLen > 0) {
150547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten            memcpy((char *) buffer + (iovec[0].mLen * mFrameSize), iovec[1].mBase,
151547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten                    iovec[1].mLen * mFrameSize);
152547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
153547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        readRelease(availToRead);
154547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
155547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToRead;
156547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
157547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
158547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kastenssize_t audio_utils_fifo::readObtain(audio_utils_iovec iovec[2], size_t count)
159547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
160547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
1619b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t rear = (uint32_t) atomic_load_explicit(&mSharedRear, std::memory_order_acquire);
1629b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t front = mLocalFront;
1639b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    int32_t filled = diff(rear, front);
1649b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (filled < 0) {
165547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mReadObtained = 0;
1669b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        return (ssize_t) filled;
1679b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
1689b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t availToRead = (size_t) filled;
1699b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToRead > count) {
1709b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToRead = count;
1719b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1729b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t frontMasked = front & (mFrameCountP2 - 1);
1739b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t part1 = mFrameCount - frontMasked;
1749b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToRead) {
1759b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToRead;
1769b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
177547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToRead - part1 : 0;
178547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[0].mLen = part1;
179547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (frontMasked * mFrameSize) : NULL;
180547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[1].mLen = part2;
181547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
182547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    mReadObtained = availToRead;
183547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToRead;
184547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
185547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
186547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kastenvoid audio_utils_fifo::readRelease(size_t count)
187547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
188547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (count > 0) {
189547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        ALOG_ASSERT(count <= mReadObtained);
190547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mLocalFront = sum(mLocalFront, count);
1919b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
1929b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten                std::memory_order_release);
193547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        mReadObtained -= count;
1949b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1959b4c805bc22842480690f14826b729845887963aGlenn Kasten}
196