blob: 76e19cfcd81608a6f3eb1921eac2d8323090fdf7 [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
20#include <stdlib.h>
21#include <string.h>
22#include <audio_utils/fifo.h>
23#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080024#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070025#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080026
Glenn Kasten9b4fe472016-06-13 09:34:57 -070027audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer) :
28 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
29 mFudgeFactor(mFrameCountP2 - mFrameCount), mFrameSize(frameSize), mBuffer(buffer),
Glenn Kasten547a9922016-06-15 13:07:31 -070030 mLocalFront(0), mLocalRear(0), mSharedFront(0), mSharedRear(0),
31 mReadObtained(0), mWriteObtained(0)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080032{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070033 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
34 // be able to distinguish successful and error return values from read and write.
35 ALOG_ASSERT(frameCount > 0 && frameSize > 0 && buffer != NULL &&
36 frameCount <= ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080037}
38
Glenn Kasten9b4fe472016-06-13 09:34:57 -070039audio_utils_fifo::~audio_utils_fifo()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080040{
41}
42
Glenn Kasten9b4fe472016-06-13 09:34:57 -070043uint32_t audio_utils_fifo::sum(uint32_t index, uint32_t increment)
44 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080045{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070046 if (mFudgeFactor) {
47 uint32_t mask = mFrameCountP2 - 1;
48 ALOG_ASSERT((index & mask) < mFrameCount);
49 ALOG_ASSERT(increment <= mFrameCountP2);
50 if ((index & mask) + increment >= mFrameCount) {
51 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080052 }
53 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070054 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080055 return index;
56 } else {
57 return index + increment;
58 }
59}
60
Glenn Kasten9b4fe472016-06-13 09:34:57 -070061int32_t audio_utils_fifo::diff(uint32_t rear, uint32_t front)
62 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070064 uint32_t diff = rear - front;
65 if (mFudgeFactor) {
66 uint32_t mask = mFrameCountP2 - 1;
67 uint32_t rearMasked = rear & mask;
68 uint32_t frontMasked = front & mask;
69 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
70 return (int32_t) android::UNKNOWN_ERROR;
71 }
72 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080073 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070074 if (genDiff > mFrameCountP2) {
75 return (int32_t) android::UNKNOWN_ERROR;
76 }
77 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080078 }
79 }
80 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -070081 if (diff > mFrameCount) {
82 return (int32_t) android::UNKNOWN_ERROR;
83 }
84 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080085}
86
Glenn Kasten9b4fe472016-06-13 09:34:57 -070087ssize_t audio_utils_fifo::write(const void *buffer, size_t count)
88 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080089{
Glenn Kasten547a9922016-06-15 13:07:31 -070090 audio_utils_iovec iovec[2];
91 ssize_t availToWrite = writeObtain(iovec, count);
92 if (availToWrite > 0) {
93 memcpy(iovec[0].mBase, buffer, iovec[0].mLen * mFrameSize);
94 if (iovec[1].mLen > 0) {
95 memcpy(iovec[1].mBase, (char *) buffer + (iovec[0].mLen * mFrameSize),
96 iovec[1].mLen * mFrameSize);
97 }
98 writeRelease(availToWrite);
99 }
100 return availToWrite;
101}
102
103ssize_t audio_utils_fifo::writeObtain(audio_utils_iovec iovec[2], size_t count)
104 __attribute__((no_sanitize("integer")))
105{
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700106 uint32_t front = (uint32_t) atomic_load_explicit(&mSharedFront, std::memory_order_acquire);
107 uint32_t rear = mLocalRear;
108 int32_t filled = diff(rear, front);
109 if (filled < 0) {
Glenn Kasten547a9922016-06-15 13:07:31 -0700110 mWriteObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700111 return (ssize_t) filled;
112 }
113 size_t availToWrite = (size_t) mFrameCount - (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800114 if (availToWrite > count) {
115 availToWrite = count;
116 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700117 uint32_t rearMasked = rear & (mFrameCountP2 - 1);
118 size_t part1 = mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800119 if (part1 > availToWrite) {
120 part1 = availToWrite;
121 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700122 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
123 iovec[0].mLen = part1;
124 iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (rearMasked * mFrameSize) : NULL;
125 iovec[1].mLen = part2;
126 iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
127 mWriteObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800128 return availToWrite;
129}
130
Glenn Kasten547a9922016-06-15 13:07:31 -0700131void audio_utils_fifo::writeRelease(size_t count)
132{
133 if (count > 0) {
134 ALOG_ASSERT(count <= mWriteObtained);
135 mLocalRear = sum(mLocalRear, count);
136 atomic_store_explicit(&mSharedRear, (uint_fast32_t) mLocalRear,
137 std::memory_order_release);
138 mWriteObtained -= count;
139 }
140}
141
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700142ssize_t audio_utils_fifo::read(void *buffer, size_t count)
143 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800144{
Glenn Kasten547a9922016-06-15 13:07:31 -0700145 audio_utils_iovec iovec[2];
146 ssize_t availToRead = readObtain(iovec, count);
147 if (availToRead > 0) {
148 memcpy(buffer, iovec[0].mBase, iovec[0].mLen * mFrameSize);
149 if (iovec[1].mLen > 0) {
150 memcpy((char *) buffer + (iovec[0].mLen * mFrameSize), iovec[1].mBase,
151 iovec[1].mLen * mFrameSize);
152 }
153 readRelease(availToRead);
154 }
155 return availToRead;
156}
157
158ssize_t audio_utils_fifo::readObtain(audio_utils_iovec iovec[2], size_t count)
159 __attribute__((no_sanitize("integer")))
160{
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700161 uint32_t rear = (uint32_t) atomic_load_explicit(&mSharedRear, std::memory_order_acquire);
162 uint32_t front = mLocalFront;
163 int32_t filled = diff(rear, front);
164 if (filled < 0) {
Glenn Kasten547a9922016-06-15 13:07:31 -0700165 mReadObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700166 return (ssize_t) filled;
167 }
168 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800169 if (availToRead > count) {
170 availToRead = count;
171 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700172 uint32_t frontMasked = front & (mFrameCountP2 - 1);
173 size_t part1 = mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800174 if (part1 > availToRead) {
175 part1 = availToRead;
176 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700177 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
178 iovec[0].mLen = part1;
179 iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (frontMasked * mFrameSize) : NULL;
180 iovec[1].mLen = part2;
181 iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
182 mReadObtained = availToRead;
183 return availToRead;
184}
185
186void audio_utils_fifo::readRelease(size_t count)
187{
188 if (count > 0) {
189 ALOG_ASSERT(count <= mReadObtained);
190 mLocalFront = sum(mLocalFront, count);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700191 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
192 std::memory_order_release);
Glenn Kasten547a9922016-06-15 13:07:31 -0700193 mReadObtained -= count;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800194 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800195}