HTTPLiveSource.cpp revision 055404ea1309d4cbc5d313332b026f86bd6f0da1
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//#define LOG_NDEBUG 0 18#define LOG_TAG "HTTPLiveSource" 19#include <utils/Log.h> 20 21#include "HTTPLiveSource.h" 22 23#include "AnotherPacketSource.h" 24#include "LiveDataSource.h" 25 26#include <media/IMediaHTTPService.h> 27#include <media/stagefright/foundation/ABuffer.h> 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/MediaErrors.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/MediaDefs.h> 33 34namespace android { 35 36NuPlayer::HTTPLiveSource::HTTPLiveSource( 37 const sp<AMessage> ¬ify, 38 const sp<IMediaHTTPService> &httpService, 39 const char *url, 40 const KeyedVector<String8, String8> *headers) 41 : Source(notify), 42 mHTTPService(httpService), 43 mURL(url), 44 mFlags(0), 45 mFinalResult(OK), 46 mOffset(0), 47 mFetchSubtitleDataGeneration(0), 48 mFetchMetaDataGeneration(0), 49 mHasMetadata(false), 50 mMetadataSelected(false) { 51 if (headers) { 52 mExtraHeaders = *headers; 53 54 ssize_t index = 55 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 56 57 if (index >= 0) { 58 mFlags |= kFlagIncognito; 59 60 mExtraHeaders.removeItemsAt(index); 61 } 62 } 63} 64 65NuPlayer::HTTPLiveSource::~HTTPLiveSource() { 66 if (mLiveSession != NULL) { 67 mLiveSession->disconnect(); 68 69 mLiveLooper->unregisterHandler(mLiveSession->id()); 70 mLiveLooper->unregisterHandler(id()); 71 mLiveLooper->stop(); 72 73 mLiveSession.clear(); 74 mLiveLooper.clear(); 75 } 76} 77 78void NuPlayer::HTTPLiveSource::prepareAsync() { 79 if (mLiveLooper == NULL) { 80 mLiveLooper = new ALooper; 81 mLiveLooper->setName("http live"); 82 mLiveLooper->start(); 83 84 mLiveLooper->registerHandler(this); 85 } 86 87 sp<AMessage> notify = new AMessage(kWhatSessionNotify, this); 88 89 mLiveSession = new LiveSession( 90 notify, 91 (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, 92 mHTTPService); 93 94 mLiveLooper->registerHandler(mLiveSession); 95 96 mLiveSession->connectAsync( 97 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 98} 99 100void NuPlayer::HTTPLiveSource::start() { 101} 102 103sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) { 104 if (mLiveSession == NULL) { 105 return NULL; 106 } 107 108 sp<AMessage> format; 109 status_t err = mLiveSession->getStreamFormat( 110 audio ? LiveSession::STREAMTYPE_AUDIO 111 : LiveSession::STREAMTYPE_VIDEO, 112 &format); 113 114 if (err != OK) { 115 return NULL; 116 } 117 118 return format; 119} 120 121status_t NuPlayer::HTTPLiveSource::feedMoreTSData() { 122 return OK; 123} 124 125status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit( 126 bool audio, sp<ABuffer> *accessUnit) { 127 return mLiveSession->dequeueAccessUnit( 128 audio ? LiveSession::STREAMTYPE_AUDIO 129 : LiveSession::STREAMTYPE_VIDEO, 130 accessUnit); 131} 132 133status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { 134 return mLiveSession->getDuration(durationUs); 135} 136 137size_t NuPlayer::HTTPLiveSource::getTrackCount() const { 138 return mLiveSession->getTrackCount(); 139} 140 141sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { 142 return mLiveSession->getTrackInfo(trackIndex); 143} 144 145ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const { 146 if (mLiveSession == NULL) { 147 return -1; 148 } else if (type == MEDIA_TRACK_TYPE_METADATA) { 149 // MEDIA_TRACK_TYPE_METADATA is always last track 150 // mMetadataSelected can only be true when mHasMetadata is true 151 return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1; 152 } else { 153 return mLiveSession->getSelectedTrack(type); 154 } 155} 156 157status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) { 158 if (mLiveSession == NULL) { 159 return INVALID_OPERATION; 160 } 161 162 status_t err = INVALID_OPERATION; 163 bool postFetchMsg = false, isSub = false; 164 if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) { 165 err = mLiveSession->selectTrack(trackIndex, select); 166 postFetchMsg = select; 167 isSub = true; 168 } else { 169 // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1) 170 if (mMetadataSelected && !select) { 171 err = OK; 172 } else if (!mMetadataSelected && select) { 173 postFetchMsg = true; 174 err = OK; 175 } else { 176 err = BAD_VALUE; // behave as LiveSession::selectTrack 177 } 178 179 mMetadataSelected = select; 180 } 181 182 if (err == OK) { 183 int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration; 184 generation++; 185 if (postFetchMsg) { 186 int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData; 187 sp<AMessage> msg = new AMessage(what, this); 188 msg->setInt32("generation", generation); 189 msg->post(); 190 } 191 } 192 193 // LiveSession::selectTrack returns BAD_VALUE when selecting the currently 194 // selected track, or unselecting a non-selected track. In this case it's an 195 // no-op so we return OK. 196 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; 197} 198 199status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { 200 return mLiveSession->seekTo(seekTimeUs); 201} 202 203void NuPlayer::HTTPLiveSource::pollForRawData( 204 const sp<AMessage> &msg, int32_t currentGeneration, 205 LiveSession::StreamType fetchType, int32_t pushWhat) { 206 207 int32_t generation; 208 CHECK(msg->findInt32("generation", &generation)); 209 210 if (generation != currentGeneration) { 211 return; 212 } 213 214 sp<ABuffer> buffer; 215 while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) { 216 217 sp<AMessage> notify = dupNotify(); 218 notify->setInt32("what", pushWhat); 219 notify->setBuffer("buffer", buffer); 220 221 int64_t timeUs, baseUs, delayUs; 222 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 223 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 224 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 225 226 if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) { 227 notify->post(); 228 msg->post(delayUs > 0ll ? delayUs : 0ll); 229 return; 230 } else if (fetchType == LiveSession::STREAMTYPE_METADATA) { 231 if (delayUs < -1000000ll) { // 1 second 232 continue; 233 } 234 notify->post(); 235 // push all currently available metadata buffers in each invocation of pollForRawData 236 // continue; 237 } else { 238 TRESPASS(); 239 } 240 } 241 242 // try again in 1 second 243 msg->post(1000000ll); 244} 245 246void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 247 switch (msg->what()) { 248 case kWhatSessionNotify: 249 { 250 onSessionNotify(msg); 251 break; 252 } 253 254 case kWhatFetchSubtitleData: 255 { 256 pollForRawData( 257 msg, mFetchSubtitleDataGeneration, 258 /* fetch */ LiveSession::STREAMTYPE_SUBTITLES, 259 /* push */ kWhatSubtitleData); 260 261 break; 262 } 263 264 case kWhatFetchMetaData: 265 { 266 if (!mMetadataSelected) { 267 break; 268 } 269 270 pollForRawData( 271 msg, mFetchMetaDataGeneration, 272 /* fetch */ LiveSession::STREAMTYPE_METADATA, 273 /* push */ kWhatTimedMetaData); 274 275 break; 276 } 277 278 default: 279 Source::onMessageReceived(msg); 280 break; 281 } 282} 283 284void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 285 int32_t what; 286 CHECK(msg->findInt32("what", &what)); 287 288 switch (what) { 289 case LiveSession::kWhatPrepared: 290 { 291 // notify the current size here if we have it, otherwise report an initial size of (0,0) 292 sp<AMessage> format = getFormat(false /* audio */); 293 int32_t width; 294 int32_t height; 295 if (format != NULL && 296 format->findInt32("width", &width) && format->findInt32("height", &height)) { 297 notifyVideoSizeChanged(format); 298 } else { 299 notifyVideoSizeChanged(); 300 } 301 302 uint32_t flags = FLAG_CAN_PAUSE; 303 if (mLiveSession->isSeekable()) { 304 flags |= FLAG_CAN_SEEK; 305 flags |= FLAG_CAN_SEEK_BACKWARD; 306 flags |= FLAG_CAN_SEEK_FORWARD; 307 } 308 309 if (mLiveSession->hasDynamicDuration()) { 310 flags |= FLAG_DYNAMIC_DURATION; 311 } 312 313 notifyFlagsChanged(flags); 314 315 notifyPrepared(); 316 break; 317 } 318 319 case LiveSession::kWhatPreparationFailed: 320 { 321 status_t err; 322 CHECK(msg->findInt32("err", &err)); 323 324 notifyPrepared(err); 325 break; 326 } 327 328 case LiveSession::kWhatStreamsChanged: 329 { 330 uint32_t changedMask; 331 CHECK(msg->findInt32( 332 "changedMask", (int32_t *)&changedMask)); 333 334 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 335 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 336 337 sp<AMessage> reply; 338 CHECK(msg->findMessage("reply", &reply)); 339 340 sp<AMessage> notify = dupNotify(); 341 notify->setInt32("what", kWhatQueueDecoderShutdown); 342 notify->setInt32("audio", audio); 343 notify->setInt32("video", video); 344 notify->setMessage("reply", reply); 345 notify->post(); 346 break; 347 } 348 349 case LiveSession::kWhatBufferingStart: 350 { 351 sp<AMessage> notify = dupNotify(); 352 notify->setInt32("what", kWhatPauseOnBufferingStart); 353 notify->post(); 354 break; 355 } 356 357 case LiveSession::kWhatBufferingEnd: 358 { 359 sp<AMessage> notify = dupNotify(); 360 notify->setInt32("what", kWhatResumeOnBufferingEnd); 361 notify->post(); 362 break; 363 } 364 365 366 case LiveSession::kWhatBufferingUpdate: 367 { 368 sp<AMessage> notify = dupNotify(); 369 int32_t percentage; 370 CHECK(msg->findInt32("percentage", &percentage)); 371 notify->setInt32("what", kWhatBufferingUpdate); 372 notify->setInt32("percentage", percentage); 373 notify->post(); 374 break; 375 } 376 377 case LiveSession::kWhatMetadataDetected: 378 { 379 if (!mHasMetadata) { 380 mHasMetadata = true; 381 382 sp<AMessage> notify = dupNotify(); 383 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE 384 notify->setInt32("what", kWhatTimedMetaData); 385 notify->post(); 386 } 387 break; 388 } 389 390 case LiveSession::kWhatError: 391 { 392 break; 393 } 394 395 default: 396 TRESPASS(); 397 } 398} 399 400} // namespace android 401 402