1 /*
2 * Copyright (C) 2012 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 #include <inttypes.h>
18
19 #define LOG_TAG "MonoPipe"
20 //#define LOG_NDEBUG 0
21
22 #include <cutils/atomic.h>
23 #include <cutils/compiler.h>
24 #include <utils/Log.h>
25 #include <utils/Trace.h>
26 #include <media/AudioBufferProvider.h>
27 #include <media/nbaio/MonoPipe.h>
28 #include <audio_utils/roundup.h>
29
30
31 namespace android {
32
MonoPipe(size_t reqFrames,const NBAIO_Format & format,bool writeCanBlock)33 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
34 NBAIO_Sink(format),
35 mReqFrames(reqFrames),
36 mMaxFrames(roundup(reqFrames)),
37 mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
38 mFront(0),
39 mRear(0),
40 mWriteTsValid(false),
41 // mWriteTs
42 mSetpoint((reqFrames * 11) / 16),
43 mWriteCanBlock(writeCanBlock),
44 mIsShutdown(false),
45 // mTimestampShared
46 mTimestampMutator(&mTimestampShared),
47 mTimestampObserver(&mTimestampShared)
48 {
49 }
50
~MonoPipe()51 MonoPipe::~MonoPipe()
52 {
53 free(mBuffer);
54 }
55
availableToWrite() const56 ssize_t MonoPipe::availableToWrite() const
57 {
58 if (CC_UNLIKELY(!mNegotiated)) {
59 return NEGOTIATE;
60 }
61 // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
62 ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
63 ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
64 return ret;
65 }
66
write(const void * buffer,size_t count)67 ssize_t MonoPipe::write(const void *buffer, size_t count)
68 {
69 if (CC_UNLIKELY(!mNegotiated)) {
70 return NEGOTIATE;
71 }
72 size_t totalFramesWritten = 0;
73 while (count > 0) {
74 // can't return a negative value, as we already checked for !mNegotiated
75 size_t avail = availableToWrite();
76 size_t written = avail;
77 if (CC_LIKELY(written > count)) {
78 written = count;
79 }
80 size_t rear = mRear & (mMaxFrames - 1);
81 size_t part1 = mMaxFrames - rear;
82 if (part1 > written) {
83 part1 = written;
84 }
85 if (CC_LIKELY(part1 > 0)) {
86 memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize);
87 if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
88 size_t part2 = written - part1;
89 if (CC_LIKELY(part2 > 0)) {
90 memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
91 }
92 }
93 android_atomic_release_store(written + mRear, &mRear);
94 totalFramesWritten += written;
95 }
96 if (!mWriteCanBlock || mIsShutdown) {
97 break;
98 }
99 count -= written;
100 buffer = (char *) buffer + (written * mFrameSize);
101 // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
102 // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
103 uint32_t ns;
104 if (written > 0) {
105 size_t filled = (mMaxFrames - avail) + written;
106 // FIXME cache these values to avoid re-computation
107 if (filled <= mSetpoint / 2) {
108 // pipe is (nearly) empty, fill quickly
109 ns = written * ( 500000000 / Format_sampleRate(mFormat));
110 } else if (filled <= (mSetpoint * 3) / 4) {
111 // pipe is below setpoint, fill at slightly faster rate
112 ns = written * ( 750000000 / Format_sampleRate(mFormat));
113 } else if (filled <= (mSetpoint * 5) / 4) {
114 // pipe is at setpoint, fill at nominal rate
115 ns = written * (1000000000 / Format_sampleRate(mFormat));
116 } else if (filled <= (mSetpoint * 3) / 2) {
117 // pipe is above setpoint, fill at slightly slower rate
118 ns = written * (1150000000 / Format_sampleRate(mFormat));
119 } else if (filled <= (mSetpoint * 7) / 4) {
120 // pipe is overflowing, fill slowly
121 ns = written * (1350000000 / Format_sampleRate(mFormat));
122 } else {
123 // pipe is severely overflowing
124 ns = written * (1750000000 / Format_sampleRate(mFormat));
125 }
126 } else {
127 ns = count * (1350000000 / Format_sampleRate(mFormat));
128 }
129 if (ns > 999999999) {
130 ns = 999999999;
131 }
132 struct timespec nowTs;
133 bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
134 // deduct the elapsed time since previous write() completed
135 if (nowTsValid && mWriteTsValid) {
136 time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
137 long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
138 ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
139 "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
140 mWriteTs.tv_sec, mWriteTs.tv_nsec, nowTs.tv_sec, nowTs.tv_nsec);
141 if (nsec < 0) {
142 --sec;
143 nsec += 1000000000;
144 }
145 if (sec == 0) {
146 if ((long) ns > nsec) {
147 ns -= nsec;
148 } else {
149 ns = 0;
150 }
151 }
152 }
153 if (ns > 0) {
154 const struct timespec req = {0, static_cast<long>(ns)};
155 nanosleep(&req, NULL);
156 }
157 // record the time that this write() completed
158 if (nowTsValid) {
159 mWriteTs = nowTs;
160 if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
161 mWriteTs.tv_nsec -= 1000000000;
162 ++mWriteTs.tv_sec;
163 }
164 }
165 mWriteTsValid = nowTsValid;
166 }
167 mFramesWritten += totalFramesWritten;
168 return totalFramesWritten;
169 }
170
setAvgFrames(size_t setpoint)171 void MonoPipe::setAvgFrames(size_t setpoint)
172 {
173 mSetpoint = setpoint;
174 }
175
shutdown(bool newState)176 void MonoPipe::shutdown(bool newState)
177 {
178 mIsShutdown = newState;
179 }
180
isShutdown()181 bool MonoPipe::isShutdown()
182 {
183 return mIsShutdown;
184 }
185
getTimestamp(ExtendedTimestamp & timestamp)186 status_t MonoPipe::getTimestamp(ExtendedTimestamp ×tamp)
187 {
188 ExtendedTimestamp ets;
189 if (mTimestampObserver.poll(ets)) {
190 timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
191 ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
192 timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
193 ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
194 return OK;
195 }
196 return INVALID_OPERATION;
197 }
198
199 } // namespace android
200