michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #if !defined(RtspMediaResource_h_) michael@0: #define RtspMediaResource_h_ michael@0: michael@0: #include "MediaResource.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: class RtspTrackBuffer; michael@0: michael@0: /* RtspMediaResource michael@0: * RtspMediaResource provides an interface to deliver and control RTSP media michael@0: * data to RtspDecoder. michael@0: * michael@0: * RTSP Flow Start vs HTTP Flow Start: michael@0: * For HTTP (and files stored on disk), once the channel is created and response michael@0: * data is available, HTMLMediaElement::MediaLoadListener::OnStartRequest is michael@0: * called. (Note, this is an asynchronous call following channel->AsyncOpen). michael@0: * The decoder and MediaResource are set up to talk to each other: michael@0: * InitializeDecoderForChannel and FinishDecoderSetup. michael@0: * RtspMediaResource is different from this, in that FinishDecoderSetup is michael@0: * postponed until after the initial connection with the server is made. michael@0: * RtspController, owned by RtspMediaResource, provides the interface to setup michael@0: * the connection, and calls RtspMediaResource::Listener::OnConnected michael@0: * (from nsIStreamingProtocolListener). FinishDecoderSetup is then called to michael@0: * connect RtspMediaResource with RtspDecoder and allow HTMLMediaElement to michael@0: * request playback etc. michael@0: * michael@0: * Playback: michael@0: * When the user presses play/pause, HTMLMediaElement::Play/::Pause is called, michael@0: * subsequently making calls to the decoder state machine. Upon these state michael@0: * changes, the decoder is told to start reading and decoding data. This causes michael@0: * the nsIStreamingMediaController object to send play/pause commands to the michael@0: * server. michael@0: * Data is then delivered to the host and eventually written to the michael@0: * RtspTrackBuffer objects. Note that RtspMediaResource does not know about the michael@0: * play or pause state. It only knows about the data written into its buffers. michael@0: * michael@0: * Data Structures and Flow: michael@0: * Unlike HTTP, RTSP provides separate streams for audio and video. michael@0: * As such, it creates two RtspTrackBuffer objects for the audio and video data. michael@0: * Data is read using the function ReadFrameFromTrack. These buffer objects are michael@0: * ring buffers, implying that data from the network may be discarded if the michael@0: * decoder cannot read at a high enough rate. michael@0: * michael@0: * Data is delivered via RtspMediaResource::Listener::OnMediaDataAvailable. michael@0: * This Listener implements nsIStreamingProtocolListener, and writes the data to michael@0: * the appropriate RtspTrackBuffer. The decoder then reads the data by calling michael@0: * RtspMediaResource::ReadFrameFromTrack. Note that the decoder and decode michael@0: * thread will be blocked until data is available in one of the two buffers. michael@0: * michael@0: * Seeking: michael@0: * Since the frame data received after seek is not continuous with existing michael@0: * frames in RtspTrackBuffer, the buffer must be cleared. If we don't clear the michael@0: * old frame data in RtspTrackBuffer, the decoder's behavior will be michael@0: * unpredictable. So we add |mFrameType| in RtspTrackBuffer to do this: michael@0: * When we are seeking, the mFrameType flag is set, and RtspTrackBuffer will michael@0: * drop the incoming data until the RTSP server completes the seek operation. michael@0: * Note: seeking for RTSP is carried out based on sending the seek time to the michael@0: * server, unlike HTTP in which the seek time is converted to a byte offset. michael@0: * Thus, RtspMediaResource has a SeekTime function which should be called michael@0: * instead of Seek. michael@0: * */ michael@0: class RtspMediaResource : public BaseMediaResource michael@0: { michael@0: public: michael@0: RtspMediaResource(MediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI, michael@0: const nsACString& aContentType); michael@0: virtual ~RtspMediaResource(); michael@0: michael@0: // The following methods can be called on any thread. michael@0: michael@0: // Get the RtspMediaResource pointer if this MediaResource is a michael@0: // RtspMediaResource. For calling Rtsp specific functions. michael@0: virtual RtspMediaResource* GetRtspPointer() MOZ_OVERRIDE MOZ_FINAL { michael@0: return this; michael@0: } michael@0: michael@0: // Returns the nsIStreamingProtocolController in the RtspMediaResource. michael@0: // RtspMediaExtractor: request it to get mime type for creating decoder. michael@0: // RtspOmxDecoder: request it to send play/pause commands to RTSP server. michael@0: // The lifetime of mMediaStreamController is controlled by RtspMediaResource michael@0: // because the RtspMediaExtractor and RtspOmxDecoder won't hold the reference. michael@0: nsIStreamingProtocolController* GetMediaStreamController() { michael@0: return mMediaStreamController; michael@0: } michael@0: michael@0: virtual bool IsRealTime() MOZ_OVERRIDE { michael@0: return mRealTime; michael@0: } michael@0: michael@0: // The following methods can be called on any thread except main thread. michael@0: michael@0: // Read data from track. michael@0: // Parameters: michael@0: // aToBuffer, aToBufferSize: buffer pointer and buffer size. michael@0: // aReadCount: output actual read bytes. michael@0: // aFrameTime: output frame time stamp. michael@0: // aFrameSize: actual data size in track. michael@0: nsresult ReadFrameFromTrack(uint8_t* aBuffer, uint32_t aBufferSize, michael@0: uint32_t aTrackIdx, uint32_t& aBytes, michael@0: uint64_t& aTime, uint32_t& aFrameSize); michael@0: michael@0: // Seek to the given time offset michael@0: nsresult SeekTime(int64_t aOffset); michael@0: michael@0: // dummy michael@0: virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, michael@0: uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE{ michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // dummy michael@0: virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE {} michael@0: // dummy michael@0: virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE {} michael@0: // dummy michael@0: virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) michael@0: MOZ_OVERRIDE { michael@0: return NS_OK; michael@0: } michael@0: // dummy michael@0: virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE { michael@0: return NS_OK; michael@0: } michael@0: // dummy michael@0: virtual void StartSeekingForMetadata() MOZ_OVERRIDE {} michael@0: // dummy michael@0: virtual void EndSeekingForMetadata() MOZ_OVERRIDE {} michael@0: // dummy michael@0: virtual int64_t Tell() MOZ_OVERRIDE { return 0; } michael@0: michael@0: // Any thread michael@0: virtual void Pin() MOZ_OVERRIDE {} michael@0: virtual void Unpin() MOZ_OVERRIDE {} michael@0: michael@0: // dummy michael@0: virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; } michael@0: michael@0: virtual bool IsSuspended() MOZ_OVERRIDE { return false; } michael@0: virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; } michael@0: // dummy michael@0: virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { return 0; } michael@0: michael@0: virtual int64_t GetLength() MOZ_OVERRIDE { michael@0: if (mRealTime) { michael@0: return -1; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: // dummy michael@0: virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { return 0; } michael@0: // dummy michael@0: virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { return 0; } michael@0: // dummy michael@0: virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { michael@0: return false; michael@0: } michael@0: // dummy michael@0: nsresult GetCachedRanges(nsTArray& aRanges) MOZ_OVERRIDE { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // The following methods can be called on main thread only. michael@0: michael@0: virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE; michael@0: virtual nsresult Close() MOZ_OVERRIDE; michael@0: virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE; michael@0: virtual void Resume() MOZ_OVERRIDE; michael@0: virtual already_AddRefed GetCurrentPrincipal() MOZ_OVERRIDE; michael@0: virtual bool CanClone() MOZ_OVERRIDE { michael@0: return false; michael@0: } michael@0: virtual already_AddRefed CloneData(MediaDecoder* aDecoder) michael@0: MOZ_OVERRIDE { michael@0: return nullptr; michael@0: } michael@0: // dummy michael@0: virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, michael@0: uint32_t aCount) MOZ_OVERRIDE { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: virtual size_t SizeOfExcludingThis( michael@0: MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; michael@0: michael@0: virtual size_t SizeOfIncludingThis( michael@0: MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { michael@0: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: michael@0: // Listener implements nsIStreamingProtocolListener as michael@0: // mMediaStreamController's callback function. michael@0: // It holds RtspMediaResource reference to notify the connection status and michael@0: // data arrival. The Revoke function releases the reference when michael@0: // RtspMediaResource::OnDisconnected is called. michael@0: class Listener MOZ_FINAL : public nsIInterfaceRequestor, michael@0: public nsIStreamingProtocolListener michael@0: { michael@0: public: michael@0: Listener(RtspMediaResource* aResource) : mResource(aResource) {} michael@0: ~Listener() {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSISTREAMINGPROTOCOLLISTENER michael@0: michael@0: void Revoke(); michael@0: michael@0: private: michael@0: nsRefPtr mResource; michael@0: }; michael@0: friend class Listener; michael@0: michael@0: protected: michael@0: // Main thread access only. michael@0: // These are called on the main thread by Listener. michael@0: NS_DECL_NSISTREAMINGPROTOCOLLISTENER michael@0: michael@0: nsRefPtr mListener; michael@0: michael@0: private: michael@0: bool IsVideoEnabled(); michael@0: bool IsVideo(uint8_t tracks, nsIStreamingProtocolMetaData *meta); michael@0: // These two members are created at |RtspMediaResource::OnConnected|. michael@0: nsCOMPtr mMediaStreamController; michael@0: nsTArray> mTrackBuffer; michael@0: michael@0: // A flag that indicates the |RtspMediaResource::OnConnected| has already been michael@0: // called. michael@0: bool mIsConnected; michael@0: // live stream michael@0: bool mRealTime; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif michael@0: