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