• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &timestamp)
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