/* * device.h: The basic device interface * * See the main source file 'vdr.c' for copyright information and * how to reach the author. * * $Id: device.h 1.51 2005/01/08 10:15:00 kls Exp $ */ #ifndef __DEVICE_H #define __DEVICE_H #include "ci.h" #include "eit.h" #include "filter.h" #include "nit.h" #include "pat.h" #include "ringbuffer.h" #include "sdt.h" #include "sections.h" #include "thread.h" #include "tools.h" #define MAXDEVICES 16 // the maximum number of devices in the system #define MAXPIDHANDLES 16 // the maximum number of different PIDs per device #define MAXRECEIVERS 16 // the maximum number of receivers per device #define MAXVOLUME 255 #define VOLUMEDELTA 5 // used to increase/decrease the volume #define TS_SIZE 188 #define TS_SYNC_BYTE 0x47 #define PID_MASK_HI 0x1F enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; enum ePlayMode { pmNone, // audio/video from decoder pmAudioVideo, // audio/video from player pmAudioOnly, // audio only from player, video from decoder pmAudioOnlyBlack, // audio only from player, no video (black screen) pmVideoOnly, // video only from player, audio from decoder pmExtern_THIS_SHOULD_BE_AVOIDED // external player (e.g. MPlayer), release the device // WARNING: USE THIS MODE ONLY AS A LAST RESORT, IF YOU // ABSOLUTELY, POSITIVELY CAN'T IMPLEMENT YOUR PLAYER // THE WAY IT IS SUPPOSED TO WORK. FORCING THE DEVICE // TO RELEASE ITS FILES HANDLES (OR WHATEVER RESOURCES // IT MAY USE) TO ALLOW AN EXTERNAL PLAYER TO ACCESS // THEM MEANS THAT SUCH A PLAYER WILL NEED TO HAVE // DETAILED KNOWLEDGE ABOUT THE INTERNALS OF THE DEVICE // IN USE. AS A CONSEQUENCE, YOUR PLAYER MAY NOT WORK // IF A PARTICULAR VDR INSTALLATION USES A DEVICE NOT // KNOWN TO YOUR PLAYER. }; enum eVideoSystem { vsPAL, vsNTSC }; enum eTrackType { ttNone, ttAudio, ttAudioFirst = ttAudio, ttAudioLast = ttAudioFirst + 31/*XXX MAXAPIDS - 1*/, ttDolby, ttDolbyFirst = ttDolby, ttDolbyLast = ttDolbyFirst + 31/*XXX MAXAPIDS - 1*/, /* future... ttSubtitle, ttSubtitleFirst = ttSubtitle, ttSubtitleLast = ttSubtitleFirst + 31, */ ttMaxTrackTypes }; #define IS_AUDIO_TRACK(t) (ttAudioFirst <= (t) && (t) <= ttAudioLast) #define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast) struct tTrackId { uint16_t id; // The PES packet id or the PID. char language[8]; // something like either "eng" or "deu/eng" char description[32]; // something like "Dolby Digital 5.1" // for future use: uint32_t flags; // Used to further identify the actual track. }; class cChannel; class cPlayer; class cReceiver; class cSpuDecoder; class cPesAssembler; /// The cDevice class is the base from which actual devices can be derived. class cDevice : public cThread { private: static int numDevices; static int useDevice; static cDevice *device[MAXDEVICES]; static cDevice *primaryDevice; public: static int NumDevices(void) { return numDevices; } ///< Returns the total number of devices. static void SetUseDevice(int n); ///< Sets the 'useDevice' flag of the given device. ///< If this function is not called before initializing, all devices ///< will be used. static bool UseDevice(int n) { return useDevice == 0 || (useDevice & (1 << n)) != 0; } ///< Tells whether the device with the given card index shall be used in ///< this instance of VDR. static bool SetPrimaryDevice(int n); ///< Sets the primary device to 'n'. ///< \param n must be in the range 1...numDevices. ///< \return true if this was possible. static cDevice *PrimaryDevice(void) { return primaryDevice; } ///< Returns the primary device. static cDevice *ActualDevice(void); ///< Returns the actual receiving device in case of Transfer Mode, or the ///< primary device otherwise. static cDevice *GetDevice(int Index); ///< Gets the device with the given Index. ///< \param Index must be in the range 0..numDevices-1. ///< \return A pointer to the device, or NULL if the Index was invalid. static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL); ///< Returns a device that is able to receive the given Channel at the ///< given Priority. ///< See ProvidesChannel() for more information on how ///< priorities are handled, and the meaning of NeedsDetachReceivers. static void Shutdown(void); ///< Closes down all devices. ///< Must be called at the end of the program. private: static int nextCardIndex; int cardIndex; protected: cDevice(void); virtual ~cDevice(); static int NextCardIndex(int n = 0); ///< Calculates the next card index. ///< Each device in a given machine must have a unique card index, which ///< will be used to identify the device for assigning Ca parameters and ///< deciding whether to actually use that device in this particular ///< instance of VDR. Every time a new cDevice is created, it will be ///< given the current nextCardIndex, and then nextCardIndex will be ///< automatically incremented by 1. A derived class can determine whether ///< a given device shall be used by checking UseDevice(NextCardIndex()). ///< If a device is skipped, or if there are possible device indexes left ///< after a derived class has set up all its devices, NextCardIndex(n) ///< must be called, where n is the number of card indexes to skip. virtual void MakePrimaryDevice(bool On); ///< Informs a device that it will be the primary device. If there is ///< anything the device needs to set up when it becomes the primary ///< device (On = true) or to shut down when it no longer is the primary ///< device (On = false), it should do so in this function. public: bool IsPrimaryDevice(void) const { return this == primaryDevice; } int CardIndex(void) const { return cardIndex; } ///< Returns the card index of this device (0 ... MAXDEVICES - 1). int DeviceNumber(void) const; ///< Returns the number of this device (0 ... MAXDEVICES - 1). virtual int ProvidesCa(const cChannel *Channel) const;//XXX PLUGINS.html!!! //XXX describe changed functionality!!! ///< Checks whether this device provides the given value in its ///< caCaps. Returns 0 if the value is not provided, 1 if only this ///< value is provided, and > 1 if this and other values are provided. ///< If the given value is equal to the number of this device, ///< 1 is returned. If it is 0 (FTA), 1 plus the number of other values ///< in caCaps is returned. virtual bool HasDecoder(void) const; ///< Tells whether this device has an MPEG decoder. // SPU facilities public: virtual cSpuDecoder *GetSpuDecoder(void); ///< Returns a pointer to the device's SPU decoder (or NULL, if this ///< device doesn't have an SPU decoder). // Channel facilities protected: static int currentChannel; public: virtual bool ProvidesSource(int Source) const; ///< Returns true if this device can provide the given source. virtual bool ProvidesTransponder(const cChannel *Channel) const; ///< XXX -> PLUGINS.html! virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const; ///< Returns true if this device can provide the given channel. ///< In case the device has cReceivers attached to it or it is the primary ///< device, Priority is used to decide whether the caller's request can ///< be honored. ///< The special Priority value -1 will tell the caller whether this device ///< is principally able to provide the given Channel, regardless of any ///< attached cReceivers. ///< If NeedsDetachReceivers is given, the resulting value in it will tell the ///< caller whether or not it will have to detach any currently attached ///< receivers from this device before calling SwitchChannel. Note ///< that the return value in NeedsDetachReceivers is only meaningful if the ///< function itself actually returns true. ///< The default implementation always returns false, so a derived cDevice ///< class that can provide channels must implement this function. bool SwitchChannel(const cChannel *Channel, bool LiveView); ///< Switches the device to the given Channel, initiating transfer mode ///< if necessary. static bool SwitchChannel(int Direction); ///< Switches the primary device to the next available channel in the given ///< Direction (only the sign of Direction is evaluated, positive values ///< switch to higher channel numbers). private: eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ///< Sets the device to the given channel (general setup). protected: virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); ///< Sets the device to the given channel (actual physical setup). public: static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } ///< Returns the number of the current channel on the primary device. virtual bool HasLock(int TimeoutMs = 0);//XXX PLUGINS.html ///< Returns true if the device has a lock on the requested transponder. ///< Default is true, a specific device implementation may return false ///< to indicate that it is not ready yet. ///< If TimeoutMs is not zero, waits for the given number of milliseconds ///< before returning false. virtual bool HasProgramme(void); ///< Returns true if the device is currently showing any programme to ///< the user, either through replaying or live. // PID handle facilities private: bool active; virtual void Action(void); protected: enum ePidType { ptAudio, ptVideo, ptPcr, ptTeletext, ptDolby, ptOther }; class cPidHandle { public: int pid; int handle; int used; cPidHandle(void) { pid = used = 0; handle = -1; } }; cPidHandle pidHandles[MAXPIDHANDLES]; bool HasPid(int Pid) const; ///< Returns true if this device is currently receiving the given PID. bool AddPid(int Pid, ePidType PidType = ptOther); ///< Adds a PID to the set of PIDs this device shall receive. void DelPid(int Pid, ePidType PidType = ptOther); ///< Deletes a PID from the set of PIDs this device shall receive. virtual bool SetPid(cPidHandle *Handle, int Type, bool On); ///< Does the actual PID setting on this device. ///< On indicates whether the PID shall be added or deleted. ///< Handle->handle can be used by the device to store information it ///< needs to receive this PID (for instance a file handle). ///< Handle->used indicated how many receivers are using this PID. ///< Type indicates some special types of PIDs, which the device may ///< need to set in a specific way. // Section filter facilities private: cSectionHandler *sectionHandler; cEitFilter *eitFilter; cPatFilter *patFilter; cSdtFilter *sdtFilter; cNitFilter *nitFilter; protected: void StartSectionHandler(void); ///< A derived device that provides section data must call ///< this function to actually set up the section handler. public: virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask); ///< Opens a file handle for the given filter data. ///< A derived device that provides section data must ///< implement this function. void AttachFilter(cFilter *Filter); ///< Attaches the given filter to this device. void Detach(cFilter *Filter); ///< Detaches the given filter from this device. // Common Interface facilities: protected: cCiHandler *ciHandler; public: cCiHandler *CiHandler(void) { return ciHandler; } // Image Grab facilities public: virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); ///< Capture a single frame as an image. ///< Grabs the currently visible screen image into the given file, with the ///< given parameters. ///< \param FileName The name of the file to write. Should include the proper extension. ///< \param Jpeg If true will write a JPEG file. Otherwise a PNM file will be written. ///< \param Quality The compression factor for JPEG. 1 will create a very blocky ///< and small image, 70..80 will yield reasonable quality images while keeping the ///< image file size around 50 KB for a full frame. The default will create a big ///< but very high quality image. ///< \param SizeX The number of horizontal pixels in the frame (default is the current screen width). ///< \param SizeY The number of vertical pixels in the frame (default is the current screen height). ///< \return True if all went well. */ // Video format facilities public: virtual void SetVideoFormat(bool VideoFormat16_9); ///< Sets the output video format to either 16:9 or 4:3 (only useful ///< if this device has an MPEG decoder). virtual eVideoSystem GetVideoSystem(void); ///< Returns the video system of the currently displayed material ///< (default is PAL). // Track facilities private: tTrackId availableTracks[ttMaxTrackTypes]; eTrackType currentAudioTrack; protected: virtual void SetAudioTrackDevice(eTrackType Type); ///< Sets the current audio track to the given value. public: void ClrAvailableTracks(bool DescriptionsOnly = false); bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, const char *Description = NULL, uint32_t Flags = 0); ///< Sets the track of the given Type and Index to the given values. ///< Type must be one of the basic eTrackType values, like ttAudio or ttDolby. ///< Index tells which track of the given basic type is meant. ///< If Id is 0 any existing id (and flags) will be left untouched and only the ///< given Language and Description will be set. ///< \return Returns true if the track was set correctly, false otherwise. const tTrackId *GetTrack(eTrackType Type); ///< Returns a pointer to the given track id, or NULL if Type is not ///< less than ttMaxTrackTypes. int NumAudioTracks(void) const; ///< Returns the number of audio tracks that are currently available. ///< This is just for information, to quickly find out whether there ///< is more than one audio track. eTrackType GetCurrentAudioTrack(void) { return currentAudioTrack; } bool SetCurrentAudioTrack(eTrackType Type); ///< Sets the current audio track to the given Type. ///< \return Returns true if Type is a valid audio track, false otherwise. // Audio facilities private: bool mute; int volume; protected: virtual int GetAudioChannelDevice(void); ///< Gets the current audio channel, which is stereo (0), mono left (1) or ///< mono right (2). virtual void SetAudioChannelDevice(int AudioChannel); ///< Sets the audio channel to stereo (0), mono left (1) or mono right (2). virtual void SetVolumeDevice(int Volume); ///< Sets the audio volume on this device (Volume = 0...255). virtual void SetDigitalAudioDevice(bool On); ///< Tells the actual device that digital audio output shall be switched ///< on or off. public: bool IsMute(void) const { return mute; } bool ToggleMute(void); ///< Turns the volume off or on and returns the new mute state. int GetAudioChannel(void); ///< Gets the current audio channel, which is stereo (0), mono left (1) or ///< mono right (2). void SetAudioChannel(int AudioChannel); ///< Sets the audio channel to stereo (0), mono left (1) or mono right (2). ///< Any other values will be silently ignored. void SetVolume(int Volume, bool Absolute = false); ///< Sets the volume to the given value, either absolutely or relative to ///< the current volume. static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX??? // Player facilities private: cPlayer *player; cPesAssembler *pesAssembler; protected: virtual bool CanReplay(void) const; ///< Returns true if this device can currently start a replay session. virtual bool SetPlayMode(ePlayMode PlayMode); ///< Sets the device into the given play mode. ///< \return true if the operation was successful. virtual int PlayVideo(const uchar *Data, int Length); ///< Plays the given data block as video. ///< Data points to exactly one complete PES packet of the given Length. ///< PlayVideo() shall process the packet either as a whole (returning ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). ///< \return Returns the number of bytes actually taken from Data, or -1 ///< in case of an error. virtual int PlayAudio(const uchar *Data, int Length); ///< Plays the given data block as audio. ///< Data points to exactly one complete PES packet of the given Length. ///< PlayAudio() shall process the packet either as a whole (returning ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). ///< \return Returns the number of bytes actually taken from Data, or -1 ///< in case of an error. virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false); ///< Plays the single PES packet in Data with the given Length. ///< If VideoOnly is true, only the video will be displayed, ///< which is necessary for trick modes like 'fast forward'. ///< Data must point to one single, complete PES packet. public: virtual int64_t GetSTC(void); ///< Gets the current System Time Counter, which can be used to ///< synchronize audio and video. If this device is unable to ///< provide the STC, -1 will be returned. virtual void TrickSpeed(int Speed); ///< Sets the device into a mode where replay is done slower. ///< Every single frame shall then be displayed the given number of ///< times. virtual void Clear(void); ///< Clears all video and audio data from the device. ///< A derived class must call the base class function to make sure ///< all registered cAudio objects are notified. virtual void Play(void); ///< Sets the device into play mode (after a previous trick ///< mode). virtual void Freeze(void); ///< Puts the device into "freeze frame" mode. virtual void Mute(void); ///< Turns off audio while replaying. ///< A derived class must call the base class function to make sure ///< all registered cAudio objects are notified. virtual void StillPicture(const uchar *Data, int Length); ///< Displays the given I-frame as a still picture. virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); ///< Returns true if the device itself or any of the file handles in ///< Poller is ready for further action. ///< If TimeoutMs is not zero, the device will wait up to the given number ///< of milleseconds before returning in case there is no immediate ///< need for data. virtual bool Flush(int TimeoutMs = 0); ///< Returns true if the device's output buffers are empty, i. e. any ///< data which was bufferd so far has been processed. ///< If TimeoutMs is not zero, the device will wait up to the given ///< number of milliseconds before returning in case there is still ///< data in the buffers.. virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly = false); ///< Plays all valid PES packets in Data with the given Length. ///< If Data is NULL any leftover data from a previous call will be ///< discarded. If VideoOnly is true, only the video will be displayed, ///< which is necessary for trick modes like 'fast forward'. ///< Data should point to a sequence of complete PES packets. If the ///< last packet in Data is not complete, it will be copied and combined ///< to a complete packet with data from the next call to PlayPes(). ///< That way any functions called from within PlayPes() will be ///< guaranteed to always receive complete PES packets. bool Replaying(void) const; ///< Returns true if we are currently replaying. void StopReplay(void); ///< Stops the current replay session (if any). bool AttachPlayer(cPlayer *Player); ///< Attaches the given player to this device. void Detach(cPlayer *Player); ///< Detaches the given player from this device. // Receiver facilities private: cMutex mutexReceiver; cReceiver *receiver[MAXRECEIVERS]; int CanShift(int Ca, int Priority, int UsedCards = 0) const; protected: int Priority(void) const; ///< Returns the priority of the current receiving session (0..MAXPRIORITY), ///< or -1 if no receiver is currently active. The primary device will ///< always return at least Setup.PrimaryLimit-1. virtual bool OpenDvr(void); ///< Opens the DVR of this device and prepares it to deliver a Transport ///< Stream for use in a cReceiver. virtual void CloseDvr(void); ///< Shuts down the DVR. virtual bool GetTSPacket(uchar *&Data); ///< Gets exactly one TS packet from the DVR of this device and returns ///< a pointer to it in Data. Only the first 188 bytes (TS_SIZE) Data ///< points to are valid and may be accessed. If there is currently no ///< new data available, Data will be set to NULL. The function returns ///< false in case of a non recoverable error, otherwise it returns true, ///< even if Data is NULL. public: int Ca(void) const; ///< Returns the ca of the current receiving session(s). bool Receiving(bool CheckAny = false) const; ///< Returns true if we are currently receiving. bool AttachReceiver(cReceiver *Receiver); ///< Attaches the given receiver to this device. void Detach(cReceiver *Receiver); ///< Detaches the given receiver from this device. }; /// Derived cDevice classes that can receive channels will have to provide /// Transport Stream (TS) packets one at a time. cTSBuffer implements a /// simple buffer that allows the device to read a larger amount of data /// from the driver with each call to Read(), thus avoiding the overhead /// of getting each TS packet separately from the driver. It also makes /// sure the returned data points to a TS packet and automatically /// re-synchronizes after broken packets. class cTSBuffer : public cThread { private: int f; int cardIndex; bool active; bool delivered; cRingBufferLinear *ringBuffer; virtual void Action(void); public: cTSBuffer(int File, int Size, int CardIndex); ~cTSBuffer(); uchar *Get(void); }; #endif //__DEVICE_H