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
30namespace android {
31
32MonoPipe::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
50MonoPipe::~MonoPipe()
51{
52    free(mBuffer);
53}
54
55ssize_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
66ssize_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
165void MonoPipe::setAvgFrames(size_t setpoint)
166{
167    mSetpoint = setpoint;
168}
169
170void MonoPipe::shutdown(bool newState)
171{
172    mIsShutdown = newState;
173}
174
175bool MonoPipe::isShutdown()
176{
177    return mIsShutdown;
178}
179
180status_t MonoPipe::getTimestamp(ExtendedTimestamp &timestamp)
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