diff options
-rw-r--r-- | clientcontrol.c | 227 | ||||
-rw-r--r-- | clientcontrol.h | 77 | ||||
-rw-r--r-- | ffnetdev.c | 118 | ||||
-rw-r--r-- | ffnetdev.h | 2 | ||||
-rw-r--r-- | pes2ts.c | 9 | ||||
-rw-r--r-- | pes2ts.h | 5 | ||||
-rw-r--r-- | streamdevice.c | 55 | ||||
-rw-r--r-- | streamdevice.h | 61 | ||||
-rw-r--r-- | tsworker.c | 19 |
9 files changed, 470 insertions, 103 deletions
diff --git a/clientcontrol.c b/clientcontrol.c new file mode 100644 index 0000000..ca5fd05 --- /dev/null +++ b/clientcontrol.c @@ -0,0 +1,227 @@ +/* + * tsworker.c: ts streaming worker thread + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <sys/time.h> + +#include <vdr/tools.h> + +#include "tools/socket.h" +#include "tools/select.h" + +#include "clientcontrol.h" +#include "config.h" + + +////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// + +cClientControl *cClientControl::m_Instance = NULL; + +cClientControl::cClientControl(void) + : cThread("[ffnetdev] ClientControl") +{ + m_Active = false; + m_ClientSocket = NULL; +} + +cClientControl::~cClientControl() +{ + if (m_Active) + Stop(); + delete m_ClientSocket; +} + +void cClientControl::Init(int iPort, cPluginFFNetDev *pPlugin) +{ + if (m_Instance == NULL) + { + m_Instance = new cClientControl; + m_Instance->m_pPlugin = pPlugin; + m_Instance->m_iPort = iPort; + m_Instance->Start(); + m_Instance->m_bCloseClientRequest = false; + m_Instance->m_bPlayStateReq = false; + } +} + +void cClientControl::Exit(void) +{ + if (m_Instance != NULL) + { + m_Instance->Stop(); + DELETENULL(m_Instance); + } +} + +void cClientControl::Stop(void) +{ + m_Active = false; + Cancel(3); +} + +void cClientControl::CloseStreamClient(void) +{ + m_Instance->m_bCloseClientRequest = true; +#ifdef DEBUG + fprintf(stderr, "[ffnetdev] Streamer: Closing of ClientControl client socket requested.\r\n"); +#endif +} + +void cClientControl::Action(void) +{ + cTBSelect select; + cTBSocket m_StreamListen; + int ret; + + const char* m_ListenIp = "0.0.0.0"; + uint iPort = m_iPort; + + m_ClientSocket = new cTBSocket; + + m_Active = true; + m_bHaveClient = false; + + if (!m_StreamListen.Listen(m_ListenIp, iPort, 1)) { // ToDo JN place to allow more connections/clients! + esyslog("[ffnetdev] ClientControl: Couldn't listen %s:%d: %s", m_ListenIp, iPort, strerror(errno)); + m_Active = false; + } + else + isyslog("[ffnetdev] ClientControl: Listening on port %d", iPort); + + while (m_Active) { + select.Clear(); + + if (m_bHaveClient==false) + select.Add(m_StreamListen, false); + else { + select.Add(*m_ClientSocket, true); //select for writing fd + select.Add(*m_ClientSocket, false); //select for reading fd + } + + int numfd; + /* React on status change of any of the above file descriptor */ + if ((numfd=select.Select(1000)) < 0) { + if (!m_Active) // Exit was requested while polling + continue; + esyslog("[ffnetdev] ClientControl: Fatal error, ffnetdev exiting: %s", strerror(errno)); + m_Active = false; + continue; + } + + + /* Accept connecting */ + if ( (m_bHaveClient==false)&&select.CanRead(m_StreamListen) ) { + if (m_ClientSocket->Accept(m_StreamListen)) { + isyslog("[ffnetdev] ClientControl: Accepted client %s:%d", + m_ClientSocket->RemoteIp().c_str(), m_ClientSocket->RemotePort()); + m_bHaveClient = true; + } + else { + esyslog("[ffnetdev] Streamer: Couldn't accept : %s", strerror(errno)); + m_bHaveClient = false; + m_Active = false; + continue; + } + } + + + /* Check for closed client connection */ + if (m_bHaveClient==true) { + if (m_bCloseClientRequest==true) { + m_bCloseClientRequest = false; + m_bHaveClient = false; + + if ( m_ClientSocket->Close() ) { +#ifdef DEBUG + fprintf(stderr, "[ffnetdev] ClientControl: Client socket closed successfully.\n"); +#endif + isyslog("[ffnetdev] ClientControl: Connection closed: client %s:%d", + m_ClientSocket->RemoteIp().c_str(), m_ClientSocket->RemotePort()); + } + else + { +#ifdef DEBUG + fprintf(stderr, "[ffnetdev] ClientControl: Error closing client socket.\n"); +#endif + esyslog("[ffnetdev] ClientControl: Error closing connection."); + m_Active=false; + continue; + } + + } + + if ( select.CanWrite(*m_ClientSocket) ) + { + + } + + if ( select.CanRead(*m_ClientSocket) ) + { + SClientControl data; + SClientControlInfo info; + + if ( (ret = m_ClientSocket->Read(&data, sizeof(data))) == sizeof(data)) + { + switch (data.pakType) + { + case ptInfo: + if (m_ClientSocket->Read(&info, data.dataLen) == data.dataLen) + m_pPlugin->SetClientName(info.clientName); + dsyslog("clientName %s, data.dataLen %d %d", info.clientName, data.dataLen, sizeof(data)); + break; + + case ptPlayStateReq: + m_bPlayStateReq = true; + break; + + default: + break; + } + } + else if (ret == 0) + { + CloseStreamClient(); + } + } + } + + cCondWait::SleepMs(3); + + } // while(m_Active) + +} + + +bool cClientControl::SendPlayState(ePlayMode PlayMode, bool bPlay, bool bForward, int iSpeed) +{ + SClientControl data; + SClientControlPlayState state; + + int ret; + + if ((m_Instance == NULL) || (m_Instance->m_ClientSocket == NULL)) + return false; + + m_Instance->m_bPlayStateReq = false; + + state.PlayMode = PlayMode; + state.Play = bPlay; + state.Forward = bForward; + state.Speed = iSpeed; + + data.pakType = ptPlayState; + data.dataLen = sizeof(state); + if ((ret = m_Instance->m_ClientSocket->Write(&data, sizeof(data))) == sizeof(data)) + { + if ((ret = m_Instance->m_ClientSocket->Write(&state, sizeof(state))) == sizeof(state)) + return true; + else + return false; + } + else + return false; +} diff --git a/clientcontrol.h b/clientcontrol.h new file mode 100644 index 0000000..38c16dc --- /dev/null +++ b/clientcontrol.h @@ -0,0 +1,77 @@ +/* + * clientcontrol.h: ClientControl thread + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _CLIENTCONTROL__H +#define _CLIENTCONTROL__H + +#include <vdr/thread.h> + +#include "tools/socket.h" +#include "ffnetdev.h" + +enum CCPakType{ ptInfo=0, ptPlayState, ptPlayStateReq }; + +struct SClientControl +{ + char pakType; + char dataLen; + char data[0]; +}; + +struct SClientControlInfo +{ + char clientName[20]; +}; + +struct SClientControlPlayState +{ + char PlayMode; + bool Play; + bool Forward; + char Speed; +}; + + +// --- cClientControl ------------------------------------------------------------- + +class cClientControl : public cThread { +private: + bool m_Active; + bool m_bHaveClient; + bool m_bCloseClientRequest; + static cClientControl *m_Instance; + cTBSocket *m_ClientSocket; + int m_iPort; + cPluginFFNetDev *m_pPlugin; + bool m_bPlayStateReq; + +protected: + virtual void Action(void); + void Stop(void); +public: + cClientControl(void); + virtual ~cClientControl(); + + static void Init(int, cPluginFFNetDev*); + static void Exit(void); + static bool Active(void); + + static bool HaveClient(void); + static void CloseStreamClient(void); + + static bool SendPlayState(ePlayMode PlayMode, bool bPlay, bool bForward, int iSpeed); + static bool PlayStateReq(void) { return m_Instance->m_bPlayStateReq; }; +}; + +inline bool cClientControl::Active(void) { + return m_Instance && (m_Instance->m_bHaveClient==true); +} + +inline bool cClientControl::HaveClient(void) { + return m_Instance->m_bHaveClient; +} +#endif @@ -211,60 +211,82 @@ bool cPluginFFNetDev::SetupParse(const char *Name, const char *Value) void cPluginFFNetDev::SetPrimaryDevice() { - int i = 0; - while ((cOsd::IsOpen() > 0) && (i-- > 0)) - cRemote::Put(kBack); - - if ((config.iAutoSetPrimaryDVB == 1) && (m_origPrimaryDevice == -1)) - { - cDevice *PrimaryDevice; - if ((PrimaryDevice = cDevice::PrimaryDevice()) != NULL) - m_origPrimaryDevice = PrimaryDevice->DeviceNumber() + 1; - else - m_origPrimaryDevice = -1; - - if (m_StreamDevice->DeviceNumber() + 1 != m_origPrimaryDevice) - { - cDevice::SetPrimaryDevice(m_StreamDevice->DeviceNumber() + 1); - isyslog("[ffnetdev] set Primary Device to %d", m_StreamDevice->DeviceNumber() + 1); - } - else - { - m_origPrimaryDevice = -1; - } - } - - if(EnableRemote) - { - if (m_Remote == NULL) - m_Remote = new cMyRemote("ffnetdev"); - - if (!cRemote::HasKeys()) - new cLearningThread(); - dsyslog("[ffnetdev] remote control enabled.\n"); - } - else - { - dsyslog("[ffnetdev] remote control disabled.\n"); - } + int i = 0; + while ((cOsd::IsOpen() > 0) && (i-- > 0)) + cRemote::Put(kBack); + + if ((config.iAutoSetPrimaryDVB == 1) && (m_origPrimaryDevice == -1)) + { + cDevice *PrimaryDevice; + if ((PrimaryDevice = cDevice::PrimaryDevice()) != NULL) + m_origPrimaryDevice = PrimaryDevice->DeviceNumber() + 1; + else + m_origPrimaryDevice = -1; + + if (m_StreamDevice->DeviceNumber() + 1 != m_origPrimaryDevice) + { + cDevice::SetPrimaryDevice(m_StreamDevice->DeviceNumber() + 1); + isyslog("[ffnetdev] set Primary Device to %d", m_StreamDevice->DeviceNumber() + 1); + } + else + { + m_origPrimaryDevice = -1; + } + } + + if(EnableRemote) + { + if (m_Remote == NULL) + { + char str[30]; + if (strlen(m_ClientName) > 0) + sprintf(str, "ffnetdev-%s", m_ClientName); + else + strcpy(str, "ffnetdev"); + + m_Remote = new cMyRemote(str); + } + + if (!cRemote::HasKeys()) + new cLearningThread(); + dsyslog("[ffnetdev] remote control enabled.\n"); + } + else + { + dsyslog("[ffnetdev] remote control disabled.\n"); + } } void cPluginFFNetDev::RestorePrimaryDevice() { - int i = 10; - while ((cOsd::IsOpen() > 0) && (i-- > 0)) - cRemote::Put(kBack); + int i = 10; + while ((cOsd::IsOpen() > 0) && (i-- > 0)) + cRemote::Put(kBack); + + dsyslog("[ffnetdev] remote control disabled.\n"); + + if (m_origPrimaryDevice != -1) + { + cDevice::SetPrimaryDevice(m_origPrimaryDevice); + isyslog("[ffnetdev] restore Primary Device to %d", m_origPrimaryDevice); + m_origPrimaryDevice = -1; + sleep(5); + } + + m_ClientName[0] = '\0'; + if (m_Remote) + { + Remotes.Del(m_Remote); + m_Remote = NULL; + } + dsyslog("[ffnetdev] -------------------\n"); +} - dsyslog("[ffnetdev] remote control disabled.\n"); - - if (m_origPrimaryDevice != -1) - { - cDevice::SetPrimaryDevice(m_origPrimaryDevice); - isyslog("[ffnetdev] restore Primary Device to %d", m_origPrimaryDevice); - m_origPrimaryDevice = -1; - sleep(5); - } +void cPluginFFNetDev::SetClientName(char* ClientName) +{ + strcpy(m_ClientName, ClientName); + dsyslog("[ffnetdev] SetClientname %s", m_ClientName); } @@ -27,6 +27,7 @@ private: int ControlPort; bool EnableRemote; int m_origPrimaryDevice; + char m_ClientName[20]; public: cPluginFFNetDev(void); @@ -57,6 +58,7 @@ public: void SetPrimaryDevice(); void RestorePrimaryDevice(); cMyRemote *GetRemote() { return m_Remote; } + void SetClientName(char* ClientName); }; #endif @@ -39,8 +39,7 @@ int cPESRemux::Put(const uchar *Data, int Count) cPES2TSRemux::cPES2TSRemux(int VPid, int APid): cPESRemux(INPUTBUFSIZE, IPACKS), cThread("[ffnetdev] PES2TS remux"), m_OutputBuffer(new cRingBufferLinear(OUTPUTBUFSIZE, TS_SIZE * 2)), - m_Active(false), - m_PlayModeChanged(false) + m_Active(false) { vpid = VPid; apid = APid; @@ -73,12 +72,6 @@ void cPES2TSRemux::Action(void) // fprintf(stderr, "[ffnetdev] Remuxer: Inputbuffersize: %d, Outputbuffersize: %d\n", // m_InputBuffer->Available(), m_OutputBuffer->Available()); - if (m_PlayModeChanged) - { - cCondWait::SleepMs(1500); - m_PlayModeChanged = false; - } - if (m_InputBuffer->Available() < (int)IPACKS*10) { cCondWait::SleepMs(5); continue; @@ -40,8 +40,6 @@ public: virtual void ClearOutput() = 0; void LockOutput() { while (OutputLocked) cCondWait::SleepMs(1); OutputLocked = true; } void UnlockOutput() { OutputLocked = false; } - virtual void PlayModeChange() {}; - }; class cPES2TSRemux: public cPESRemux, cThread { @@ -50,7 +48,6 @@ private: bool m_Active; unsigned short vpid; unsigned short apid; - bool m_PlayModeChanged; protected: virtual void Action(void); @@ -65,8 +62,6 @@ public: uchar *Get(int &Count) { return m_OutputBuffer->Get(Count); } void DelOutput(int Count) { m_OutputBuffer->Del(Count); } void ClearOutput() { LockOutput(); m_OutputBuffer->Clear(); UnlockOutput(); } - void PlayModeChange() { m_PlayModeChanged = true; } - }; class cPES2PESRemux: public cPESRemux { diff --git a/streamdevice.c b/streamdevice.c index c5e0bb8..283229c 100644 --- a/streamdevice.c +++ b/streamdevice.c @@ -5,11 +5,12 @@ * */ +#include "vdr/player.h" #include "streamdevice.h" #include "osdworker.h" #include "tsworker.h" #include "netosd.h" -#include "vdr/player.h" +#include "clientcontrol.h" cStreamDevice::cStreamDevice(void) { @@ -17,6 +18,8 @@ cStreamDevice::cStreamDevice(void) //m_Remux = new cPES2TSRemux(TS_VPID, TS_APID); m_Remux = new cPES2PESRemux(); m_Playing = false; + m_PlayState = psPlay; + m_PlayMode = pmNone; } cStreamDevice::~cStreamDevice(void) @@ -51,42 +54,70 @@ bool cStreamDevice::SetPlayMode(ePlayMode PlayMode) { dsyslog("[ffnetdev] Device: Setting playmode. Mode: %d\n",PlayMode); cOSDWorker::SendPlayMode(PlayMode); - m_Remux->ClearInput(); - m_Remux->ClearOutput(); - m_Remux->PlayModeChange(); + + m_PlayMode = PlayMode; + if (PlayMode == pmNone) + { + m_PlayState = psBufferReset; + m_Remux->ClearInput(); + m_Remux->ClearOutput(); + } + else + { + while (((m_PlayState == psBufferReset) || (m_PlayState == psBufferReseted)) && + (!cClientControl::PlayStateReq()) && (cTSWorker::HaveStreamClient())) + cCondWait::SleepMs(10); + dsyslog("[ffnetdev] PlayStateReq\n"); + m_PlayState = psPlay; + } + cControl *pControl = cControl::Control(); if (pControl) { bool Forward; int Speed; pControl->GetReplayMode(m_Playing, Forward, Speed); + cClientControl::SendPlayState(PlayMode, m_Playing, Forward, Speed); } else { m_Playing = false; + cClientControl::SendPlayState(PlayMode, false, false, 0); } return true; } void cStreamDevice::TrickSpeed(int Speed) { - dsyslog("[ffnetdev] Device: Trickspeed(not implemented). Speed: %d\n", Speed); - m_Remux->ClearInput(); - m_Remux->ClearOutput(); - m_Remux->PlayModeChange(); + dsyslog("[ffnetdev] Device: Trickspeed. Speed: %d\n", Speed); + cControl *pControl = cControl::Control(); + if (pControl) + { + bool Forward; + int Speed; + pControl->GetReplayMode(m_Playing, Forward, Speed); + cClientControl::SendPlayState(m_PlayMode, m_Playing, Forward, Speed); + } } void cStreamDevice::Clear(void) { dsyslog("[ffnetdev] Device: Clear(not implemented).\n"); - m_Remux->ClearInput(); - m_Remux->ClearOutput(); - m_Remux->PlayModeChange(); // cDevice::Clear(); } void cStreamDevice::Play(void) { - dsyslog("[ffnetdev] Device: Play(not implemented).\n"); + dsyslog("[ffnetdev] Device: Play.\n"); + + cControl *pControl = cControl::Control(); + if (pControl) + { + bool Forward; + int Speed; + pControl->GetReplayMode(m_Playing, Forward, Speed); + cClientControl::SendPlayState(m_PlayMode, m_Playing, Forward, Speed); + } + // cDevice::Play(); } diff --git a/streamdevice.h b/streamdevice.h index 8f8603b..412aafb 100644 --- a/streamdevice.h +++ b/streamdevice.h @@ -15,40 +15,47 @@ #include "pes2ts.h" +enum ePlayState {psBufferReset,psBufferReseted,psPlay}; + class cStreamDevice: public cDevice { private: - cPESRemux *m_Remux; - bool m_Playing; + cPESRemux *m_Remux; + bool m_Playing; + ePlayState m_PlayState; + ePlayMode m_PlayMode; + protected: public: - cStreamDevice(void); - ~cStreamDevice(void); - virtual bool HasDecoder(void) const; - virtual bool CanReplay(void) const; - virtual bool SetPlayMode(ePlayMode PlayMode); - virtual void TrickSpeed(int Speed); - virtual void Clear(void); - virtual void Play(void); - virtual void Freeze(void); - virtual void Mute(void); - virtual void SetVolumeDevice (int Volume); - virtual void StillPicture(const uchar *Data, int Length); - virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); - virtual int PlayVideo(const uchar *Data, int Length); + cStreamDevice(void); + ~cStreamDevice(void); + virtual bool HasDecoder(void) const; + virtual bool CanReplay(void) const; + virtual bool SetPlayMode(ePlayMode PlayMode); + virtual void TrickSpeed(int Speed); + virtual void Clear(void); + virtual void Play(void); + virtual void Freeze(void); + virtual void Mute(void); + virtual void SetVolumeDevice (int Volume); + virtual void StillPicture(const uchar *Data, int Length); + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); + virtual int PlayVideo(const uchar *Data, int Length); #if VDRVERSNUM < 10342 - virtual int PlayAudio(const uchar *Data, int Length); + virtual int PlayAudio(const uchar *Data, int Length); #else - virtual int PlayAudio(const uchar *Data, int Length, uchar Id); + virtual int PlayAudio(const uchar *Data, int Length, uchar Id); #endif - virtual int ProvidesCa(const cChannel *Channel) const; - virtual void MakePrimaryDevice(bool On); - uchar *Get(int &Count) { return m_Remux->Get(Count); } - void LockOutput() { m_Remux->LockOutput(); } - void UnlockOutput() { m_Remux->UnlockOutput(); } - void Del(int Count) { m_Remux->DelOutput(Count); } - void ClearOutput() { m_Remux->ClearOutput(); } - int Available(void) { return m_Remux->Available(); } - int Free(void) { return m_Remux->Free(); } + virtual int ProvidesCa(const cChannel *Channel) const; + virtual void MakePrimaryDevice(bool On); + uchar *Get(int &Count) { return m_Remux->Get(Count); } + void LockOutput() { m_Remux->LockOutput(); } + void UnlockOutput() { m_Remux->UnlockOutput(); } + void Del(int Count) { m_Remux->DelOutput(Count); } + void ClearOutput() { m_Remux->ClearOutput(); } + int Available(void) { return m_Remux->Available(); } + int Free(void) { return m_Remux->Free(); } + void SetPlayState(ePlayState PlayState) { m_PlayState = PlayState;} + ePlayState GetPlayState(void) { return m_PlayState; } }; #endif @@ -172,18 +172,30 @@ void cTSWorker::ActionTCP(void) { m_StreamClient->RemoteIp().c_str(), m_StreamClient->RemotePort()); } else - { + { #ifdef DEBUG fprintf(stderr, "[ffnetdev] Streamer: Error closing client socket.\n"); #endif esyslog("[ffnetdev] Streamer: Error closing connection."); m_Active=false; continue; - } - + } } if ( select.CanWrite(*m_StreamClient) ) { + + if (m_StreamDevice->GetPlayState() == psBufferReset) + { + cCondWait::SleepMs(10); + m_StreamDevice->SetPlayState(psBufferReseted); + } + + if (m_StreamDevice->GetPlayState() == psBufferReseted) + { + cCondWait::SleepMs(10); + continue; + } + int count=0; m_StreamDevice->LockOutput(); @@ -329,6 +341,7 @@ void cTSWorker::ActionUDP(void) } + int count=0; m_StreamDevice->LockOutput(); |