#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; } } };