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