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