[go: nahoru, domu]

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
31namespace android {
32
33MonoPipe::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
51MonoPipe::~MonoPipe()
52{
53    free(mBuffer);
54}
55
56ssize_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
67ssize_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
171void MonoPipe::setAvgFrames(size_t setpoint)
172{
173    mSetpoint = setpoint;
174}
175
176void MonoPipe::shutdown(bool newState)
177{
178    mIsShutdown = newState;
179}
180
181bool MonoPipe::isShutdown()
182{
183    return mIsShutdown;
184}
185
186status_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