Merge "RTSP seeking is now asynchronous, MediaPlayer is not notified that the seek is complete until it actually is. Ignore seek requests on live streams." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
beffefa24f
@@ -876,12 +876,19 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
|
||||||
|
static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AwesomePlayer::onRTSPSeekDone() {
|
||||||
|
notifyListener_l(MEDIA_SEEK_COMPLETE);
|
||||||
|
mSeekNotificationSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
|
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
|
||||||
if (mRTSPController != NULL) {
|
if (mRTSPController != NULL) {
|
||||||
mRTSPController->seek(timeUs);
|
mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
|
||||||
|
|
||||||
notifyListener_l(MEDIA_SEEK_COMPLETE);
|
|
||||||
mSeekNotificationSent = true;
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct ARTSPController : public MediaExtractor {
|
|||||||
status_t connect(const char *url);
|
status_t connect(const char *url);
|
||||||
void disconnect();
|
void disconnect();
|
||||||
|
|
||||||
void seek(int64_t timeUs);
|
void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
|
||||||
|
|
||||||
virtual size_t countTracks();
|
virtual size_t countTracks();
|
||||||
virtual sp<MediaSource> getTrack(size_t index);
|
virtual sp<MediaSource> getTrack(size_t index);
|
||||||
@@ -61,6 +61,7 @@ private:
|
|||||||
enum {
|
enum {
|
||||||
kWhatConnectDone = 'cdon',
|
kWhatConnectDone = 'cdon',
|
||||||
kWhatDisconnectDone = 'ddon',
|
kWhatDisconnectDone = 'ddon',
|
||||||
|
kWhatSeekDone = 'sdon',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@@ -79,6 +80,10 @@ private:
|
|||||||
sp<MyHandler> mHandler;
|
sp<MyHandler> mHandler;
|
||||||
sp<AHandlerReflector<ARTSPController> > mReflector;
|
sp<AHandlerReflector<ARTSPController> > mReflector;
|
||||||
|
|
||||||
|
void (*mSeekDoneCb)(void *);
|
||||||
|
void *mSeekDoneCookie;
|
||||||
|
int64_t mLastSeekCompletedTimeUs;
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
|
DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,9 @@ private:
|
|||||||
|
|
||||||
static bool ContinuePreparation(void *cookie);
|
static bool ContinuePreparation(void *cookie);
|
||||||
|
|
||||||
|
static void OnRTSPSeekDoneWrapper(void *cookie);
|
||||||
|
void onRTSPSeekDone();
|
||||||
|
|
||||||
AwesomePlayer(const AwesomePlayer &);
|
AwesomePlayer(const AwesomePlayer &);
|
||||||
AwesomePlayer &operator=(const AwesomePlayer &);
|
AwesomePlayer &operator=(const AwesomePlayer &);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ namespace android {
|
|||||||
|
|
||||||
ARTSPController::ARTSPController(const sp<ALooper> &looper)
|
ARTSPController::ARTSPController(const sp<ALooper> &looper)
|
||||||
: mState(DISCONNECTED),
|
: mState(DISCONNECTED),
|
||||||
mLooper(looper) {
|
mLooper(looper),
|
||||||
|
mSeekDoneCb(NULL),
|
||||||
|
mSeekDoneCookie(NULL),
|
||||||
|
mLastSeekCompletedTimeUs(-1) {
|
||||||
mReflector = new AHandlerReflector<ARTSPController>(this);
|
mReflector = new AHandlerReflector<ARTSPController>(this);
|
||||||
looper->registerHandler(mReflector);
|
looper->registerHandler(mReflector);
|
||||||
}
|
}
|
||||||
@@ -80,14 +83,31 @@ void ARTSPController::disconnect() {
|
|||||||
mHandler.clear();
|
mHandler.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARTSPController::seek(int64_t timeUs) {
|
void ARTSPController::seekAsync(
|
||||||
|
int64_t timeUs,
|
||||||
|
void (*seekDoneCb)(void *), void *cookie) {
|
||||||
Mutex::Autolock autoLock(mLock);
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
|
||||||
if (mState != CONNECTED) {
|
CHECK(seekDoneCb != NULL);
|
||||||
|
CHECK(mSeekDoneCb == NULL);
|
||||||
|
|
||||||
|
// Ignore seek requests that are too soon after the previous one has
|
||||||
|
// completed, we don't want to swamp the server.
|
||||||
|
|
||||||
|
bool tooEarly =
|
||||||
|
mLastSeekCompletedTimeUs >= 0
|
||||||
|
&& ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
|
||||||
|
|
||||||
|
if (mState != CONNECTED || tooEarly) {
|
||||||
|
(*seekDoneCb)(cookie);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mHandler->seek(timeUs);
|
mSeekDoneCb = seekDoneCb;
|
||||||
|
mSeekDoneCookie = cookie;
|
||||||
|
|
||||||
|
sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
|
||||||
|
mHandler->seek(timeUs, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ARTSPController::countTracks() {
|
size_t ARTSPController::countTracks() {
|
||||||
@@ -132,6 +152,19 @@ void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case kWhatSeekDone:
|
||||||
|
{
|
||||||
|
LOGI("seek done");
|
||||||
|
|
||||||
|
mLastSeekCompletedTimeUs = ALooper::GetNowUs();
|
||||||
|
|
||||||
|
void (*seekDoneCb)(void *) = mSeekDoneCb;
|
||||||
|
mSeekDoneCb = NULL;
|
||||||
|
|
||||||
|
(*seekDoneCb)(mSeekDoneCookie);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TRESPASS();
|
TRESPASS();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ struct MyHandler : public AHandler {
|
|||||||
mCheckPending(false),
|
mCheckPending(false),
|
||||||
mCheckGeneration(0),
|
mCheckGeneration(0),
|
||||||
mTryTCPInterleaving(false),
|
mTryTCPInterleaving(false),
|
||||||
mReceivedFirstRTCPPacket(false) {
|
mReceivedFirstRTCPPacket(false),
|
||||||
|
mSeekable(false) {
|
||||||
mNetLooper->setName("rtsp net");
|
mNetLooper->setName("rtsp net");
|
||||||
mNetLooper->start(false /* runOnCallingThread */,
|
mNetLooper->start(false /* runOnCallingThread */,
|
||||||
false /* canCallJava */,
|
false /* canCallJava */,
|
||||||
@@ -115,9 +116,10 @@ struct MyHandler : public AHandler {
|
|||||||
(new AMessage('abor', id()))->post();
|
(new AMessage('abor', id()))->post();
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(int64_t timeUs) {
|
void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
|
||||||
sp<AMessage> msg = new AMessage('seek', id());
|
sp<AMessage> msg = new AMessage('seek', id());
|
||||||
msg->setInt64("time", timeUs);
|
msg->setInt64("time", timeUs);
|
||||||
|
msg->setMessage("doneMsg", doneMsg);
|
||||||
msg->post();
|
msg->post();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,6 +381,7 @@ struct MyHandler : public AHandler {
|
|||||||
mFirstAccessUnitNTP = 0;
|
mFirstAccessUnitNTP = 0;
|
||||||
mNumAccessUnitsReceived = 0;
|
mNumAccessUnitsReceived = 0;
|
||||||
mReceivedFirstRTCPPacket = false;
|
mReceivedFirstRTCPPacket = false;
|
||||||
|
mSeekable = false;
|
||||||
|
|
||||||
sp<AMessage> reply = new AMessage('tear', id());
|
sp<AMessage> reply = new AMessage('tear', id());
|
||||||
|
|
||||||
@@ -551,7 +554,17 @@ struct MyHandler : public AHandler {
|
|||||||
|
|
||||||
case 'seek':
|
case 'seek':
|
||||||
{
|
{
|
||||||
|
sp<AMessage> doneMsg;
|
||||||
|
CHECK(msg->findMessage("doneMsg", &doneMsg));
|
||||||
|
|
||||||
if (mSeekPending) {
|
if (mSeekPending) {
|
||||||
|
doneMsg->post();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mSeekable) {
|
||||||
|
LOGW("This is a live stream, ignoring seek request.");
|
||||||
|
doneMsg->post();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,6 +590,7 @@ struct MyHandler : public AHandler {
|
|||||||
|
|
||||||
sp<AMessage> reply = new AMessage('see1', id());
|
sp<AMessage> reply = new AMessage('see1', id());
|
||||||
reply->setInt64("time", timeUs);
|
reply->setInt64("time", timeUs);
|
||||||
|
reply->setMessage("doneMsg", doneMsg);
|
||||||
mConn->sendRequest(request.c_str(), reply);
|
mConn->sendRequest(request.c_str(), reply);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -605,7 +619,11 @@ struct MyHandler : public AHandler {
|
|||||||
|
|
||||||
request.append("\r\n");
|
request.append("\r\n");
|
||||||
|
|
||||||
|
sp<AMessage> doneMsg;
|
||||||
|
CHECK(msg->findMessage("doneMsg", &doneMsg));
|
||||||
|
|
||||||
sp<AMessage> reply = new AMessage('see2', id());
|
sp<AMessage> reply = new AMessage('see2', id());
|
||||||
|
reply->setMessage("doneMsg", doneMsg);
|
||||||
mConn->sendRequest(request.c_str(), reply);
|
mConn->sendRequest(request.c_str(), reply);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -644,6 +662,11 @@ struct MyHandler : public AHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mSeekPending = false;
|
mSeekPending = false;
|
||||||
|
|
||||||
|
sp<AMessage> doneMsg;
|
||||||
|
CHECK(msg->findMessage("doneMsg", &doneMsg));
|
||||||
|
|
||||||
|
doneMsg->post();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,6 +737,8 @@ struct MyHandler : public AHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void parsePlayResponse(const sp<ARTSPResponse> &response) {
|
void parsePlayResponse(const sp<ARTSPResponse> &response) {
|
||||||
|
mSeekable = false;
|
||||||
|
|
||||||
ssize_t i = response->mHeaders.indexOfKey("range");
|
ssize_t i = response->mHeaders.indexOfKey("range");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
// Server doesn't even tell use what range it is going to
|
// Server doesn't even tell use what range it is going to
|
||||||
@@ -777,6 +802,8 @@ struct MyHandler : public AHandler {
|
|||||||
|
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSeekable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<APacketSource> getPacketSource(size_t index) {
|
sp<APacketSource> getPacketSource(size_t index) {
|
||||||
@@ -808,6 +835,7 @@ private:
|
|||||||
int32_t mCheckGeneration;
|
int32_t mCheckGeneration;
|
||||||
bool mTryTCPInterleaving;
|
bool mTryTCPInterleaving;
|
||||||
bool mReceivedFirstRTCPPacket;
|
bool mReceivedFirstRTCPPacket;
|
||||||
|
bool mSeekable;
|
||||||
|
|
||||||
struct TrackInfo {
|
struct TrackInfo {
|
||||||
AString mURL;
|
AString mURL;
|
||||||
|
|||||||
Reference in New Issue
Block a user