content/media/RtspMediaResource.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/DebugOnly.h"
     9 #include "RtspMediaResource.h"
    11 #include "MediaDecoder.h"
    12 #include "mozilla/dom/HTMLMediaElement.h"
    13 #include "mozilla/Monitor.h"
    14 #include "mozilla/Preferences.h"
    15 #include "nsIScriptSecurityManager.h"
    16 #include "nsIStreamingProtocolService.h"
    17 #include "nsServiceManagerUtils.h"
    18 #ifdef NECKO_PROTOCOL_rtsp
    19 #include "mozilla/net/RtspChannelChild.h"
    20 #endif
    21 using namespace mozilla::net;
    23 #ifdef PR_LOGGING
    24 PRLogModuleInfo* gRtspMediaResourceLog;
    25 #define RTSP_LOG(msg, ...) PR_LOG(gRtspMediaResourceLog, PR_LOG_DEBUG, \
    26                                   (msg, ##__VA_ARGS__))
    27 // Debug logging macro with object pointer and class name.
    28 #define RTSPMLOG(msg, ...) \
    29         RTSP_LOG("%p [RtspMediaResource]: " msg, this, ##__VA_ARGS__)
    30 #else
    31 #define RTSP_LOG(msg, ...)
    32 #define RTSPMLOG(msg, ...)
    33 #endif
    35 namespace mozilla {
    37 /* class RtspTrackBuffer: a ring buffer implementation for audio/video track
    38  * un-decoded data.
    39  * The ring buffer is divided into BUFFER_SLOT_NUM slots,
    40  * and each slot's size is fixed(mSlotSize).
    41  * Even though the ring buffer is divided into fixed size slots, it still can
    42  * store the data which size is larger than one slot size.
    43  * */
    44 #define BUFFER_SLOT_NUM 8192
    45 #define BUFFER_SLOT_DEFAULT_SIZE 256
    46 #define BUFFER_SLOT_MAX_SIZE 512
    47 #define BUFFER_SLOT_INVALID -1
    48 #define BUFFER_SLOT_EMPTY 0
    50 struct BufferSlotData {
    51   int32_t mLength;
    52   uint64_t mTime;
    53 };
    55 class RtspTrackBuffer
    56 {
    57 public:
    58   RtspTrackBuffer(const char *aMonitor, int32_t aTrackIdx, uint32_t aSlotSize)
    59   : mMonitor(aMonitor)
    60   , mSlotSize(aSlotSize)
    61   , mTotalBufferSize(BUFFER_SLOT_NUM * mSlotSize)
    62   , mFrameType(0)
    63   , mIsStarted(false) {
    64     MOZ_COUNT_CTOR(RtspTrackBuffer);
    65 #ifdef PR_LOGGING
    66     mTrackIdx = aTrackIdx;
    67 #endif
    68     MOZ_ASSERT(mSlotSize < UINT32_MAX / BUFFER_SLOT_NUM);
    69     mRingBuffer = new uint8_t[mTotalBufferSize];
    70     Reset();
    71   };
    72   ~RtspTrackBuffer() {
    73     MOZ_COUNT_DTOR(RtspTrackBuffer);
    74     mRingBuffer = nullptr;
    75   };
    77   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    78     // including this
    79     size_t size = aMallocSizeOf(this);
    81     // excluding this
    82     size += mRingBuffer.SizeOfExcludingThis(aMallocSizeOf);
    84     return size;
    85   }
    87   void Start() {
    88     MonitorAutoLock monitor(mMonitor);
    89     mIsStarted = true;
    90     mFrameType = 0;
    91   }
    92   void Stop() {
    93     MonitorAutoLock monitor(mMonitor);
    94     mIsStarted = false;
    95   }
    97   // Read the data from mRingBuffer[mConsumerIdx*mSlotSize] into aToBuffer.
    98   // If the aToBufferSize is smaller than mBufferSlotDataLength[mConsumerIdx],
    99   // early return and set the aFrameSize to notify the reader the aToBuffer
   100   // doesn't have enough space. The reader must realloc the aToBuffer if it
   101   // wishes to read the data.
   102   nsresult ReadBuffer(uint8_t* aToBuffer, uint32_t aToBufferSize,
   103                       uint32_t& aReadCount, uint64_t& aFrameTime,
   104                       uint32_t& aFrameSize);
   105   // Write the data from aFromBuffer into mRingBuffer[mProducerIdx*mSlotSize].
   106   void WriteBuffer(const char *aFromBuffer, uint32_t aWriteCount,
   107                    uint64_t aFrameTime, uint32_t aFrameType);
   108   // Reset the mProducerIdx, mConsumerIdx, mBufferSlotDataLength[],
   109   // mBufferSlotDataTime[].
   110   void Reset();
   112   // We should call SetFrameType first then reset().
   113   // If we call reset() first, the queue may still has some "garbage" frame
   114   // from another thread's |OnMediaDataAvailable| before |SetFrameType|.
   115   void ResetWithFrameType(uint32_t aFrameType) {
   116     SetFrameType(aFrameType);
   117     Reset();
   118   }
   120 private:
   121   // The FrameType is sync to nsIStreamingProtocolController.h
   122   void SetFrameType(uint32_t aFrameType) {
   123     MonitorAutoLock monitor(mMonitor);
   124     mFrameType = mFrameType | aFrameType;
   125   }
   127   // A monitor lock to prevent racing condition.
   128   Monitor mMonitor;
   129 #ifdef PR_LOGGING
   130   // Indicate the track number for Rtsp.
   131   int32_t mTrackIdx;
   132 #endif
   133   // mProducerIdx: A slot index that we store data from
   134   // nsIStreamingProtocolController.
   135   // mConsumerIdx: A slot index that we read when decoder need(from OMX decoder).
   136   int32_t mProducerIdx;
   137   int32_t mConsumerIdx;
   139   // Because each slot's size is fixed, we need an array to record the real
   140   // data length and data time stamp.
   141   // The value in mBufferSlotData[index].mLength represents:
   142   // -1(BUFFER_SLOT_INVALID): The index of slot data is invalid, mConsumerIdx
   143   //                          should go forward.
   144   // 0(BUFFER_SLOT_EMPTY): The index slot is empty. mConsumerIdx should wait here.
   145   // positive value: The index slot contains valid data and the value is data size.
   146   BufferSlotData mBufferSlotData[BUFFER_SLOT_NUM];
   148   // The ring buffer pointer.
   149   nsAutoArrayPtr<uint8_t> mRingBuffer;
   150   // Each slot's size.
   151   uint32_t mSlotSize;
   152   // Total mRingBuffer's total size.
   153   uint32_t mTotalBufferSize;
   154   // A flag that that indicate the incoming data should be dropped or stored.
   155   // When we are seeking, the incoming data should be dropped.
   156   // Bit definition in |nsIStreamingProtocolController.h|
   157   uint32_t mFrameType;
   159   // Set true/false when |Start()/Stop()| is called.
   160   bool mIsStarted;
   161 };
   163 nsresult RtspTrackBuffer::ReadBuffer(uint8_t* aToBuffer, uint32_t aToBufferSize,
   164                                      uint32_t& aReadCount, uint64_t& aFrameTime,
   165                                      uint32_t& aFrameSize)
   166 {
   167   MonitorAutoLock monitor(mMonitor);
   168   RTSPMLOG("ReadBuffer mTrackIdx %d mProducerIdx %d mConsumerIdx %d "
   169            "mBufferSlotData[mConsumerIdx].mLength %d"
   170            ,mTrackIdx ,mProducerIdx ,mConsumerIdx
   171            ,mBufferSlotData[mConsumerIdx].mLength);
   172   // Reader should skip the slots with mLength==BUFFER_SLOT_INVALID.
   173   // The loop ends when
   174   // 1. Read data successfully
   175   // 2. Fail to read data due to aToBuffer's space
   176   // 3. No data in this buffer
   177   // 4. mIsStarted is not set
   178   while (1) {
   179     if (mBufferSlotData[mConsumerIdx].mLength > 0) {
   180       // Check the aToBuffer space is enough for data copy.
   181       if ((int32_t)aToBufferSize < mBufferSlotData[mConsumerIdx].mLength) {
   182         aFrameSize = mBufferSlotData[mConsumerIdx].mLength;
   183         break;
   184       }
   185       uint32_t slots = (mBufferSlotData[mConsumerIdx].mLength / mSlotSize) + 1;
   186       // we have data, copy to aToBuffer
   187       MOZ_ASSERT(mBufferSlotData[mConsumerIdx].mLength <=
   188                  (int32_t)((BUFFER_SLOT_NUM - mConsumerIdx) * mSlotSize));
   189       memcpy(aToBuffer,
   190              (void *)(&mRingBuffer[mSlotSize * mConsumerIdx]),
   191              mBufferSlotData[mConsumerIdx].mLength);
   193       aFrameSize = aReadCount = mBufferSlotData[mConsumerIdx].mLength;
   194       aFrameTime = mBufferSlotData[mConsumerIdx].mTime;
   195       RTSPMLOG("DataLength %d, data time %lld"
   196                ,mBufferSlotData[mConsumerIdx].mLength
   197                ,mBufferSlotData[mConsumerIdx].mTime);
   198       // After reading the data, we set current index of mBufferSlotDataLength
   199       // to BUFFER_SLOT_EMPTY to indicate these slots are free.
   200       for (uint32_t i = mConsumerIdx; i < mConsumerIdx + slots; ++i) {
   201         mBufferSlotData[i].mLength = BUFFER_SLOT_EMPTY;
   202         mBufferSlotData[i].mTime = BUFFER_SLOT_EMPTY;
   203       }
   204       mConsumerIdx = (mConsumerIdx + slots) % BUFFER_SLOT_NUM;
   205       break;
   206     } else if (mBufferSlotData[mConsumerIdx].mLength == BUFFER_SLOT_INVALID) {
   207       mConsumerIdx = (mConsumerIdx + 1) % BUFFER_SLOT_NUM;
   208       RTSPMLOG("BUFFER_SLOT_INVALID move forward");
   209     } else {
   210       // No data, and disconnected.
   211       if (!mIsStarted) {
   212         return NS_ERROR_FAILURE;
   213       }
   214       // No data, the decode thread is blocked here until we receive
   215       // OnMediaDataAvailable. The OnMediaDataAvailable will call WriteBuffer()
   216       // to wake up the decode thread.
   217       RTSPMLOG("monitor.Wait()");
   218       monitor.Wait();
   219     }
   220   }
   221   return NS_OK;
   222 }
   224 /* When we perform a WriteBuffer, we check mIsStarted and aFrameType first.
   225  * These flags prevent "garbage" frames from being written into the buffer.
   226  *
   227  * After writing the data into the buffer, we check to see if we wrote over a
   228  * slot, and update mConsumerIdx if necessary.
   229  * This ensures that the decoder will get the "oldest" data available in the
   230  * buffer.
   231  *
   232  * If the incoming data is larger than one slot size (isMultipleSlots), we do
   233  * |mBufferSlotData[].mLength = BUFFER_SLOT_INVALID;| for other slots except the
   234  * first slot, in order to notify the reader that some slots are unavailable.
   235  *
   236  * If the incoming data is isMultipleSlots and crosses the end of
   237  * BUFFER_SLOT_NUM, returnToHead is set to true and the data will continue to
   238  * be written from head(index 0).
   239  *
   240  * MEDIASTREAM_FRAMETYPE_DISCONTINUITY currently is used when we are seeking.
   241  * */
   242 void RtspTrackBuffer::WriteBuffer(const char *aFromBuffer, uint32_t aWriteCount,
   243                                   uint64_t aFrameTime, uint32_t aFrameType)
   244 {
   245   MonitorAutoLock monitor(mMonitor);
   246   if (!mIsStarted) {
   247     RTSPMLOG("mIsStarted is false");
   248     return;
   249   }
   250   if (mTotalBufferSize < aWriteCount) {
   251     RTSPMLOG("mTotalBufferSize < aWriteCount, incoming data is too large");
   252     return;
   253   }
   254   // Checking the incoming data's frame type.
   255   // If we receive MEDIASTREAM_FRAMETYPE_DISCONTINUITY, clear the mFrameType
   256   // imply the RtspTrackBuffer is ready for receive data.
   257   if (aFrameType & MEDIASTREAM_FRAMETYPE_DISCONTINUITY) {
   258     mFrameType = mFrameType & (~MEDIASTREAM_FRAMETYPE_DISCONTINUITY);
   259     RTSPMLOG("Clear mFrameType");
   260     return;
   261   }
   262   // Checking current buffer frame type.
   263   // If the MEDIASTREAM_FRAMETYPE_DISCONTINUNITY bit is set, imply the
   264   // RtspTrackBuffer can't receive data now. So we drop the frame until we
   265   // receive MEDIASTREAM_FRAMETYPE_DISCONTINUNITY.
   266   if (mFrameType & MEDIASTREAM_FRAMETYPE_DISCONTINUITY) {
   267     RTSPMLOG("Return because the mFrameType is set");
   268     return;
   269   }
   270   // The flag is true if the incoming data is larger than one slot size.
   271   bool isMultipleSlots = false;
   272   // The flag is true if the incoming data is larger than remainder free slots
   273   bool returnToHead = false;
   274   // Calculate how many slots the incoming data needed.
   275   int32_t slots = 1;
   276   int32_t i;
   277   RTSPMLOG("WriteBuffer mTrackIdx %d mProducerIdx %d mConsumerIdx %d",
   278            mTrackIdx, mProducerIdx,mConsumerIdx);
   279   if (aWriteCount > mSlotSize) {
   280     isMultipleSlots = true;
   281     slots = (aWriteCount / mSlotSize) + 1;
   282   }
   283   if (isMultipleSlots &&
   284       (aWriteCount > (BUFFER_SLOT_NUM - mProducerIdx) * mSlotSize)) {
   285     returnToHead = true;
   286   }
   287   RTSPMLOG("slots %d isMultipleSlots %d returnToHead %d",
   288            slots, isMultipleSlots, returnToHead);
   289   if (returnToHead) {
   290     // Clear the rest index of mBufferSlotData[].mLength
   291     for (i = mProducerIdx; i < BUFFER_SLOT_NUM; ++i) {
   292       mBufferSlotData[i].mLength = BUFFER_SLOT_INVALID;
   293     }
   294     // We wrote one or more slots that the decode thread has not yet read.
   295     // So the mConsumerIdx returns to the head of slot buffer and moves forward
   296     // to the oldest slot.
   297     if (mProducerIdx <= mConsumerIdx && mConsumerIdx < mProducerIdx + slots) {
   298       mConsumerIdx = 0;
   299       for (i = mConsumerIdx; i < BUFFER_SLOT_NUM; ++i) {
   300         if (mBufferSlotData[i].mLength > 0) {
   301           mConsumerIdx = i;
   302           break;
   303         }
   304       }
   305     }
   306     mProducerIdx = 0;
   307   }
   309   memcpy(&(mRingBuffer[mSlotSize * mProducerIdx]), aFromBuffer, aWriteCount);
   311   if (mProducerIdx <= mConsumerIdx && mConsumerIdx < mProducerIdx + slots
   312       && mBufferSlotData[mConsumerIdx].mLength > 0) {
   313     // Wrote one or more slots that the decode thread has not yet read.
   314     RTSPMLOG("overwrite!! %d time %lld"
   315              ,mTrackIdx,mBufferSlotData[mConsumerIdx].mTime);
   316     mBufferSlotData[mProducerIdx].mLength = aWriteCount;
   317     mBufferSlotData[mProducerIdx].mTime = aFrameTime;
   318     // Clear the mBufferSlotDataLength except the start slot.
   319     if (isMultipleSlots) {
   320       for (i = mProducerIdx + 1; i < mProducerIdx + slots; ++i) {
   321         mBufferSlotData[i].mLength = BUFFER_SLOT_INVALID;
   322       }
   323     }
   324     mProducerIdx = (mProducerIdx + slots) % BUFFER_SLOT_NUM;
   325     // Move the mConsumerIdx forward to ensure that the decoder reads the
   326     // oldest data available.
   327     mConsumerIdx = mProducerIdx;
   328   } else {
   329     // Normal case, the writer doesn't take over the reader.
   330     mBufferSlotData[mProducerIdx].mLength = aWriteCount;
   331     mBufferSlotData[mProducerIdx].mTime = aFrameTime;
   332     // Clear the mBufferSlotData[].mLength except the start slot.
   333     if (isMultipleSlots) {
   334       for (i = mProducerIdx + 1; i < mProducerIdx + slots; ++i) {
   335         mBufferSlotData[i].mLength = BUFFER_SLOT_INVALID;
   336       }
   337     }
   338     mProducerIdx = (mProducerIdx + slots) % BUFFER_SLOT_NUM;
   339   }
   341   mMonitor.NotifyAll();
   342 }
   344 void RtspTrackBuffer::Reset() {
   345   MonitorAutoLock monitor(mMonitor);
   346   mProducerIdx = 0;
   347   mConsumerIdx = 0;
   348   for (uint32_t i = 0; i < BUFFER_SLOT_NUM; ++i) {
   349     mBufferSlotData[i].mLength = BUFFER_SLOT_EMPTY;
   350     mBufferSlotData[i].mTime = BUFFER_SLOT_EMPTY;
   351   }
   352   mMonitor.NotifyAll();
   353 }
   355 RtspMediaResource::RtspMediaResource(MediaDecoder* aDecoder,
   356     nsIChannel* aChannel, nsIURI* aURI, const nsACString& aContentType)
   357   : BaseMediaResource(aDecoder, aChannel, aURI, aContentType)
   358   , mIsConnected(false)
   359   , mRealTime(false)
   360 {
   361 #ifndef NECKO_PROTOCOL_rtsp
   362   MOZ_CRASH("Should not be called except for B2G platform");
   363 #else
   364   MOZ_ASSERT(aChannel);
   365   mMediaStreamController =
   366     static_cast<RtspChannelChild*>(aChannel)->GetController();
   367   MOZ_ASSERT(mMediaStreamController);
   368   mListener = new Listener(this);
   369   mMediaStreamController->AsyncOpen(mListener);
   370 #ifdef PR_LOGGING
   371   if (!gRtspMediaResourceLog) {
   372     gRtspMediaResourceLog = PR_NewLogModule("RtspMediaResource");
   373   }
   374 #endif
   375 #endif
   376 }
   378 RtspMediaResource::~RtspMediaResource()
   379 {
   380   RTSPMLOG("~RtspMediaResource");
   381   if (mListener) {
   382     // Kill its reference to us since we're going away
   383     mListener->Revoke();
   384   }
   385 }
   387 size_t
   388 RtspMediaResource::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   389 {
   390   size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
   391   size += mTrackBuffer.SizeOfExcludingThis(aMallocSizeOf);
   393   // Include the size of each track buffer.
   394   for (size_t i = 0; i < mTrackBuffer.Length(); i++) {
   395     size += mTrackBuffer[i]->SizeOfIncludingThis(aMallocSizeOf);
   396   }
   398   // Could add in the future:
   399   // - mMediaStreamController
   401   return size;
   402 }
   404 //----------------------------------------------------------------------------
   405 // RtspMediaResource::Listener
   406 //----------------------------------------------------------------------------
   407 NS_IMPL_ISUPPORTS(RtspMediaResource::Listener,
   408                   nsIInterfaceRequestor, nsIStreamingProtocolListener);
   410 nsresult
   411 RtspMediaResource::Listener::OnMediaDataAvailable(uint8_t aTrackIdx,
   412                                                   const nsACString &data,
   413                                                   uint32_t length,
   414                                                   uint32_t offset,
   415                                                   nsIStreamingProtocolMetaData *meta)
   416 {
   417   if (!mResource)
   418     return NS_OK;
   419   return mResource->OnMediaDataAvailable(aTrackIdx, data, length, offset, meta);
   420 }
   422 nsresult
   423 RtspMediaResource::Listener::OnConnected(uint8_t aTrackIdx,
   424                                          nsIStreamingProtocolMetaData *meta)
   425 {
   426   if (!mResource)
   427     return NS_OK;
   428   return mResource->OnConnected(aTrackIdx, meta);
   429 }
   431 nsresult
   432 RtspMediaResource::Listener::OnDisconnected(uint8_t aTrackIdx, nsresult reason)
   433 {
   434   if (!mResource)
   435     return NS_OK;
   436   return mResource->OnDisconnected(aTrackIdx, reason);
   437 }
   439 nsresult
   440 RtspMediaResource::Listener::GetInterface(const nsIID & aIID, void **aResult)
   441 {
   442   return QueryInterface(aIID, aResult);
   443 }
   445 void
   446 RtspMediaResource::Listener::Revoke()
   447 {
   448   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   449   if (mResource) {
   450     mResource = nullptr;
   451   }
   452 }
   454 nsresult
   455 RtspMediaResource::ReadFrameFromTrack(uint8_t* aBuffer, uint32_t aBufferSize,
   456                                       uint32_t aTrackIdx, uint32_t& aBytes,
   457                                       uint64_t& aTime, uint32_t& aFrameSize)
   458 {
   459   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
   460   NS_ASSERTION(aTrackIdx < mTrackBuffer.Length(),
   461                "ReadTrack index > mTrackBuffer");
   462   MOZ_ASSERT(aBuffer);
   464   return mTrackBuffer[aTrackIdx]->ReadBuffer(aBuffer, aBufferSize, aBytes,
   465                                              aTime, aFrameSize);
   466 }
   468 nsresult
   469 RtspMediaResource::OnMediaDataAvailable(uint8_t aTrackIdx,
   470                                         const nsACString &data,
   471                                         uint32_t length,
   472                                         uint32_t offset,
   473                                         nsIStreamingProtocolMetaData *meta)
   474 {
   475   uint64_t time;
   476   uint32_t frameType;
   477   meta->GetTimeStamp(&time);
   478   meta->GetFrameType(&frameType);
   479   if (mRealTime) {
   480     time = 0;
   481   }
   482   mTrackBuffer[aTrackIdx]->WriteBuffer(data.BeginReading(), length, time,
   483                                        frameType);
   484   return NS_OK;
   485 }
   487 // Bug 962309 - Video RTSP support should be disabled in 1.3
   488 bool
   489 RtspMediaResource::IsVideoEnabled()
   490 {
   491   return Preferences::GetBool("media.rtsp.video.enabled", false);
   492 }
   494 bool
   495 RtspMediaResource::IsVideo(uint8_t tracks, nsIStreamingProtocolMetaData *meta)
   496 {
   497   bool isVideo = false;
   498   for (int i = 0; i < tracks; ++i) {
   499     nsCOMPtr<nsIStreamingProtocolMetaData> trackMeta;
   500     mMediaStreamController->GetTrackMetaData(i, getter_AddRefs(trackMeta));
   501     MOZ_ASSERT(trackMeta);
   502     uint32_t w = 0, h = 0;
   503     trackMeta->GetWidth(&w);
   504     trackMeta->GetHeight(&h);
   505     if (w > 0 || h > 0) {
   506       isVideo = true;
   507       break;
   508     }
   509   }
   510   return isVideo;
   511 }
   513 nsresult
   514 RtspMediaResource::OnConnected(uint8_t aTrackIdx,
   515                                nsIStreamingProtocolMetaData *meta)
   516 {
   517   if (mIsConnected) {
   518     for (uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
   519       mTrackBuffer[i]->Start();
   520     }
   521     return NS_OK;
   522   }
   524   uint8_t tracks;
   525   mMediaStreamController->GetTotalTracks(&tracks);
   527   // If the preference of RTSP video feature is not enabled and the streaming is
   528   // video, we give up moving forward.
   529   if (!IsVideoEnabled() && IsVideo(tracks, meta)) {
   530     // Give up, report error to media element.
   531     nsCOMPtr<nsIRunnable> event =
   532       NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
   533     NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   534     return NS_ERROR_FAILURE;
   535   }
   536   uint64_t duration = 0;
   537   for (int i = 0; i < tracks; ++i) {
   538     nsCString rtspTrackId("RtspTrack");
   539     rtspTrackId.AppendInt(i);
   540     nsCOMPtr<nsIStreamingProtocolMetaData> trackMeta;
   541     mMediaStreamController->GetTrackMetaData(i, getter_AddRefs(trackMeta));
   542     MOZ_ASSERT(trackMeta);
   543     trackMeta->GetDuration(&duration);
   545     // Here is a heuristic to estimate the slot size.
   546     // For video track, calculate the width*height.
   547     // For audio track, use the BUFFER_SLOT_DEFAULT_SIZE because the w*h is 0.
   548     // Finally clamp them into (BUFFER_SLOT_DEFAULT_SIZE,BUFFER_SLOT_MAX_SIZE)
   549     uint32_t w, h;
   550     uint32_t slotSize;
   551     trackMeta->GetWidth(&w);
   552     trackMeta->GetHeight(&h);
   553     slotSize = clamped((int32_t)(w * h), BUFFER_SLOT_DEFAULT_SIZE,
   554                        BUFFER_SLOT_MAX_SIZE);
   555     mTrackBuffer.AppendElement(new RtspTrackBuffer(rtspTrackId.get(),
   556                                                    i, slotSize));
   557     mTrackBuffer[i]->Start();
   558   }
   560   if (!mDecoder) {
   561     return NS_ERROR_FAILURE;
   562   }
   564   // If the duration is 0, imply the stream is live stream.
   565   if (duration) {
   566     // Not live stream.
   567     mRealTime = false;
   568     bool seekable = true;
   569     mDecoder->SetInfinite(false);
   570     mDecoder->SetTransportSeekable(seekable);
   571     mDecoder->SetDuration(duration);
   572   } else {
   573     // Live stream.
   574     // Check the preference "media.realtime_decoder.enabled".
   575     if (!Preferences::GetBool("media.realtime_decoder.enabled", false)) {
   576       // Give up, report error to media element.
   577       nsCOMPtr<nsIRunnable> event =
   578         NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
   579       NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   580       return NS_ERROR_FAILURE;
   581     } else {
   582       mRealTime = true;
   583       bool seekable = false;
   584       mDecoder->SetInfinite(true);
   585       mDecoder->SetTransportSeekable(seekable);
   586       mDecoder->SetMediaSeekable(seekable);
   587     }
   588   }
   589   // Fires an initial progress event and sets up the stall counter so stall events
   590   // fire if no download occurs within the required time frame.
   591   mDecoder->Progress(false);
   593   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   594   NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
   595   dom::HTMLMediaElement* element = owner->GetMediaElement();
   596   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
   598   element->FinishDecoderSetup(mDecoder, this);
   599   mIsConnected = true;
   601   return NS_OK;
   602 }
   604 nsresult
   605 RtspMediaResource::OnDisconnected(uint8_t aTrackIdx, nsresult aReason)
   606 {
   607   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   609   for (uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
   610     mTrackBuffer[i]->Stop();
   611     mTrackBuffer[i]->Reset();
   612   }
   614   if (mDecoder) {
   615     if (aReason == NS_ERROR_NOT_INITIALIZED ||
   616         aReason == NS_ERROR_CONNECTION_REFUSED ||
   617         aReason == NS_ERROR_NOT_CONNECTED ||
   618         aReason == NS_ERROR_NET_TIMEOUT) {
   619       // Report error code to Decoder.
   620       RTSPMLOG("Error in OnDisconnected 0x%x", aReason);
   621       mDecoder->NetworkError();
   622     } else {
   623       // Resetting the decoder and media element when the connection
   624       // between RTSP client and server goes down.
   625       mDecoder->ResetConnectionState();
   626     }
   627   }
   629   if (mListener) {
   630     // Note: Listener's Revoke() kills its reference to us, which means it would
   631     // release |this| object. So, ensure it is called in the end of this method.
   632     mListener->Revoke();
   633   }
   635   return NS_OK;
   636 }
   638 void RtspMediaResource::Suspend(bool aCloseImmediately)
   639 {
   640   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   641   if (NS_WARN_IF(!mDecoder)) {
   642     return;
   643   }
   645   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   646   NS_ENSURE_TRUE_VOID(owner);
   647   dom::HTMLMediaElement* element = owner->GetMediaElement();
   648   NS_ENSURE_TRUE_VOID(element);
   650   mMediaStreamController->Suspend();
   651   element->DownloadSuspended();
   652 }
   654 void RtspMediaResource::Resume()
   655 {
   656   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   657   if (NS_WARN_IF(!mDecoder)) {
   658     return;
   659   }
   661   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   662   NS_ENSURE_TRUE_VOID(owner);
   663   dom::HTMLMediaElement* element = owner->GetMediaElement();
   664   NS_ENSURE_TRUE_VOID(element);
   666   if (mChannel) {
   667     element->DownloadResumed();
   668   }
   669   mMediaStreamController->Resume();
   670 }
   672 nsresult RtspMediaResource::Open(nsIStreamListener **aStreamListener)
   673 {
   674   return NS_OK;
   675 }
   677 nsresult RtspMediaResource::Close()
   678 {
   679   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   680   mMediaStreamController->Stop();
   681   // Since mDecoder is not an nsCOMPtr in BaseMediaResource, we have to
   682   // explicitly set it as null pointer in order to prevent misuse from this
   683   // object (RtspMediaResource).
   684   if (mDecoder) {
   685     mDecoder = nullptr;
   686   }
   687   return NS_OK;
   688 }
   690 already_AddRefed<nsIPrincipal> RtspMediaResource::GetCurrentPrincipal()
   691 {
   692   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   694   nsCOMPtr<nsIPrincipal> principal;
   695   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   696   if (!secMan || !mChannel)
   697     return nullptr;
   698   secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
   699   return principal.forget();
   700 }
   702 nsresult RtspMediaResource::SeekTime(int64_t aOffset)
   703 {
   704   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
   706   RTSPMLOG("Seek requested for aOffset [%lld] for decoder [%p]",
   707            aOffset, mDecoder);
   708   // Clear buffer and raise the frametype flag.
   709   for(uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
   710     mTrackBuffer[i]->ResetWithFrameType(MEDIASTREAM_FRAMETYPE_DISCONTINUITY);
   711   }
   713   return mMediaStreamController->Seek(aOffset);
   714 }
   716 } // namespace mozilla

mercurial