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