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