diff options
Diffstat (limited to 'xineExternal.c')
-rw-r--r-- | xineExternal.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/xineExternal.c b/xineExternal.c new file mode 100644 index 0000000..b0ea701 --- /dev/null +++ b/xineExternal.c @@ -0,0 +1,258 @@ + +#include "xineCommon.h" + +#include "xineExternal.h" +#include "xineLib.h" + + + +namespace PluginXine +{ + + cXineExternal::cXineExternal() + : cThread() + , m_fdControl(-1) + , m_fdResult(-1) + , m_shutdown(false) + , m_connected(false) + , m_xineLib(0) + , m_enabled(false) + { + } + + cXineExternal::~cXineExternal() + { + StopExternal(); + } + + void cXineExternal::StartExternal() + { + cThread::Start(); + } + + void cXineExternal::StopExternal() + { + cMutexLock shutdownMutexLock(&m_shutdownMutex); + m_shutdown = true; + m_shutdownCondVar.Broadcast(); + + disconnect(); + } + + bool cXineExternal::readCommand() + { + int len = 0; + + while (!m_shutdown + && len < EXTERNAL_COMMAND_MAX_LEN) + { + cPoller poller(m_fdControl); + if (poller.Poll(100)) + { + void (* const sigPipeHandler)(int) = ::signal(SIGPIPE, SIG_IGN); + + int r = ::read(m_fdControl, &m_command[ len ], 1); + int myErrno = errno; + + ::signal(SIGPIPE, sigPipeHandler); + + if (r < 0) + { + if (EAGAIN == myErrno) + return false; + + if (m_connected) + { + errno = myErrno; + ::perror("vdr-xine: reading external command failed"); + } + } + + if (r <= 0) + { + disconnect(); + return false; + } + + if ('\n' == m_command[ len ]) + break; + + len += r; + } + } + + if (m_shutdown) + return false; + + if (len >= EXTERNAL_COMMAND_MAX_LEN + && m_command[ EXTERNAL_COMMAND_MAX_LEN - 1 ] != '\n') + { + ::fprintf(stderr, "vdr-xine: external command length exceeded!\n"); + disconnect(); + return false; + } + + m_command[ len ] = '\0'; + + return (len > 0); + } + + bool cXineExternal::writeResult(const char *result) + { + int l = ::strlen(result); + + while (l > 0) + { + void (* const sigPipeHandler)(int) = ::signal(SIGPIPE, SIG_IGN); + + int r = ::write(m_fdResult, &result, l); + int myErrno = errno; + + ::signal(SIGPIPE, sigPipeHandler); + + if (r < 0) + { + if (EAGAIN == myErrno) + continue; + + errno = myErrno; + ::perror("vdr-xine: writing external result failed"); + } + + if (r <= 0) + { + disconnect(); + return false; + } + + result += r; + l -= r; + } + + return true; + } + + void cXineExternal::cmdPlay(const char *const mrl) + { + if (m_xineLib) + { + m_xineLib->execFuncPlayExternal(mrl); + m_xineLib->execFuncWait(); + } + } + + void cXineExternal::enable(const bool enable) + { + cMutexLock lock(&m_enabledMutex); + + if (m_enabled && !enable) + cmdPlay(0); + + m_enabled = enable; + } + + void cXineExternal::externalStreamFinished() + { + ::fprintf(stderr, "vdr-xine: external stream finished\n"); + + cmdPlay(0); + + writeResult("play finished\n"); + } + + void cXineExternal::Action(void) + { + while (!m_shutdown) + { + if (!isConnected()) + { +// ::fprintf(stderr, "?"); + checkConnect(); + } + else + { +// ::fprintf(stderr, "!"); + + if (readCommand()) + { + cMutexLock lock(&m_enabledMutex); + + if (!m_enabled) + { + ::fprintf(stderr, "vdr-xine: external commands not allowed!\n"); + disconnect(); + } + else + { + if (0 == strncmp(m_command, "play ", 5)) + { + cmdPlay(m_command + 5); + } + else + { + ::fprintf(stderr, "vdr-xine: external command '%s' unknown!\n", m_command); + disconnect(); + } + } + } + } + + if (!m_shutdown) + { + cMutexLock shutdownMutexLock(&m_shutdownMutex); + if (!m_shutdown) + m_shutdownCondVar.TimedWait(m_shutdownMutex, 100); + } + } + } + + bool cXineExternal::isConnected() + { + return (-1 != m_fdControl); + } + + bool cXineExternal::checkConnect() + { + m_fdResult = ::open(m_xineLib->m_fifoNameExtResult.c_str() , O_WRONLY | O_NONBLOCK); + if (-1 == m_fdResult) + return false; + + ::fprintf(stderr, "vdr-xine: external connecting ...\n"); + + m_fdControl = ::open(m_xineLib->m_fifoNameExtControl.c_str(), O_RDONLY); + + ::fcntl(m_fdResult, F_SETFL, ~O_NONBLOCK & ::fcntl(m_fdResult, F_GETFL, 0)); + + if (isConnected()) + { + ::fprintf(stderr, "vdr-xine: external connected!\n"); + + m_connected = true; + return true; + } + + ::fprintf(stderr, "vdr-xine: external connect failed!\n"); + + return false; + } + + void cXineExternal::disconnect() + { + m_connected = false; + + cmdPlay(0); + + if (-1 != m_fdControl) + { + ::close(m_fdControl); + m_fdControl = -1; + } + + if (-1 != m_fdResult) + { + ::close(m_fdResult); + m_fdResult = -1; + } + } + +}; |