blob: 3c5df1ad857d0b3d4a89219a075e020c3570883f [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
Glenn Kasten01066232012-02-27 11:50:44 -080022#include <cutils/compiler.h>
23#include <utils/Log.h>
Glenn Kasten28ed2f92012-06-07 10:17:54 -070024#include <utils/Trace.h>
Glenn Kasten2dd4bdd2012-08-29 11:10:32 -070025#include <media/AudioBufferProvider.h>
26#include <media/nbaio/MonoPipe.h>
Glenn Kasten53dbe772015-01-06 10:46:38 -080027#include <audio_utils/roundup.h>
Glenn Kasten01066232012-02-27 11:50:44 -080028
John Grossman2c3b2da2012-08-02 17:08:54 -070029
Glenn Kasten01066232012-02-27 11:50:44 -080030namespace android {
31
Glenn Kasten72e54af2014-01-31 09:37:35 -080032MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
Glenn Kasten01066232012-02-27 11:50:44 -080033 NBAIO_Sink(format),
Glenn Kastened99c2b2016-12-12 08:31:24 -080034 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten820ba702012-05-30 16:34:17 -070035 mMaxFrames(roundup(reqFrames)),
Glenn Kasten01066232012-02-27 11:50:44 -080036 mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
Glenn Kastened99c2b2016-12-12 08:31:24 -080037 mFifo(mMaxFrames, Format_frameSize(format), mBuffer, true /*throttlesWriter*/),
38 mFifoWriter(mFifo),
Glenn Kasten28ed2f92012-06-07 10:17:54 -070039 mWriteTsValid(false),
40 // mWriteTs
41 mSetpoint((reqFrames * 11) / 16),
Glenn Kasten003d9f72012-09-28 12:22:52 -070042 mWriteCanBlock(writeCanBlock),
Glenn Kastena07a1c22013-08-23 10:54:35 -070043 mIsShutdown(false),
44 // mTimestampShared
45 mTimestampMutator(&mTimestampShared),
46 mTimestampObserver(&mTimestampShared)
Glenn Kasten01066232012-02-27 11:50:44 -080047{
Glenn Kasten01066232012-02-27 11:50:44 -080048}
49
50MonoPipe::~MonoPipe()
51{
52 free(mBuffer);
53}
54
Glenn Kastened99c2b2016-12-12 08:31:24 -080055ssize_t MonoPipe::availableToWrite()
Glenn Kasten01066232012-02-27 11:50:44 -080056{
57 if (CC_UNLIKELY(!mNegotiated)) {
58 return NEGOTIATE;
59 }
Glenn Kastened99c2b2016-12-12 08:31:24 -080060 // uses mMaxFrames not reqFrames, so allows "over-filling" the pipe beyond requested limit
61 ssize_t ret = mFifoWriter.available();
62 ALOG_ASSERT(ret <= mMaxFrames);
Glenn Kasten01066232012-02-27 11:50:44 -080063 return ret;
64}
65
66ssize_t MonoPipe::write(const void *buffer, size_t count)
67{
Glenn Kasten01066232012-02-27 11:50:44 -080068 if (CC_UNLIKELY(!mNegotiated)) {
69 return NEGOTIATE;
70 }
71 size_t totalFramesWritten = 0;
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070072 while (count > 0) {
Glenn Kastened99c2b2016-12-12 08:31:24 -080073 ssize_t actual = mFifoWriter.write(buffer, count);
74 ALOG_ASSERT(actual <= count);
75 if (actual < 0) {
76 if (totalFramesWritten == 0) {
77 return actual;
Glenn Kasten01066232012-02-27 11:50:44 -080078 }
Glenn Kastened99c2b2016-12-12 08:31:24 -080079 break;
Glenn Kasten01066232012-02-27 11:50:44 -080080 }
Glenn Kastened99c2b2016-12-12 08:31:24 -080081 size_t written = (size_t) actual;
82 totalFramesWritten += written;
Glenn Kasten003d9f72012-09-28 12:22:52 -070083 if (!mWriteCanBlock || mIsShutdown) {
Glenn Kasten01066232012-02-27 11:50:44 -080084 break;
85 }
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070086 count -= written;
Glenn Kasten4d693d62014-03-06 07:53:11 -080087 buffer = (char *) buffer + (written * mFrameSize);
Glenn Kastened99c2b2016-12-12 08:31:24 -080088 // TODO Replace this whole section by audio_util_fifo's setpoint feature.
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070089 // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
Glenn Kasten28ed2f92012-06-07 10:17:54 -070090 // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
Glenn Kasten820ba702012-05-30 16:34:17 -070091 uint32_t ns;
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070092 if (written > 0) {
Glenn Kastened99c2b2016-12-12 08:31:24 -080093 ssize_t avail = mFifoWriter.available();
94 ALOG_ASSERT(avail <= mMaxFrames);
95 if (avail < 0) {
96 // don't return avail as status, because totalFramesWritten > 0
97 break;
98 }
99 size_t filled = mMaxFrames - (size_t) avail;
Glenn Kasten820ba702012-05-30 16:34:17 -0700100 // FIXME cache these values to avoid re-computation
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700101 if (filled <= mSetpoint / 2) {
Glenn Kasten820ba702012-05-30 16:34:17 -0700102 // pipe is (nearly) empty, fill quickly
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700103 ns = written * ( 500000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700104 } else if (filled <= (mSetpoint * 3) / 4) {
105 // pipe is below setpoint, fill at slightly faster rate
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700106 ns = written * ( 750000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700107 } else if (filled <= (mSetpoint * 5) / 4) {
108 // pipe is at setpoint, fill at nominal rate
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700109 ns = written * (1000000000 / Format_sampleRate(mFormat));
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700110 } else if (filled <= (mSetpoint * 3) / 2) {
111 // pipe is above setpoint, fill at slightly slower rate
112 ns = written * (1150000000 / Format_sampleRate(mFormat));
113 } else if (filled <= (mSetpoint * 7) / 4) {
114 // pipe is overflowing, fill slowly
115 ns = written * (1350000000 / Format_sampleRate(mFormat));
Glenn Kasten820ba702012-05-30 16:34:17 -0700116 } else {
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700117 // pipe is severely overflowing
118 ns = written * (1750000000 / Format_sampleRate(mFormat));
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700119 }
120 } else {
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700121 ns = count * (1350000000 / Format_sampleRate(mFormat));
Glenn Kasten6d8aabe2012-05-18 10:47:28 -0700122 }
123 if (ns > 999999999) {
124 ns = 999999999;
125 }
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700126 struct timespec nowTs;
127 bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
128 // deduct the elapsed time since previous write() completed
129 if (nowTsValid && mWriteTsValid) {
130 time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
131 long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
Glenn Kasten80b32732012-09-24 11:29:00 -0700132 ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
133 "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
134 mWriteTs.tv_sec, mWriteTs.tv_nsec, nowTs.tv_sec, nowTs.tv_nsec);
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700135 if (nsec < 0) {
136 --sec;
137 nsec += 1000000000;
138 }
139 if (sec == 0) {
140 if ((long) ns > nsec) {
141 ns -= nsec;
142 } else {
143 ns = 0;
144 }
145 }
146 }
147 if (ns > 0) {
synergydev3b546ca2013-10-25 12:36:28 -0700148 const struct timespec req = {0, static_cast<long>(ns)};
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700149 nanosleep(&req, NULL);
150 }
151 // record the time that this write() completed
152 if (nowTsValid) {
153 mWriteTs = nowTs;
154 if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
155 mWriteTs.tv_nsec -= 1000000000;
156 ++mWriteTs.tv_sec;
157 }
158 }
159 mWriteTsValid = nowTsValid;
Glenn Kasten01066232012-02-27 11:50:44 -0800160 }
161 mFramesWritten += totalFramesWritten;
162 return totalFramesWritten;
163}
164
Glenn Kasten28ed2f92012-06-07 10:17:54 -0700165void MonoPipe::setAvgFrames(size_t setpoint)
166{
167 mSetpoint = setpoint;
168}
169
Glenn Kasten003d9f72012-09-28 12:22:52 -0700170void MonoPipe::shutdown(bool newState)
171{
172 mIsShutdown = newState;
173}
174
175bool MonoPipe::isShutdown()
176{
177 return mIsShutdown;
178}
179
Andy Hung818e7a32016-02-16 18:08:07 -0800180status_t MonoPipe::getTimestamp(ExtendedTimestamp &timestamp)
Glenn Kasten767094d2013-08-23 13:51:43 -0700181{
Andy Hung818e7a32016-02-16 18:08:07 -0800182 ExtendedTimestamp ets;
183 if (mTimestampObserver.poll(ets)) {
184 timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
185 ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
186 timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
187 ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
Glenn Kasten4d0815d2013-08-29 14:40:55 -0700188 return OK;
189 }
Glenn Kasten767094d2013-08-23 13:51:43 -0700190 return INVALID_OPERATION;
191}
192
Glenn Kasten01066232012-02-27 11:50:44 -0800193} // namespace android