HTTPLiveSource.cpp revision 6ffb1fd67eb8f00f130a6db914ba42a8432aec70
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#include "LiveSession.h" 26 27#include <media/IMediaHTTPService.h> 28#include <media/stagefright/foundation/ABuffer.h> 29#include <media/stagefright/foundation/ADebug.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/MediaErrors.h> 32#include <media/stagefright/MetaData.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 if (headers) { 49 mExtraHeaders = *headers; 50 51 ssize_t index = 52 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 53 54 if (index >= 0) { 55 mFlags |= kFlagIncognito; 56 57 mExtraHeaders.removeItemsAt(index); 58 } 59 } 60} 61 62NuPlayer::HTTPLiveSource::~HTTPLiveSource() { 63 if (mLiveSession != NULL) { 64 mLiveSession->disconnect(); 65 66 mLiveLooper->unregisterHandler(mLiveSession->id()); 67 mLiveLooper->unregisterHandler(id()); 68 mLiveLooper->stop(); 69 70 mLiveSession.clear(); 71 mLiveLooper.clear(); 72 } 73} 74 75void NuPlayer::HTTPLiveSource::prepareAsync() { 76 if (mLiveLooper == NULL) { 77 mLiveLooper = new ALooper; 78 mLiveLooper->setName("http live"); 79 mLiveLooper->start(); 80 81 mLiveLooper->registerHandler(this); 82 } 83 84 sp<AMessage> notify = new AMessage(kWhatSessionNotify, id()); 85 86 mLiveSession = new LiveSession( 87 notify, 88 (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, 89 mHTTPService); 90 91 mLiveLooper->registerHandler(mLiveSession); 92 93 mLiveSession->connectAsync( 94 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 95} 96 97void NuPlayer::HTTPLiveSource::start() { 98} 99 100sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) { 101 if (mLiveSession == NULL) { 102 return NULL; 103 } 104 105 sp<AMessage> format; 106 status_t err = mLiveSession->getStreamFormat( 107 audio ? LiveSession::STREAMTYPE_AUDIO 108 : LiveSession::STREAMTYPE_VIDEO, 109 &format); 110 111 if (err != OK) { 112 return NULL; 113 } 114 115 return format; 116} 117 118status_t NuPlayer::HTTPLiveSource::feedMoreTSData() { 119 return OK; 120} 121 122status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit( 123 bool audio, sp<ABuffer> *accessUnit) { 124 return mLiveSession->dequeueAccessUnit( 125 audio ? LiveSession::STREAMTYPE_AUDIO 126 : LiveSession::STREAMTYPE_VIDEO, 127 accessUnit); 128} 129 130status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { 131 return mLiveSession->getDuration(durationUs); 132} 133 134size_t NuPlayer::HTTPLiveSource::getTrackCount() const { 135 return mLiveSession->getTrackCount(); 136} 137 138sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { 139 return mLiveSession->getTrackInfo(trackIndex); 140} 141 142ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const { 143 if (mLiveSession == NULL) { 144 return -1; 145 } else { 146 return mLiveSession->getSelectedTrack(type); 147 } 148} 149 150status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) { 151 status_t err = mLiveSession->selectTrack(trackIndex, select); 152 153 if (err == OK) { 154 mFetchSubtitleDataGeneration++; 155 if (select) { 156 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 157 msg->setInt32("generation", mFetchSubtitleDataGeneration); 158 msg->post(); 159 } 160 } 161 162 // LiveSession::selectTrack returns BAD_VALUE when selecting the currently 163 // selected track, or unselecting a non-selected track. In this case it's an 164 // no-op so we return OK. 165 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; 166} 167 168status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { 169 return mLiveSession->seekTo(seekTimeUs); 170} 171 172void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 173 switch (msg->what()) { 174 case kWhatSessionNotify: 175 { 176 onSessionNotify(msg); 177 break; 178 } 179 180 case kWhatFetchSubtitleData: 181 { 182 int32_t generation; 183 CHECK(msg->findInt32("generation", &generation)); 184 185 if (generation != mFetchSubtitleDataGeneration) { 186 // stale 187 break; 188 } 189 190 sp<ABuffer> buffer; 191 if (mLiveSession->dequeueAccessUnit( 192 LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) { 193 sp<AMessage> notify = dupNotify(); 194 notify->setInt32("what", kWhatSubtitleData); 195 notify->setBuffer("buffer", buffer); 196 notify->post(); 197 198 int64_t timeUs, baseUs, durationUs, delayUs; 199 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 200 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 201 CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); 202 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 203 204 msg->post(delayUs > 0ll ? delayUs : 0ll); 205 } else { 206 // try again in 1 second 207 msg->post(1000000ll); 208 } 209 210 break; 211 } 212 213 default: 214 Source::onMessageReceived(msg); 215 break; 216 } 217} 218 219void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 220 int32_t what; 221 CHECK(msg->findInt32("what", &what)); 222 223 switch (what) { 224 case LiveSession::kWhatPrepared: 225 { 226 // notify the current size here if we have it, otherwise report an initial size of (0,0) 227 sp<AMessage> format = getFormat(false /* audio */); 228 int32_t width; 229 int32_t height; 230 if (format != NULL && 231 format->findInt32("width", &width) && format->findInt32("height", &height)) { 232 notifyVideoSizeChanged(format); 233 } else { 234 notifyVideoSizeChanged(); 235 } 236 237 uint32_t flags = FLAG_CAN_PAUSE; 238 if (mLiveSession->isSeekable()) { 239 flags |= FLAG_CAN_SEEK; 240 flags |= FLAG_CAN_SEEK_BACKWARD; 241 flags |= FLAG_CAN_SEEK_FORWARD; 242 } 243 244 if (mLiveSession->hasDynamicDuration()) { 245 flags |= FLAG_DYNAMIC_DURATION; 246 } 247 248 notifyFlagsChanged(flags); 249 250 notifyPrepared(); 251 break; 252 } 253 254 case LiveSession::kWhatPreparationFailed: 255 { 256 status_t err; 257 CHECK(msg->findInt32("err", &err)); 258 259 notifyPrepared(err); 260 break; 261 } 262 263 case LiveSession::kWhatStreamsChanged: 264 { 265 uint32_t changedMask; 266 CHECK(msg->findInt32( 267 "changedMask", (int32_t *)&changedMask)); 268 269 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 270 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 271 272 sp<AMessage> reply; 273 CHECK(msg->findMessage("reply", &reply)); 274 275 sp<AMessage> notify = dupNotify(); 276 notify->setInt32("what", kWhatQueueDecoderShutdown); 277 notify->setInt32("audio", audio); 278 notify->setInt32("video", video); 279 notify->setMessage("reply", reply); 280 notify->post(); 281 break; 282 } 283 284 case LiveSession::kWhatError: 285 { 286 break; 287 } 288 289 default: 290 TRESPASS(); 291 } 292} 293 294} // namespace android 295 296