blob: 8d1cb0fba986d52ded201978e07ddbb5a2e744f7 [file] [log] [blame]
Glenn Kasten01066232012-02-27 11:50:44 -08001/*
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
Mark Salyzyn0f6a0432014-06-18 16:32:00 -070017#include <inttypes.h>
18
Glenn Kasten01066232012-02-27 11:50:44 -080019#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>
Glenn Kasten28ed2f92012-06-07 10:17:54 -070025#include <utils/Trace.h>
Glenn Kasten2dd4bdd2012-08-29 11:10:32 -070026#include <media/AudioBufferProvider.h>
27#include <media/nbaio/MonoPipe.h>
Glenn Kasten53dbe772015-01-06 10:46:38 -080028#include <audio_utils/roundup.h>
Glenn Kasten01066232012-02-27 11:50:44 -080029
John Grossman2c3b2da2012-08-02 17:08:54 -070030
Glenn Kasten01066232012-02-27 11:50:44 -080031namespace android {
32
Glenn Kasten72e54af2014-01-31 09:37:35 -080033MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
Glenn Kasten01066232012-02-27 11:50:44 -080034 NBAIO_Sink(format),
Glenn Kasten820ba702012-05-30 16:34:17 -070035 mReqFrames(reqFrames),
36 mMaxFrames(roundup(reqFrames)),
Glenn Kasten01066232012-02-27 11:50:44 -080037 mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
38 mFront(0),
39 mRear(0),
Glenn Kasten28ed2f92012-06-07 10:17:54 -070040 mWriteTsValid(false),
41 // mWriteTs
42 mSetpoint((reqFrames * 11) / 16),
Glenn Kasten003d9f72012-09-28 12:22:52 -070043 mWriteCanBlock(writeCanBlock),
Glenn Kastena07a1c22013-08-23 10:54:35 -070044 mIsShutdown(false),
45 // mTimestampShared
46 mTimestampMutator(&mTimestampShared),
47 mTimestampObserver(&mTimestampShared)
Glenn Kasten01066232012-02-27 11:50:44 -080048{
Glenn Kasten01066232012-02-27 11:50:44 -080049}
50
51MonoPipe::~MonoPipe()
52{
53 free(mBuffer);
54}
55
56ssize_t MonoPipe::availableToWrite() const
57{
58 if (CC_UNLIKELY(!mNegotiated)) {
59 return NEGOTIATE;
60 }
Glenn Kasten820ba702012-05-30 16:34:17 -070061 // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
Glenn Kasten01066232012-02-27 11:50:44 -080062 ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
63 ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
64 return ret;
65}
66
67ssize_t MonoPipe::write(const void *buffer, size_t count)
68{
Glenn Kasten01066232012-02-27 11:50:44 -080069 if (CC_UNLIKELY(!mNegotiated)) {
70 return NEGOTIATE;
71 }
72 size_t totalFramesWritten = 0;
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070073 while (count > 0) {
Glenn Kasten820ba702012-05-30 16:34:17 -070074 // can't return a negative value, as we already checked for !mNegotiated
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070075 size_t avail = availableToWrite();
76 size_t written = avail;
Glenn Kasten01066232012-02-27 11:50:44 -080077 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)) {
Glenn Kasten4d693d62014-03-06 07:53:11 -080086 memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize);
Glenn Kasten01066232012-02-27 11:50:44 -080087 if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
88 size_t part2 = written - part1;
89 if (CC_LIKELY(part2 > 0)) {
Glenn Kasten4d693d62014-03-06 07:53:11 -080090 memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
Glenn Kasten01066232012-02-27 11:50:44 -080091 }
92 }
93 android_atomic_release_store(written + mRear, &mRear);
94 totalFramesWritten += written;
95 }
Glenn Kasten003d9f72012-09-28 12:22:52 -070096 if (!mWriteCanBlock || mIsShutdown) {
Glenn Kasten01066232012-02-27 11:50:44 -080097 break;
98 }
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070099 count -= written;
Glenn Kasten4d693d62014-03-06 07:53:11 -0800100 buffer = (char *) buffer + (written * mFrameSize);
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700101 // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700102 // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
Glenn Kasten820ba702012-05-30 16:34:17 -0700103 uint32_t ns;
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700104 if (written > 0) {
Glenn Kasten820ba702012-05-30 16:34:17 -0700105 size_t filled = (mMaxFrames - avail) + written;
106 // FIXME cache these values to avoid re-computation
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700107 if (filled <= mSetpoint / 2) {
Glenn Kasten820ba702012-05-30 16:34:17 -0700108 // pipe is (nearly) empty, fill quickly
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700109 ns = written * ( 500000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700110 } else if (filled <= (mSetpoint * 3) / 4) {
111 // pipe is below setpoint, fill at slightly faster rate
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700112 ns = written * ( 750000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700113 } else if (filled <= (mSetpoint * 5) / 4) {
114 // pipe is at setpoint, fill at nominal rate
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700115 ns = written * (1000000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700116 } 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));
Glenn Kasten820ba702012-05-30 16:34:17 -0700122 } else {
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700123 // pipe is severely overflowing
124 ns = written * (1750000000 / Format_sampleRate(mFormat));
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700125 }
126 } else {
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700127 ns = count * (1350000000 / Format_sampleRate(mFormat));
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700128 }
129 if (ns > 999999999) {
130 ns = 999999999;
131 }
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700132 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;
Glenn Kasten80b32732012-09-24 11:29:00 -0700138 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);
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700141 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) {
synergydev3b546ca2013-10-25 12:36:28 -0700154 const struct timespec req = {0, static_cast<long>(ns)};
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700155 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;
Glenn Kasten01066232012-02-27 11:50:44 -0800166 }
167 mFramesWritten += totalFramesWritten;
168 return totalFramesWritten;
169}
170
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700171void MonoPipe::setAvgFrames(size_t setpoint)
172{
173 mSetpoint = setpoint;
174}
175
Glenn Kasten003d9f72012-09-28 12:22:52 -0700176void MonoPipe::shutdown(bool newState)
177{
178 mIsShutdown = newState;
179}
180
181bool MonoPipe::isShutdown()
182{
183 return mIsShutdown;
184}
185
Andy Hung818e7a32016-02-16 18:08:07 -0800186status_t MonoPipe::getTimestamp(ExtendedTimestamp &timestamp)
Glenn Kasten767094d2013-08-23 13:51:43 -0700187{
Andy Hung818e7a32016-02-16 18:08:07 -0800188 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];
Glenn Kasten4d0815d2013-08-29 14:40:55 -0700194 return OK;
195 }
Glenn Kasten767094d2013-08-23 13:51:43 -0700196 return INVALID_OPERATION;
197}
198
Glenn Kasten01066232012-02-27 11:50:44 -0800199} // namespace android