1//#define LOG_NDEBUG 0
2#define LOG_TAG "RepeaterSource"
3#include <utils/Log.h>
4
5#include "RepeaterSource.h"
6
7#include <media/stagefright/foundation/ADebug.h>
8#include <media/stagefright/foundation/ALooper.h>
9#include <media/stagefright/foundation/AMessage.h>
10#include <media/stagefright/MediaBuffer.h>
11#include <media/stagefright/MetaData.h>
12
13namespace android {
14
15RepeaterSource::RepeaterSource(const sp<MediaSource> &source, double rateHz)
16    : mStarted(false),
17      mSource(source),
18      mRateHz(rateHz),
19      mBuffer(NULL),
20      mResult(OK),
21      mLastBufferUpdateUs(-1ll),
22      mStartTimeUs(-1ll),
23      mFrameCount(0) {
24}
25
26RepeaterSource::~RepeaterSource() {
27    CHECK(!mStarted);
28}
29
30status_t RepeaterSource::start(MetaData *params) {
31    CHECK(!mStarted);
32
33    status_t err = mSource->start(params);
34
35    if (err != OK) {
36        return err;
37    }
38
39    mBuffer = NULL;
40    mResult = OK;
41    mStartTimeUs = -1ll;
42    mFrameCount = 0;
43
44    mLooper = new ALooper;
45    mLooper->setName("repeater_looper");
46    mLooper->start();
47
48    mReflector = new AHandlerReflector<RepeaterSource>(this);
49    mLooper->registerHandler(mReflector);
50
51    postRead();
52
53    mStarted = true;
54
55    return OK;
56}
57
58status_t RepeaterSource::stop() {
59    CHECK(mStarted);
60
61    ALOGV("stopping");
62
63    if (mLooper != NULL) {
64        mLooper->stop();
65        mLooper.clear();
66
67        mReflector.clear();
68    }
69
70    if (mBuffer != NULL) {
71        ALOGV("releasing mbuf %p", mBuffer);
72        mBuffer->release();
73        mBuffer = NULL;
74    }
75
76    status_t err = mSource->stop();
77
78    ALOGV("stopped");
79
80    mStarted = false;
81
82    return err;
83}
84
85sp<MetaData> RepeaterSource::getFormat() {
86    return mSource->getFormat();
87}
88
89status_t RepeaterSource::read(
90        MediaBuffer **buffer, const ReadOptions *options) {
91    int64_t seekTimeUs;
92    ReadOptions::SeekMode seekMode;
93    CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
94
95    for (;;) {
96        int64_t bufferTimeUs = -1ll;
97
98        if (mStartTimeUs < 0ll) {
99            Mutex::Autolock autoLock(mLock);
100            while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
101                    && mResult == OK) {
102                mCondition.wait(mLock);
103            }
104
105            ALOGV("now resuming.");
106            mStartTimeUs = ALooper::GetNowUs();
107            bufferTimeUs = mStartTimeUs;
108        } else {
109            bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
110
111            int64_t nowUs = ALooper::GetNowUs();
112            int64_t delayUs = bufferTimeUs - nowUs;
113
114            if (delayUs > 0ll) {
115                usleep(delayUs);
116            }
117        }
118
119        bool stale = false;
120
121        {
122            Mutex::Autolock autoLock(mLock);
123            if (mResult != OK) {
124                CHECK(mBuffer == NULL);
125                return mResult;
126            }
127
128            int64_t nowUs = ALooper::GetNowUs();
129            if (nowUs - mLastBufferUpdateUs > 1000000ll) {
130                mLastBufferUpdateUs = -1ll;
131                stale = true;
132            } else {
133                mBuffer->add_ref();
134                *buffer = mBuffer;
135                (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
136                ++mFrameCount;
137            }
138        }
139
140        if (!stale) {
141            break;
142        }
143
144        mStartTimeUs = -1ll;
145        mFrameCount = 0;
146        ALOGV("now dormant");
147    }
148
149    return OK;
150}
151
152void RepeaterSource::postRead() {
153    (new AMessage(kWhatRead, mReflector->id()))->post();
154}
155
156void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
157    switch (msg->what()) {
158        case kWhatRead:
159        {
160            MediaBuffer *buffer;
161            status_t err = mSource->read(&buffer);
162
163            ALOGV("read mbuf %p", buffer);
164
165            Mutex::Autolock autoLock(mLock);
166            if (mBuffer != NULL) {
167                mBuffer->release();
168                mBuffer = NULL;
169            }
170            mBuffer = buffer;
171            mResult = err;
172            mLastBufferUpdateUs = ALooper::GetNowUs();
173
174            mCondition.broadcast();
175
176            if (err == OK) {
177                postRead();
178            }
179            break;
180        }
181
182        default:
183            TRESPASS();
184    }
185}
186
187void RepeaterSource::wakeUp() {
188    ALOGV("wakeUp");
189    Mutex::Autolock autoLock(mLock);
190    if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
191        mLastBufferUpdateUs = ALooper::GetNowUs();
192        mCondition.broadcast();
193    }
194}
195
196}  // namespace android
197