1/*
2 * Copyright (C) 2010 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 "ARTSPController.h"
18
19#include "MyHandler.h"
20
21#include <media/stagefright/foundation/ADebug.h>
22#include <media/stagefright/MediaErrors.h>
23#include <media/stagefright/MediaSource.h>
24#include <media/stagefright/MetaData.h>
25
26namespace android {
27
28ARTSPController::ARTSPController(const sp<ALooper> &looper)
29    : mState(DISCONNECTED),
30      mLooper(looper),
31      mSeekDoneCb(NULL),
32      mSeekDoneCookie(NULL),
33      mLastSeekCompletedTimeUs(-1) {
34    mReflector = new AHandlerReflector<ARTSPController>(this);
35    looper->registerHandler(mReflector);
36}
37
38ARTSPController::~ARTSPController() {
39    CHECK_EQ((int)mState, (int)DISCONNECTED);
40    mLooper->unregisterHandler(mReflector->id());
41}
42
43status_t ARTSPController::connect(const char *url) {
44    Mutex::Autolock autoLock(mLock);
45
46    if (mState != DISCONNECTED) {
47        return ERROR_ALREADY_CONNECTED;
48    }
49
50    sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
51
52    mHandler = new MyHandler(url, mLooper);
53
54    mState = CONNECTING;
55
56    mHandler->connect(msg);
57
58    while (mState == CONNECTING) {
59        mCondition.wait(mLock);
60    }
61
62    if (mState != CONNECTED) {
63        mHandler.clear();
64    }
65
66    return mConnectionResult;
67}
68
69void ARTSPController::disconnect() {
70    Mutex::Autolock autoLock(mLock);
71
72    if (mState != CONNECTED) {
73        return;
74    }
75
76    sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
77    mHandler->disconnect(msg);
78
79    while (mState == CONNECTED) {
80        mCondition.wait(mLock);
81    }
82
83    mHandler.clear();
84}
85
86void ARTSPController::seekAsync(
87        int64_t timeUs,
88        void (*seekDoneCb)(void *), void *cookie) {
89    Mutex::Autolock autoLock(mLock);
90
91    CHECK(seekDoneCb != NULL);
92    CHECK(mSeekDoneCb == NULL);
93
94    // Ignore seek requests that are too soon after the previous one has
95    // completed, we don't want to swamp the server.
96
97    bool tooEarly =
98        mLastSeekCompletedTimeUs >= 0
99            && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
100
101    if (mState != CONNECTED || tooEarly) {
102        (*seekDoneCb)(cookie);
103        return;
104    }
105
106    mSeekDoneCb = seekDoneCb;
107    mSeekDoneCookie = cookie;
108
109    sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
110    mHandler->seek(timeUs, msg);
111}
112
113size_t ARTSPController::countTracks() {
114    if (mHandler == NULL) {
115        return 0;
116    }
117
118    return mHandler->countTracks();
119}
120
121sp<MediaSource> ARTSPController::getTrack(size_t index) {
122    CHECK(mHandler != NULL);
123
124    return mHandler->getPacketSource(index);
125}
126
127sp<MetaData> ARTSPController::getTrackMetaData(
128        size_t index, uint32_t flags) {
129    CHECK(mHandler != NULL);
130
131    return mHandler->getPacketSource(index)->getFormat();
132}
133
134void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
135    switch (msg->what()) {
136        case kWhatConnectDone:
137        {
138            Mutex::Autolock autoLock(mLock);
139
140            CHECK(msg->findInt32("result", &mConnectionResult));
141            mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
142
143            mCondition.signal();
144            break;
145        }
146
147        case kWhatDisconnectDone:
148        {
149            Mutex::Autolock autoLock(mLock);
150            mState = DISCONNECTED;
151            mCondition.signal();
152            break;
153        }
154
155        case kWhatSeekDone:
156        {
157            LOGI("seek done");
158
159            mLastSeekCompletedTimeUs = ALooper::GetNowUs();
160
161            void (*seekDoneCb)(void *) = mSeekDoneCb;
162            mSeekDoneCb = NULL;
163
164            (*seekDoneCb)(mSeekDoneCookie);
165            break;
166        }
167
168        default:
169            TRESPASS();
170            break;
171    }
172}
173
174int64_t ARTSPController::getNormalPlayTimeUs() {
175    CHECK(mHandler != NULL);
176    return mHandler->getNormalPlayTimeUs();
177}
178
179int64_t ARTSPController::getQueueDurationUs(bool *eos) {
180    *eos = true;
181
182    int64_t minQueuedDurationUs = 0;
183    for (size_t i = 0; i < mHandler->countTracks(); ++i) {
184        sp<APacketSource> source = mHandler->getPacketSource(i);
185
186        bool newEOS;
187        int64_t queuedDurationUs = source->getQueueDurationUs(&newEOS);
188
189        if (!newEOS) {
190            *eos = false;
191        }
192
193        if (i == 0 || queuedDurationUs < minQueuedDurationUs) {
194            minQueuedDurationUs = queuedDurationUs;
195        }
196    }
197
198    return minQueuedDurationUs;
199}
200
201}  // namespace android
202