HTTPLiveSource.cpp revision 0852843d304006e3ab333081fddda13b07193de8
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 (trackIndex != mLiveSession->getTrackCount() - 1) { 165 err = mLiveSession->selectTrack(trackIndex, select); 166 postFetchMsg = select; 167 isSub = true; 168 } else { 169 // metadata track 170 if (mHasMetadata) { 171 if (mMetadataSelected && !select) { 172 err = OK; 173 } else if (!mMetadataSelected && select) { 174 postFetchMsg = true; 175 err = OK; 176 } else { 177 err = BAD_VALUE; // behave as LiveSession::selectTrack 178 } 179 180 mMetadataSelected = select; 181 } 182 } 183 184 if (err == OK) { 185 int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration; 186 generation++; 187 if (postFetchMsg) { 188 int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData; 189 sp<AMessage> msg = new AMessage(what, this); 190 msg->setInt32("generation", generation); 191 msg->post(); 192 } 193 } 194 195 // LiveSession::selectTrack returns BAD_VALUE when selecting the currently 196 // selected track, or unselecting a non-selected track. In this case it's an 197 // no-op so we return OK. 198 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; 199} 200 201status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { 202 return mLiveSession->seekTo(seekTimeUs); 203} 204 205void NuPlayer::HTTPLiveSource::pollForRawData( 206 const sp<AMessage> &msg, int32_t currentGeneration, 207 LiveSession::StreamType fetchType, int32_t pushWhat) { 208 209 int32_t generation; 210 CHECK(msg->findInt32("generation", &generation)); 211 212 if (generation != currentGeneration) { 213 return; 214 } 215 216 sp<ABuffer> buffer; 217 while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) { 218 219 sp<AMessage> notify = dupNotify(); 220 notify->setInt32("what", pushWhat); 221 notify->setBuffer("buffer", buffer); 222 223 int64_t timeUs, baseUs, delayUs; 224 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 225 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 226 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 227 228 if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) { 229 notify->post(); 230 msg->post(delayUs > 0ll ? delayUs : 0ll); 231 return; 232 } else if (fetchType == LiveSession::STREAMTYPE_METADATA) { 233 if (delayUs < -1000000ll) { // 1 second 234 continue; 235 } 236 notify->post(); 237 // push all currently available metadata buffers in each invocation of pollForRawData 238 // continue; 239 } else { 240 TRESPASS(); 241 } 242 } 243 244 // try again in 1 second 245 msg->post(1000000ll); 246} 247 248void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 249 switch (msg->what()) { 250 case kWhatSessionNotify: 251 { 252 onSessionNotify(msg); 253 break; 254 } 255 256 case kWhatFetchSubtitleData: 257 { 258 pollForRawData( 259 msg, mFetchSubtitleDataGeneration, 260 /* fetch */ LiveSession::STREAMTYPE_SUBTITLES, 261 /* push */ kWhatSubtitleData); 262 263 break; 264 } 265 266 case kWhatFetchMetaData: 267 { 268 if (!mMetadataSelected) { 269 break; 270 } 271 272 pollForRawData( 273 msg, mFetchMetaDataGeneration, 274 /* fetch */ LiveSession::STREAMTYPE_METADATA, 275 /* push */ kWhatTimedMetaData); 276 277 break; 278 } 279 280 default: 281 Source::onMessageReceived(msg); 282 break; 283 } 284} 285 286void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 287 int32_t what; 288 CHECK(msg->findInt32("what", &what)); 289 290 switch (what) { 291 case LiveSession::kWhatPrepared: 292 { 293 // notify the current size here if we have it, otherwise report an initial size of (0,0) 294 sp<AMessage> format = getFormat(false /* audio */); 295 int32_t width; 296 int32_t height; 297 if (format != NULL && 298 format->findInt32("width", &width) && format->findInt32("height", &height)) { 299 notifyVideoSizeChanged(format); 300 } else { 301 notifyVideoSizeChanged(); 302 } 303 304 uint32_t flags = FLAG_CAN_PAUSE; 305 if (mLiveSession->isSeekable()) { 306 flags |= FLAG_CAN_SEEK; 307 flags |= FLAG_CAN_SEEK_BACKWARD; 308 flags |= FLAG_CAN_SEEK_FORWARD; 309 } 310 311 if (mLiveSession->hasDynamicDuration()) { 312 flags |= FLAG_DYNAMIC_DURATION; 313 } 314 315 notifyFlagsChanged(flags); 316 317 notifyPrepared(); 318 break; 319 } 320 321 case LiveSession::kWhatPreparationFailed: 322 { 323 status_t err; 324 CHECK(msg->findInt32("err", &err)); 325 326 notifyPrepared(err); 327 break; 328 } 329 330 case LiveSession::kWhatStreamsChanged: 331 { 332 uint32_t changedMask; 333 CHECK(msg->findInt32( 334 "changedMask", (int32_t *)&changedMask)); 335 336 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 337 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 338 339 sp<AMessage> reply; 340 CHECK(msg->findMessage("reply", &reply)); 341 342 sp<AMessage> notify = dupNotify(); 343 notify->setInt32("what", kWhatQueueDecoderShutdown); 344 notify->setInt32("audio", audio); 345 notify->setInt32("video", video); 346 notify->setMessage("reply", reply); 347 notify->post(); 348 break; 349 } 350 351 case LiveSession::kWhatBufferingStart: 352 { 353 sp<AMessage> notify = dupNotify(); 354 notify->setInt32("what", kWhatPauseOnBufferingStart); 355 notify->post(); 356 break; 357 } 358 359 case LiveSession::kWhatBufferingEnd: 360 { 361 sp<AMessage> notify = dupNotify(); 362 notify->setInt32("what", kWhatResumeOnBufferingEnd); 363 notify->post(); 364 break; 365 } 366 367 368 case LiveSession::kWhatBufferingUpdate: 369 { 370 sp<AMessage> notify = dupNotify(); 371 int32_t percentage; 372 CHECK(msg->findInt32("percentage", &percentage)); 373 notify->setInt32("what", kWhatBufferingUpdate); 374 notify->setInt32("percentage", percentage); 375 notify->post(); 376 break; 377 } 378 379 case LiveSession::kWhatMetadataDetected: 380 { 381 if (!mHasMetadata) { 382 mHasMetadata = true; 383 384 sp<AMessage> notify = dupNotify(); 385 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE 386 notify->setInt32("what", kWhatTimedMetaData); 387 notify->post(); 388 } 389 break; 390 } 391 392 case LiveSession::kWhatError: 393 { 394 break; 395 } 396 397 default: 398 TRESPASS(); 399 } 400} 401 402} // namespace android 403 404