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/compiler.h>
23 #include <utils/Log.h>
24 #include <utils/Trace.h>
25 #include <media/AudioBufferProvider.h>
26 #include <media/nbaio/MonoPipe.h>
27 #include <audio_utils/roundup.h>
28
29
30 namespace android {
31
MonoPipe(size_t reqFrames,const NBAIO_Format & format,bool writeCanBlock)32 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
33 NBAIO_Sink(format),
34 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
35 mMaxFrames(roundup(reqFrames)),
36 mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
37 mFifo(mMaxFrames, Format_frameSize(format), mBuffer, true /*throttlesWriter*/),
38 mFifoWriter(mFifo),
39 mWriteTsValid(false),
40 // mWriteTs
41 mSetpoint((reqFrames * 11) / 16),
42 mWriteCanBlock(writeCanBlock),
43 mIsShutdown(false),
44 // mTimestampShared
45 mTimestampMutator(&mTimestampShared),
46 mTimestampObserver(&mTimestampShared)
47 {
48 }
49
~MonoPipe()50 MonoPipe::~MonoPipe()
51 {
52 free(mBuffer);
53 }
54
availableToWrite()55 ssize_t MonoPipe::availableToWrite()
56 {
57 if (CC_UNLIKELY(!mNegotiated)) {
58 return NEGOTIATE;
59 }
60 // uses mMaxFrames not reqFrames, so allows "over-filling" the pipe beyond requested limit
61 ssize_t ret = mFifoWriter.available();
62 ALOG_ASSERT(ret <= mMaxFrames);
63 return ret;
64 }
65
write(const void * buffer,size_t count)66 ssize_t MonoPipe::write(const void *buffer, size_t count)
67 {
68 if (CC_UNLIKELY(!mNegotiated)) {
69 return NEGOTIATE;
70 }
71 size_t totalFramesWritten = 0;
72 while (count > 0) {
73 ssize_t actual = mFifoWriter.write(buffer, count);
74 ALOG_ASSERT(actual <= count);
75 if (actual < 0) {
76 if (totalFramesWritten == 0) {
77 return actual;
78 }
79 break;
80 }
81 size_t written = (size_t) actual;
82 totalFramesWritten += written;
83 if (!mWriteCanBlock || mIsShutdown) {
84 break;
85 }
86 count -= written;
87 buffer = (char *) buffer + (written * mFrameSize);
88 // TODO Replace this whole section by audio_util_fifo's setpoint feature.
89 // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
90 // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
91 uint32_t ns;
92 if (written > 0) {
93 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;
100 // FIXME cache these values to avoid re-computation
101 if (filled <= mSetpoint / 2) {
102 // pipe is (nearly) empty, fill quickly
103 ns = written * ( 500000000 / Format_sampleRate(mFormat));
104 } else if (filled <= (mSetpoint * 3) / 4) {
105 // pipe is below setpoint, fill at slightly faster rate
106 ns = written * ( 750000000 / Format_sampleRate(mFormat));
107 } else if (filled <= (mSetpoint * 5) / 4) {
108 // pipe is at setpoint, fill at nominal rate
109 ns = written * (1000000000 / Format_sampleRate(mFormat));
110 } 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));
116 } else {
117 // pipe is severely overflowing
118 ns = written * (1750000000 / Format_sampleRate(mFormat));
119 }
120 } else {
121 ns = count * (1350000000 / Format_sampleRate(mFormat));
122 }
123 if (ns > 999999999) {
124 ns = 999999999;
125 }
126 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;
132 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);
135 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) {
148 const struct timespec req = {0, static_cast<long>(ns)};
149 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;
160 }
161 mFramesWritten += totalFramesWritten;
162 return totalFramesWritten;
163 }
164
setAvgFrames(size_t setpoint)165 void MonoPipe::setAvgFrames(size_t setpoint)
166 {
167 mSetpoint = setpoint;
168 }
169
shutdown(bool newState)170 void MonoPipe::shutdown(bool newState)
171 {
172 mIsShutdown = newState;
173 }
174
isShutdown()175 bool MonoPipe::isShutdown()
176 {
177 return mIsShutdown;
178 }
179
getTimestamp(ExtendedTimestamp & timestamp)180 status_t MonoPipe::getTimestamp(ExtendedTimestamp ×tamp)
181 {
182 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];
188 return OK;
189 }
190 return INVALID_OPERATION;
191 }
192
193 } // namespace android
194