diff --git a/addons/Makefile.am b/addons/Makefile.am index 18c8fa017..edf44af7f 100644 --- a/addons/Makefile.am +++ b/addons/Makefile.am @@ -1,5 +1,4 @@ -SUBDIRS = pvr.hts \ - pvr.vdr.vnsi +SUBDIRS = pvr.hts clean: -rm -f *.zip diff --git a/addons/pvr.hts/src/HTSPData.cpp b/addons/pvr.hts/src/HTSPData.cpp index 6c8341a3d..2e7a9da9e 100644 --- a/addons/pvr.hts/src/HTSPData.cpp +++ b/addons/pvr.hts/src/HTSPData.cpp @@ -203,29 +203,140 @@ unsigned int CHTSPData::GetNumChannels() return GetChannels().size(); } +void CHTSPData::TransferChannel(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SChannel &channel) +{ + PVR_CHANNEL tag; + memset(&tag, 0 , sizeof(PVR_CHANNEL)); + + tag.iUniqueId = channel.id; + tag.bIsRadio = channel.radio; + tag.iChannelNumber = channel.num; + tag.strChannelName = channel.name.c_str(); + tag.strInputFormat = ""; // unused + tag.strStreamURL = ""; // unused + tag.iEncryptionSystem = channel.caid; + tag.strIconPath = channel.icon.c_str(); + tag.bIsHidden = false; + + PVR->TransferChannelEntry(handle, updateType, &tag); +} + +void CHTSPData::TransferChannelGroup(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const STag &channelGroup) +{ + PVR_CHANNEL_GROUP tag; + memset(&tag, 0 , sizeof(PVR_CHANNEL_GROUP)); + + tag.bIsRadio = false; + tag.strGroupName = channelGroup.name.c_str(); + + PVR->TransferChannelGroup(handle, updateType, &tag); +} + +void CHTSPData::TransferTimer(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SRecording &recording) +{ + PVR_TIMER tag; + memset(&tag, 0, sizeof(PVR_TIMER)); + + tag.iClientIndex = recording.id; + tag.iClientChannelUid = recording.channel; + tag.startTime = recording.start; + tag.endTime = recording.stop; + tag.strTitle = recording.title.c_str(); + tag.strDirectory = "/"; // unused + tag.strSummary = recording.description.c_str(); + tag.state = (PVR_TIMER_STATE) recording.state; + tag.iPriority = 0; // unused + tag.iLifetime = 0; // unused + tag.bIsRepeating = false; // unused + tag.firstDay = 0; // unused + tag.iWeekdays = 0; // unused + tag.iEpgUid = 0; // unused + tag.iMarginStart = 0; // unused + tag.iMarginEnd = 0; // unused + tag.iGenreType = 0; // unused + tag.iGenreSubType = 0; // unused + + PVR->TransferTimerEntry(handle, updateType, &tag); +} + +void CHTSPData::TransferRecording(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SRecording &recording) +{ + PVR_RECORDING tag; + memset(&tag, 0, sizeof(PVR_RECORDING)); + + CStdString strStreamURL = "http://"; + CStdString strRecordingId; + CStdString strChannelName = ""; + + /* lock */ + if (g_strUsername != "") + { + strStreamURL += g_strUsername; + if (g_strPassword != "") + { + strStreamURL += ":"; + strStreamURL += g_strPassword; + } + strStreamURL += "@"; + } + strStreamURL.Format("%s%s:%i/dvrfile/%i", strStreamURL.c_str(), g_strHostname.c_str(), g_iPortHTTP, recording.id); + + strRecordingId.Format("%i", recording.id); + + tag.strRecordingId = strRecordingId.c_str(); + tag.strTitle = recording.title.c_str(); + tag.strStreamURL = strStreamURL.c_str(); + tag.strDirectory = "/"; + tag.strPlotOutline = ""; + tag.strPlot = recording.description.c_str(); + tag.strChannelName = strChannelName.c_str(); + tag.recordingTime = recording.start; + tag.iDuration = recording.stop - recording.start; + tag.iPriority = 0; + tag.iLifetime = 0; + tag.iGenreType = 0; + tag.iGenreSubType = 0; + + PVR->TransferRecordingEntry(handle, updateType, &tag); +} + +void CHTSPData::TransferEvent(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SEvent &event) +{ + EPG_TAG broadcast; + memset(&broadcast, 0, sizeof(EPG_TAG)); + + broadcast.iUniqueBroadcastId = event.id; + broadcast.strTitle = event.title.c_str(); + broadcast.iChannelUniqueId = event.chan_id; + broadcast.startTime = event.start; + broadcast.endTime = event.stop; + broadcast.strPlotOutline = ""; // unused + broadcast.strPlot = event.descs.c_str(); + broadcast.strIconPath = ""; // unused + broadcast.iGenreType = (event.content & 0x0F) << 4; + broadcast.iGenreSubType = event.content & 0xF0; + broadcast.strGenreDescription = ""; + broadcast.firstAired = 0; // unused + broadcast.iParentalRating = 0; // unused + broadcast.iStarRating = 0; // unused + broadcast.bNotify = false; + broadcast.iSeriesNumber = 0; // unused + broadcast.iEpisodeNumber = 0; // unused + broadcast.iEpisodePartNumber = 0; // unused + broadcast.strEpisodeName = ""; // unused + + PVR->TransferEpgEntry(handle, PVR_UPDATE_RESPONSE, &broadcast); +} + PVR_ERROR CHTSPData::GetChannels(ADDON_HANDLE handle, bool bRadio) { SChannels channels = GetChannels(); for(SChannels::iterator it = channels.begin(); it != channels.end(); ++it) { - SChannel& channel = it->second; - if(bRadio != channel.radio) + if(bRadio != it->second.radio) continue; - PVR_CHANNEL tag; - memset(&tag, 0 , sizeof(PVR_CHANNEL)); - - tag.iUniqueId = channel.id; - tag.bIsRadio = channel.radio; - tag.iChannelNumber = channel.num; - tag.strChannelName = channel.name.c_str(); - tag.strInputFormat = ""; // unused - tag.strStreamURL = ""; // unused - tag.iEncryptionSystem = channel.caid; - tag.strIconPath = channel.icon.c_str(); - tag.bIsHidden = false; - - PVR->TransferChannelEntry(handle, &tag); + TransferChannel(handle, PVR_UPDATE_RESPONSE, it->second); } return PVR_ERROR_NO_ERROR; @@ -250,30 +361,10 @@ PVR_ERROR CHTSPData::GetEpg(ADDON_HANDLE handle, const PVR_CHANNEL &channel, tim PVR_ERROR result = GetEvent(ev, ev.id); if (result == PVR_ERROR_NO_ERROR) { - EPG_TAG broadcast; - memset(&broadcast, 0, sizeof(EPG_TAG)); - - broadcast.iUniqueBroadcastId = ev.id; - broadcast.strTitle = ev.title.c_str(); - broadcast.iChannelNumber = ev.chan_id >= 0 ? ev.chan_id : channel.iUniqueId; - broadcast.startTime = ev.start; - broadcast.endTime = ev.stop; - broadcast.strPlotOutline = ""; // unused - broadcast.strPlot = ev.descs.c_str(); - broadcast.strIconPath = ""; // unused - broadcast.iGenreType = (ev.content & 0x0F) << 4; - broadcast.iGenreSubType = ev.content & 0xF0; - broadcast.strGenreDescription = ""; - broadcast.firstAired = 0; // unused - broadcast.iParentalRating = 0; // unused - broadcast.iStarRating = 0; // unused - broadcast.bNotify = false; - broadcast.iSeriesNumber = 0; // unused - broadcast.iEpisodeNumber = 0; // unused - broadcast.iEpisodePartNumber = 0; // unused - broadcast.strEpisodeName = ""; // unused - - PVR->TransferEpgEntry(handle, &broadcast); + if (ev.chan_id < 0) + ev.chan_id = channel.iUniqueId; + + TransferEvent(handle, PVR_UPDATE_RESPONSE, ev); ev.id = ev.next; stop = ev.stop; @@ -368,7 +459,7 @@ PVR_ERROR CHTSPData::GetRecordings(ADDON_HANDLE handle) tag.iGenreType = 0; tag.iGenreSubType = 0; - PVR->TransferRecordingEntry(handle, &tag); + PVR->TransferRecordingEntry(handle, PVR_UPDATE_RESPONSE, &tag); } return PVR_ERROR_NO_ERROR; @@ -421,7 +512,7 @@ PVR_ERROR CHTSPData::GetChannelGroups(ADDON_HANDLE handle) tag.bIsRadio = false; tag.strGroupName = m_tags[iTagPtr].name.c_str(); - PVR->TransferChannelGroup(handle, &tag); + PVR->TransferChannelGroup(handle, PVR_UPDATE_RESPONSE, &tag); } return PVR_ERROR_NO_ERROR; @@ -454,7 +545,7 @@ PVR_ERROR CHTSPData::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANN XBMC->Log(LOG_DEBUG, "%s - add channel %s (%d) to group '%s' channel number %d", __FUNCTION__, channel.name.c_str(), tag.iChannelUniqueId, group.strGroupName, channel.num); - PVR->TransferChannelGroupMember(handle, &tag); + PVR->TransferChannelGroupMember(handle, PVR_UPDATE_RESPONSE, &tag); } } @@ -466,33 +557,7 @@ PVR_ERROR CHTSPData::GetTimers(ADDON_HANDLE handle) SRecordings recordings = GetDVREntries(false, true); for(SRecordings::const_iterator it = recordings.begin(); it != recordings.end(); ++it) - { - SRecording recording = it->second; - - PVR_TIMER tag; - memset(&tag, 0, sizeof(PVR_TIMER)); - - tag.iClientIndex = recording.id; - tag.iClientChannelUid = recording.channel; - tag.startTime = recording.start; - tag.endTime = recording.stop; - tag.strTitle = recording.title.c_str(); - tag.strDirectory = "/"; // unused - tag.strSummary = recording.description.c_str(); - tag.state = (PVR_TIMER_STATE) recording.state; - tag.iPriority = 0; // unused - tag.iLifetime = 0; // unused - tag.bIsRepeating = false; // unused - tag.firstDay = 0; // unused - tag.iWeekdays = 0; // unused - tag.iEpgUid = 0; // unused - tag.iMarginStart = 0; // unused - tag.iMarginEnd = 0; // unused - tag.iGenreType = 0; // unused - tag.iGenreSubType = 0; // unused - - PVR->TransferTimerEntry(handle, &tag); - } + TransferTimer(handle, PVR_UPDATE_RESPONSE, it->second); return PVR_ERROR_NO_ERROR; } @@ -830,9 +895,13 @@ void CHTSPData::ParseChannelRemove(htsmsg_t* msg) } XBMC->Log(LOG_DEBUG, "%s - id:%u", __FUNCTION__, id); - m_channels.erase(id); + SChannels::iterator it = m_channels.find(id); + if (it != m_channels.end()) + { + TransferChannel(NULL, PVR_UPDATE_DELETE, it->second); - PVR->TriggerChannelUpdate(); + m_channels.erase(it); + } } void CHTSPData::ParseChannelUpdate(htsmsg_t* msg) @@ -915,7 +984,7 @@ void CHTSPData::ParseChannelUpdate(htsmsg_t* msg) __FUNCTION__, iChannelId, strName ? strName : "(null)", strIconPath ? strIconPath : "(null)", iEventId); if (bChanged) - PVR->TriggerChannelUpdate(); + TransferChannel(NULL, PVR_UPDATE_DELETE, channel); } void CHTSPData::ParseDVREntryDelete(htsmsg_t* msg) @@ -931,10 +1000,14 @@ void CHTSPData::ParseDVREntryDelete(htsmsg_t* msg) XBMC->Log(LOG_DEBUG, "%s - Recording %i was deleted", __FUNCTION__, id); - m_recordings.erase(id); + SRecordings::iterator it = m_recordings.find(id); + if (it != m_recordings.end()) + { + TransferTimer(NULL, PVR_UPDATE_DELETE, it->second); + TransferRecording(NULL, PVR_UPDATE_DELETE, it->second); - PVR->TriggerTimerUpdate(); - PVR->TriggerRecordingUpdate(); + m_recordings.erase(id); + } } void CHTSPData::ParseDVREntryUpdate(htsmsg_t* msg) @@ -992,10 +1065,10 @@ void CHTSPData::ParseDVREntryUpdate(htsmsg_t* msg) m_recordings[recording.id] = recording; - PVR->TriggerTimerUpdate(); + TransferTimer(NULL, PVR_UPDATE_REPLACE, recording); if (recording.state == ST_RECORDING) - PVR->TriggerRecordingUpdate(); + TransferRecording(NULL, PVR_UPDATE_REPLACE, recording); } bool CHTSPData::ParseEvent(htsmsg_t* msg, uint32_t id, SEvent &event) @@ -1071,9 +1144,13 @@ void CHTSPData::ParseTagRemove(htsmsg_t* msg) } XBMC->Log(LOG_DEBUG, "%s - id:%u", __FUNCTION__, id); - m_tags.erase(id); + STags::iterator it = m_tags.find(id); + if (it != m_tags.end()) + { + TransferChannelGroup(NULL, PVR_UPDATE_DELETE, it->second); - PVR->TriggerChannelGroupsUpdate(); + m_tags.erase(id); + } } void CHTSPData::ParseTagUpdate(htsmsg_t* msg) @@ -1113,5 +1190,5 @@ void CHTSPData::ParseTagUpdate(htsmsg_t* msg) XBMC->Log(LOG_DEBUG, "%s - id:%u, name:'%s', icon:'%s'" , __FUNCTION__, id, name ? name : "(null)", icon ? icon : "(null)"); - PVR->TriggerChannelGroupsUpdate(); + TransferChannelGroup(NULL, PVR_UPDATE_REPLACE, tag); } diff --git a/addons/pvr.hts/src/HTSPData.h b/addons/pvr.hts/src/HTSPData.h index 8847116cb..22aeba0b6 100644 --- a/addons/pvr.hts/src/HTSPData.h +++ b/addons/pvr.hts/src/HTSPData.h @@ -90,6 +90,12 @@ class CHTSPData : public PLATFORM::CThread }; typedef std::map SMessages; + void TransferChannel(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SChannel &channel); + void TransferChannelGroup(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const STag &channelGroup); + void TransferTimer(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SRecording &timer); + void TransferRecording(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SRecording &recording); + void TransferEvent(ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const SEvent &event); + SChannels GetChannels(); SChannels GetChannels(int tag); SChannels GetChannels(STag &tag); diff --git a/addons/pvr.hts/src/client.cpp b/addons/pvr.hts/src/client.cpp index 1ef5d0af1..4dfeb9e39 100644 --- a/addons/pvr.hts/src/client.cpp +++ b/addons/pvr.hts/src/client.cpp @@ -291,6 +291,9 @@ PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities) pCapabilities->bSupportsChannelScan = false; pCapabilities->bHandlesInputStream = true; pCapabilities->bHandlesDemuxing = true; + pCapabilities->bSupportsLastPlayedPosition = false; + pCapabilities->bSupportsRecordingFolders = false; + pCapabilities->bSupportsRecordingPlayCount = false; return PVR_ERROR_NO_ERROR; } @@ -548,4 +551,7 @@ long long SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */) { re long long PositionLiveStream(void) { return -1; } long long LengthLiveStream(void) { return -1; } const char * GetLiveStreamURL(const PVR_CHANNEL &channel) { return ""; } +PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; } +PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition) { return PVR_ERROR_NOT_IMPLEMENTED; } +int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording) { return -1; } } diff --git a/lib/platform/os.h b/lib/platform/os.h index 61a26e051..4913d7b06 100644 --- a/lib/platform/os.h +++ b/lib/platform/os.h @@ -33,18 +33,6 @@ #if (defined(_WIN32) || defined(_WIN64)) #include "windows/os-types.h" - -#ifndef PATH_SEPARATOR_CHAR -#define PATH_SEPARATOR_CHAR '\\' -#define PATH_SEPARATOR_STRING "\\" -#endif - #else #include "posix/os-types.h" - -#ifndef PATH_SEPARATOR_CHAR -#define PATH_SEPARATOR_CHAR '/' -#define PATH_SEPARATOR_STRING "/" -#endif - #endif diff --git a/lib/platform/posix/os-threads.h b/lib/platform/posix/os-threads.h index 8b56731ad..e5f935cf6 100644 --- a/lib/platform/posix/os-threads.h +++ b/lib/platform/posix/os-threads.h @@ -64,9 +64,10 @@ namespace PLATFORM } typedef pthread_t thread_t; + #define INVALID_THREAD_VALUE 0 #define ThreadsCreate(thread, func, arg) (pthread_create(&thread, NULL, (void *(*) (void *))func, (void *)arg) == 0) - #define ThreadsWait(thread, retval) (pthread_join(thread, retval) == 0) + #define ThreadsWait(thread, retval) (thread ? pthread_join(thread, retval) == 0 : true) typedef pthread_mutex_t mutex_t; #define MutexCreate(mutex) pthread_mutex_init(&mutex, GetRecursiveMutexAttribute()); diff --git a/lib/platform/posix/os-types.h b/lib/platform/posix/os-types.h index b89b9cc2a..a36563549 100644 --- a/lib/platform/posix/os-types.h +++ b/lib/platform/posix/os-types.h @@ -44,6 +44,10 @@ #include #include +extern "C" { +#include +} + #define LIBTYPE #define DECLSPEC diff --git a/lib/platform/posix/serialport.cpp b/lib/platform/posix/serialport.cpp index cefc21201..3764a1567 100644 --- a/lib/platform/posix/serialport.cpp +++ b/lib/platform/posix/serialport.cpp @@ -47,20 +47,36 @@ #ifndef IUCLC #define IUCLC 0 #endif +#else +#include #endif + using namespace std; using namespace PLATFORM; +inline bool RemoveLock(const char *strDeviceName) +{ + #if !defined(__APPLE__) && !defined(__FreeBSD__) + return dev_unlock(strDeviceName, 0) == 0; + #endif +} + void CSerialSocket::Close(void) { if (IsOpen()) + { SocketClose(m_socket); + RemoveLock(m_strName.c_str()); + } } void CSerialSocket::Shutdown(void) { if (IsOpen()) + { SocketClose(m_socket); + RemoveLock(m_strName.c_str()); + } } ssize_t CSerialSocket::Write(void* data, size_t len) @@ -78,32 +94,48 @@ bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) { iTimeoutMs = 0; if (IsOpen()) + { + m_iError = EINVAL; return false; + } if (m_iDatabits != SERIAL_DATA_BITS_FIVE && m_iDatabits != SERIAL_DATA_BITS_SIX && m_iDatabits != SERIAL_DATA_BITS_SEVEN && m_iDatabits != SERIAL_DATA_BITS_EIGHT) { m_strError = "Databits has to be between 5 and 8"; + m_iError = EINVAL; return false; } if (m_iStopbits != SERIAL_STOP_BITS_ONE && m_iStopbits != SERIAL_STOP_BITS_TWO) { m_strError = "Stopbits has to be 1 or 2"; + m_iError = EINVAL; return false; } if (m_iParity != SERIAL_PARITY_NONE && m_iParity != SERIAL_PARITY_EVEN && m_iParity != SERIAL_PARITY_ODD) { m_strError = "Parity has to be none, even or odd"; + m_iError = EINVAL; + return false; + } + + #if !defined(__APPLE__) && !defined(__FreeBSD__) + if (dev_lock(m_strName.c_str()) != 0) + { + m_strError = "Couldn't lock the serial port"; + m_iError = EBUSY; return false; } + #endif m_socket = open(m_strName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (m_socket == INVALID_SERIAL_SOCKET_VALUE) { m_strError = strerror(errno); + RemoveLock(m_strName.c_str()); return false; } @@ -150,6 +182,7 @@ bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) if (tcsetattr(m_socket, TCSANOW, &m_options) != 0) { m_strError = strerror(errno); + RemoveLock(m_strName.c_str()); return false; } diff --git a/lib/platform/posix/serversocket.cpp b/lib/platform/posix/serversocket.cpp new file mode 100644 index 000000000..dce13d360 --- /dev/null +++ b/lib/platform/posix/serversocket.cpp @@ -0,0 +1,152 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "../os.h" +#include "../sockets/tcp.h" +#include "../sockets/serversocket.h" + +using namespace std; +using namespace PLATFORM; + +bool CTcpServerSocket::Open(uint64_t UNUSED(iTimeoutMs)) +{ + bool bReturn(false); + struct addrinfo *address(NULL), *addr(NULL); + if (!TcpResolveAddress("localhost", m_iPort, &m_iError, &address)) + { + m_strError = strerror(m_iError); + return bReturn; + } + + for(addr = address; !bReturn && addr; addr = addr->ai_next) + { + m_socket = TcpCreateSocket(addr, &m_iError); + if (m_socket != INVALID_SOCKET_VALUE) + { + bReturn = true; + break; + } + else + { + m_strError = strerror(m_iError); + } + } + + if (bReturn) + { + m_iError = bind(m_socket, addr->ai_addr, addr->ai_addrlen); + if (m_iError) + { + m_strError = strerror(m_iError); + bReturn = false; + } + } + + freeaddrinfo(address); + + if (bReturn) + { + m_iError = listen(m_socket, 16); + if (m_iError) + { + m_strError = strerror(m_iError); + bReturn = false; + } + } + + return bReturn; +} + +void CTcpServerSocket::Close(void) +{ + if (IsOpen()) + TcpSocketClose(m_socket); + m_socket = INVALID_SOCKET_VALUE; +} + +void CTcpServerSocket::Shutdown(void) +{ + Close(); +} + +bool CTcpServerSocket::IsOpen(void) +{ + return m_socket != INVALID_SOCKET_VALUE; +} + +CStdString CTcpServerSocket::GetError(void) +{ + CStdString strError; + strError = m_strError.IsEmpty() && m_iError != 0 ? strerror(m_iError) : m_strError; + return strError; +} + +int CTcpServerSocket::GetErrorNumber(void) +{ + return m_iError; +} + +CStdString CTcpServerSocket::GetName(void) +{ + CStdString strName("localhost"); + return strName; +} + +ISocket* CTcpServerSocket::Accept(void) +{ + struct sockaddr clientAddr; + unsigned int iClientLen(sizeof(clientAddr)); + tcp_socket_t client = accept(m_socket, &clientAddr, &iClientLen); + + if (client != INVALID_SOCKET_VALUE) + { + CTcpClientSocket *socket = new CTcpClientSocket(client); + return (ISocket*)socket; + } + + m_strError = strerror(m_iError); + return NULL; +} + +tcp_socket_t CTcpServerSocket::TcpCreateSocket(struct addrinfo* addr, int* iError) +{ + tcp_socket_t fdSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (fdSock == INVALID_SOCKET_VALUE) + { + *iError = errno; + return (tcp_socket_t)INVALID_SOCKET_VALUE; + } + + TcpSetNoDelay(fdSock); + + return fdSock; +} diff --git a/lib/platform/sockets/serialport.h b/lib/platform/sockets/serialport.h index bdd05b96f..eed05a001 100644 --- a/lib/platform/sockets/serialport.h +++ b/lib/platform/sockets/serialport.h @@ -71,6 +71,9 @@ namespace PLATFORM public: CSerialSocket(const CStdString &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : CCommonSocket(INVALID_SERIAL_SOCKET_VALUE, strName), + #ifdef __WINDOWS__ + m_iCurrentReadTimeout(MAXDWORD), + #endif m_bIsOpen(false), m_iBaudrate(iBaudrate), m_iDatabits(iDatabits), @@ -96,6 +99,9 @@ namespace PLATFORM protected: #ifndef __WINDOWS__ struct termios m_options; + #else + bool SetTimeouts(serial_socket_t socket, int* iError, DWORD iTimeoutMs); + DWORD m_iCurrentReadTimeout; #endif bool m_bIsOpen; diff --git a/lib/platform/sockets/serversocket.h b/lib/platform/sockets/serversocket.h new file mode 100644 index 000000000..edc7fcd98 --- /dev/null +++ b/lib/platform/sockets/serversocket.h @@ -0,0 +1,90 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "socket.h" + +using namespace std; + +namespace PLATFORM +{ + class IServerSocket : public ISocket + { + public: + IServerSocket() : ISocket() {} + + virtual ~IServerSocket(void) {} + + virtual bool Open(uint64_t iTimeoutMs = 0) = 0; + virtual void Close(void) = 0; + virtual void Shutdown(void) = 0; + virtual bool IsOpen(void) = 0; + ssize_t Write(void* data, size_t len) { (void) data; (void) len; return EINVAL; } + ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) { (void) data; (void) len; (void) iTimeoutMs; return EINVAL; } + virtual CStdString GetError(void) = 0; + virtual int GetErrorNumber(void) = 0; + virtual CStdString GetName(void) = 0; + + virtual ISocket* Accept(void) = 0; + }; + + class CTcpServerSocket : public IServerSocket + { + public: + CTcpServerSocket(uint16_t iPort) : + IServerSocket(), + m_iPort(iPort), + m_socket(INVALID_SOCKET_VALUE), + m_iError(0) {} + + virtual ~CTcpServerSocket(void) {} + + virtual bool Open(uint64_t iTimeoutMs = 0); + virtual void Close(void); + virtual void Shutdown(void); + virtual bool IsOpen(void); + virtual CStdString GetError(void); + virtual int GetErrorNumber(void); + virtual CStdString GetName(void); + + virtual ISocket* Accept(void); + + protected: + virtual tcp_socket_t TcpCreateSocket(struct addrinfo* addr, int* iError); + + protected: + uint16_t m_iPort; + tcp_socket_t m_socket; + CStdString m_strError; + int m_iError; + }; +} diff --git a/lib/platform/sockets/tcp.h b/lib/platform/sockets/tcp.h index ffc372cca..1693354ea 100644 --- a/lib/platform/sockets/tcp.h +++ b/lib/platform/sockets/tcp.h @@ -120,6 +120,48 @@ namespace PLATFORM uint16_t m_iPort; }; + class CTcpClientSocket : public CCommonSocket + { + public: + CTcpClientSocket(tcp_socket_t socket) : + CCommonSocket(socket, "tcpclient") {} + + virtual ~CTcpClientSocket(void) {} + + virtual bool Open(uint64_t iTimeoutMs = 0) + { + (void) iTimeoutMs; + return true; + } + + virtual void Close(void) + { + TcpSocketClose(m_socket); + m_socket = INVALID_SOCKET_VALUE; + } + + virtual void Shutdown(void) + { + TcpSocketShutdown(m_socket); + m_socket = INVALID_SOCKET_VALUE; + } + + virtual ssize_t Write(void* data, size_t len) + { + return TcpSocketWrite(m_socket, &m_iError, data, len); + } + + virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) + { + return TcpSocketRead(m_socket, &m_iError, data, len, iTimeoutMs); + } + + virtual bool IsOpen(void) + { + return m_socket != INVALID_SOCKET_VALUE; + } + }; + class CTcpConnection : public CProtectedSocket { public: diff --git a/lib/platform/threads/threads.h b/lib/platform/threads/threads.h index 97774b3b1..36477708d 100644 --- a/lib/platform/threads/threads.h +++ b/lib/platform/threads/threads.h @@ -41,11 +41,15 @@ namespace PLATFORM CThread(void) : m_bStop(false), m_bRunning(false), - m_bStopped(false) {} + m_bStopped(false), + m_thread(INVALID_THREAD_VALUE) {} virtual ~CThread(void) { StopThread(0); + void *retVal = NULL; + if (m_thread != INVALID_THREAD_VALUE) + ThreadsWait(m_thread, &retVal); } static void *ThreadHandler(CThread *thread) @@ -88,18 +92,18 @@ namespace PLATFORM virtual bool CreateThread(bool bWait = true) { - bool bReturn(false); - CLockObject lock(m_threadMutex); - if (!IsRunning()) + bool bReturn(false); + CLockObject lock(m_threadMutex); + if (!IsRunning()) + { + m_bStop = false; + if (ThreadsCreate(m_thread, CThread::ThreadHandler, ((void*)static_cast(this)))) { - m_bStop = false; - if (ThreadsCreate(m_thread, CThread::ThreadHandler, ((void*)static_cast(this)))) - { - if (bWait) - m_threadCondition.Wait(m_threadMutex, m_bRunning); - bReturn = true; - } + if (bWait) + m_threadCondition.Wait(m_threadMutex, m_bRunning); + bReturn = true; } + } return bReturn; } @@ -140,13 +144,13 @@ namespace PLATFORM protected: void SetRunning(bool bSetTo); + CMutex m_threadMutex; private: bool m_bStop; bool m_bRunning; bool m_bStopped; CCondition m_threadCondition; - CMutex m_threadMutex; thread_t m_thread; }; }; diff --git a/lib/platform/util/buffer.h b/lib/platform/util/buffer.h index 56ffd6450..aa658ee61 100644 --- a/lib/platform/util/buffer.h +++ b/lib/platform/util/buffer.h @@ -41,7 +41,8 @@ namespace PLATFORM { public: SyncedBuffer(size_t iMaxSize = 100) : - m_maxSize(iMaxSize) {} + m_maxSize(iMaxSize), + m_bHasMessages(false) {} virtual ~SyncedBuffer(void) { @@ -53,6 +54,7 @@ namespace PLATFORM CLockObject lock(m_mutex); while (!m_buffer.empty()) m_buffer.pop(); + m_condition.Broadcast(); } size_t Size(void) @@ -74,17 +76,41 @@ namespace PLATFORM return false; m_buffer.push(entry); + m_bHasMessages = true; + m_condition.Signal(); return true; } - bool Pop(_BType &entry) + bool Pop(_BType &entry, uint32_t iTimeoutMs = 0) { bool bReturn(false); CLockObject lock(m_mutex); + + // wait for a signal if the buffer is empty + if (m_buffer.empty() && iTimeoutMs > 0) + { + if (!m_condition.Wait(m_mutex, m_bHasMessages, iTimeoutMs)) + return bReturn; + } + + // pop the first item if (!m_buffer.empty()) { entry = m_buffer.front(); m_buffer.pop(); + m_bHasMessages = !m_buffer.empty(); + bReturn = true; + } + return bReturn; + } + + bool Peek(_BType &entry) + { + bool bReturn(false); + CLockObject lock(m_mutex); + if (!m_buffer.empty()) + { + entry = m_buffer.front(); bReturn = true; } return bReturn; @@ -94,5 +120,7 @@ namespace PLATFORM size_t m_maxSize; std::queue<_BType> m_buffer; CMutex m_mutex; + CCondition m_condition; + bool m_bHasMessages; }; }; diff --git a/lib/platform/util/util.h b/lib/platform/util/util.h new file mode 100644 index 000000000..2b85c6325 --- /dev/null +++ b/lib/platform/util/util.h @@ -0,0 +1,34 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#define DELETE_AND_NULL(t) while (t) { delete (t); (t) = NULL; } diff --git a/lib/platform/windows/os-threads.h b/lib/platform/windows/os-threads.h index 3714c1671..47101dcd0 100644 --- a/lib/platform/windows/os-threads.h +++ b/lib/platform/windows/os-threads.h @@ -34,6 +34,7 @@ namespace PLATFORM { #define thread_t HANDLE + #define INVALID_THREAD_VALUE NULL #define ThreadsWait(thread, retVal) (::WaitForSingleObject(thread, INFINITE) < 0) #define ThreadsCreate(thread, func, arg) ((thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL)) == NULL ? false : true) diff --git a/lib/platform/windows/serialport.cpp b/lib/platform/windows/serialport.cpp index c0cdd936a..96e743f80 100644 --- a/lib/platform/windows/serialport.cpp +++ b/lib/platform/windows/serialport.cpp @@ -48,28 +48,25 @@ void FormatWindowsError(int iErrorCode, CStdString &strMessage) } } -bool SetTimeouts(serial_socket_t socket, int* iError, bool bBlocking) +bool CSerialSocket::SetTimeouts(serial_socket_t socket, int* iError, DWORD iTimeoutMs) { if (socket == INVALID_HANDLE_VALUE) return false; - COMMTIMEOUTS cto; - if (!GetCommTimeouts(socket, &cto)) - { - *iError = GetLastError(); - return false; - } + if (iTimeoutMs == m_iCurrentReadTimeout) + return true; - if (bBlocking) + COMMTIMEOUTS cto; + if (iTimeoutMs == 0) { - cto.ReadIntervalTimeout = 0; + cto.ReadIntervalTimeout = MAXDWORD; cto.ReadTotalTimeoutConstant = 0; cto.ReadTotalTimeoutMultiplier = 0; } else { - cto.ReadIntervalTimeout = MAXDWORD; - cto.ReadTotalTimeoutConstant = 0; + cto.ReadIntervalTimeout = 0; + cto.ReadTotalTimeoutConstant = iTimeoutMs; cto.ReadTotalTimeoutMultiplier = 0; } @@ -78,6 +75,10 @@ bool SetTimeouts(serial_socket_t socket, int* iError, bool bBlocking) *iError = GetLastError(); return false; } + else + { + m_iCurrentReadTimeout = iTimeoutMs; + } return true; } @@ -103,7 +104,13 @@ ssize_t CSerialSocket::Write(void* data, size_t len) ssize_t CSerialSocket::Read(void* data, size_t len, uint64_t iTimeoutMs /* = 0 */) { - return IsOpen() ? SerialSocketRead(m_socket, &m_iError, data, len, iTimeoutMs) : -1; + DWORD dwTimeoutMs((DWORD)iTimeoutMs); + if (iTimeoutMs != (uint64_t)iTimeoutMs) + dwTimeoutMs = MAXDWORD; + + return IsOpen() && SetTimeouts(m_socket, &m_iError, dwTimeoutMs) ? + SerialSocketRead(m_socket, &m_iError, data, len, iTimeoutMs) : + -1; } bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) @@ -153,7 +160,7 @@ bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) return false; } - if (!SetTimeouts(m_socket, &m_iError, false)) + if (!SetTimeouts(m_socket, &m_iError, 0)) { m_strError = "unable to set timeouts"; FormatWindowsError(GetLastError(), m_strError); diff --git a/xbmc/libXBMC_pvr.h b/xbmc/libXBMC_pvr.h index fb94e23fd..a4e161b93 100644 --- a/xbmc/libXBMC_pvr.h +++ b/xbmc/libXBMC_pvr.h @@ -64,101 +64,78 @@ class CHelper_libXBMC_pvr libBasePath += PVR_HELPER_DLL; m_libXBMC_pvr = dlopen(libBasePath.c_str(), RTLD_LAZY); - if (m_libXBMC_pvr == NULL) - { - fprintf(stderr, "Unable to load %s\n", dlerror()); - return false; - } + if (!m_libXBMC_pvr) { fprintf(stderr, "Unable to load %s\n", dlerror()); return false; } PVR_register_me = (int (*)(void *HANDLE)) - dlsym(m_libXBMC_pvr, "PVR_register_me"); - if (PVR_register_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + dlsym(m_libXBMC_pvr, "PVR_register_me"); + if (!PVR_register_me) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } PVR_unregister_me = (void (*)()) - dlsym(m_libXBMC_pvr, "PVR_unregister_me"); - if (PVR_unregister_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - - TransferEpgEntry = (void (*)(const ADDON_HANDLE handle, const EPG_TAG *epgentry)) - dlsym(m_libXBMC_pvr, "PVR_transfer_epg_entry"); - if (TransferEpgEntry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - - TransferChannelEntry = (void (*)(const ADDON_HANDLE handle, const PVR_CHANNEL *chan)) - dlsym(m_libXBMC_pvr, "PVR_transfer_channel_entry"); - if (TransferChannelEntry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - - TransferTimerEntry = (void (*)(const ADDON_HANDLE handle, const PVR_TIMER *timer)) - dlsym(m_libXBMC_pvr, "PVR_transfer_timer_entry"); - if (TransferTimerEntry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - - TransferRecordingEntry = (void (*)(const ADDON_HANDLE handle, const PVR_RECORDING *recording)) - dlsym(m_libXBMC_pvr, "PVR_transfer_recording_entry"); - if (TransferRecordingEntry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + dlsym(m_libXBMC_pvr, "PVR_unregister_me"); + if (!PVR_unregister_me) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - AddMenuHook = (void (*)(PVR_MENUHOOK *hook)) - dlsym(m_libXBMC_pvr, "PVR_add_menu_hook"); - if (AddMenuHook == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } +#ifdef USE_DEMUX + AllocateDemuxPacket = (DemuxPacket* (*)(int iDataSize)) + dlsym(m_libXBMC_pvr, "PVR_allocate_demux_packet"); + if (!AllocateDemuxPacket) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - Recording = (void (*)(const char *Name, const char *FileName, bool On)) - dlsym(m_libXBMC_pvr, "PVR_recording"); - if (Recording == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + FreeDemuxPacket = (void (*)(DemuxPacket* pPacket)) + dlsym(m_libXBMC_pvr, "PVR_free_demux_packet"); + if (!FreeDemuxPacket) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } +#endif - TriggerTimerUpdate = (void (*)()) - dlsym(m_libXBMC_pvr, "PVR_trigger_timer_update"); - if (TriggerTimerUpdate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferChannelEntry = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL *chan)) + dlsym(m_libXBMC_pvr, "PVR_transfer_channel_entry"); + if (!TransferChannelEntry) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - TriggerRecordingUpdate = (void (*)()) - dlsym(m_libXBMC_pvr, "PVR_trigger_recording_update"); - if (TriggerRecordingUpdate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferChannelGroup = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL_GROUP *group)) + dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group"); + if (!TransferChannelGroup) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - TriggerChannelUpdate = (void (*)()) - dlsym(m_libXBMC_pvr, "PVR_trigger_channel_update"); - if (TriggerChannelUpdate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferChannelGroupMember = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL_GROUP_MEMBER *member)) + dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group_member"); + if (!TransferChannelGroupMember) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - TriggerChannelGroupsUpdate = (void (*)()) - dlsym(m_libXBMC_pvr, "PVR_trigger_channel_groups_update"); - if (TriggerChannelGroupsUpdate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferEpgEntry = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const EPG_TAG *epgentry)) + dlsym(m_libXBMC_pvr, "PVR_transfer_epg_entry"); + if (!TransferEpgEntry) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - TransferChannelGroup = (void (*)(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group)) - dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group"); - if (TransferChannelGroup == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferMenuHook = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_MENUHOOK *hook)) + dlsym(m_libXBMC_pvr, "PVR_transfer_menu_hook"); + if (!TransferMenuHook) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - TransferChannelGroupMember = (void (*)(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member)) - dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group_member"); - if (TransferChannelGroupMember == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferRecordingEntry = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_RECORDING *recording)) + dlsym(m_libXBMC_pvr, "PVR_transfer_recording_entry"); + if (!TransferRecordingEntry) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } -#ifdef USE_DEMUX - FreeDemuxPacket = (void (*)(DemuxPacket* pPacket)) - dlsym(m_libXBMC_pvr, "PVR_free_demux_packet"); - if (FreeDemuxPacket == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + TransferTimerEntry = (void (*)(const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_TIMER *timer)) + dlsym(m_libXBMC_pvr, "PVR_transfer_timer_entry"); + if (!TransferTimerEntry) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } - AllocateDemuxPacket = (DemuxPacket* (*)(int iDataSize)) - dlsym(m_libXBMC_pvr, "PVR_allocate_demux_packet"); - if (AllocateDemuxPacket == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } -#endif + Recording = (void (*)(const char *Name, const char *FileName, bool On)) + dlsym(m_libXBMC_pvr, "PVR_recording"); + if (!Recording) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } return PVR_register_me(m_Handle) > 0; } - void (*TransferEpgEntry)(const ADDON_HANDLE handle, const EPG_TAG *epgentry); - void (*TransferChannelEntry)(const ADDON_HANDLE handle, const PVR_CHANNEL *chan); - void (*TransferTimerEntry)(const ADDON_HANDLE handle, const PVR_TIMER *timer); - void (*TransferRecordingEntry)(const ADDON_HANDLE handle, const PVR_RECORDING *recording); - void (*AddMenuHook)(PVR_MENUHOOK *hook); - void (*Recording)(const char *Name, const char *FileName, bool On); - void (*TriggerTimerUpdate)(); - void (*TriggerRecordingUpdate)(); - void (*TriggerChannelUpdate)(); - void (*TriggerChannelGroupsUpdate)(); - void (*TransferChannelGroup)(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group); - void (*TransferChannelGroupMember)(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member); #ifdef USE_DEMUX - void (*FreeDemuxPacket)(DemuxPacket* pPacket); - DemuxPacket* (*AllocateDemuxPacket)(int iDataSize); + DemuxPacket* (*AllocateDemuxPacket) (int iDataSize); + void (*FreeDemuxPacket) (DemuxPacket* pPacket); #endif + void (*TransferChannelEntry) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL *chan); + void (*TransferChannelGroup) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL_GROUP *group); + void (*TransferChannelGroupMember) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_CHANNEL_GROUP_MEMBER *member); + void (*TransferEpgEntry) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const EPG_TAG *epgentry); + void (*TransferMenuHook) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_MENUHOOK *hook); + void (*TransferRecordingEntry) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_RECORDING *recording); + void (*TransferTimerEntry) (const ADDON_HANDLE handle, const PVR_UPDATE_TYPE updateType, const PVR_TIMER *timer); + void (*Recording) (const char *Name, const char *FileName, bool On); + protected: - int (*PVR_register_me)(void *HANDLE); - void (*PVR_unregister_me)(); + int (*PVR_register_me) (void *HANDLE); + void (*PVR_unregister_me) (void); private: void *m_libXBMC_pvr; diff --git a/xbmc/xbmc_pvr_dll.h b/xbmc/xbmc_pvr_dll.h index a2b22614e..ad25a1f2c 100644 --- a/xbmc/xbmc_pvr_dll.h +++ b/xbmc/xbmc_pvr_dll.h @@ -201,6 +201,29 @@ extern "C" */ PVR_ERROR RenameRecording(const PVR_RECORDING &recording); + /*! + * @brief Set the play count of a recording on the backend. + * @param recording The recording to change the play count. + * @param count Play count. + * @return PVR_ERROR_NO_ERROR if the recording's play count has been set successfully. + */ + PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count); + + /*! + * @brief Set the last watched position of a recording on the backend. + * @param recording The recording. + * @param position The last watched position in seconds + * @return PVR_ERROR_NO_ERROR if the position has been stored successfully. + */ + PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition); + + /*! + * @brief Retrieve the last watched position of a recording on the backend. + * @param recording The recording. + * @return The last watched position in seconds or -1 on error + */ + int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording); + //@} /** @name PVR timer methods */ //@{ @@ -406,6 +429,9 @@ extern "C" pClient->GetRecordings = GetRecordings; pClient->DeleteRecording = DeleteRecording; pClient->RenameRecording = RenameRecording; + pClient->SetRecordingPlayCount = SetRecordingPlayCount; + pClient->SetRecordingLastPlayedPosition = SetRecordingLastPlayedPosition; + pClient->GetRecordingLastPlayedPosition = GetRecordingLastPlayedPosition; pClient->GetTimersAmount = GetTimersAmount; pClient->GetTimers = GetTimers; diff --git a/xbmc/xbmc_pvr_types.h b/xbmc/xbmc_pvr_types.h index 29e9ef8bd..78b72bf2a 100644 --- a/xbmc/xbmc_pvr_types.h +++ b/xbmc/xbmc_pvr_types.h @@ -34,6 +34,7 @@ #endif #endif #include +#include #include "xbmc_addon_types.h" @@ -122,6 +123,14 @@ extern "C" { PVR_TIMER_STATE_CANCELLED = 5 /*!< @brief the timer was scheduled, but was cancelled */ } PVR_TIMER_STATE; + typedef enum + { + PVR_UPDATE_RESPONSE = 0, + PVR_UPDATE_NEW = 1, + PVR_UPDATE_REPLACE = 2, + PVR_UPDATE_DELETE = 3 + } PVR_UPDATE_TYPE; + /*! * @brief Properties passed to the Create() method of an add-on. */ @@ -129,6 +138,7 @@ extern "C" { { const char *strUserPath; /*!< @brief path to the user profile */ const char *strClientPath; /*!< @brief path to this add-on */ + void * callbackAddress; /*!< @brief address to the CPVRClient for this add-on */ } PVR_PROPERTIES; /*! @@ -146,6 +156,8 @@ extern "C" { bool bHandlesInputStream; /*!< @brief (optional) true if this add-on provides an input stream. false if XBMC handles the stream. */ bool bHandlesDemuxing; /*!< @brief (optional) true if this add-on demultiplexes packets. */ bool bSupportsRecordingFolders; /*!< @brief (optional) true if the backend supports timers / recordings in folders. */ + bool bSupportsRecordingPlayCount; /*!< @brief (optional) true if the backend supports play count for recordings. */ + bool bSupportsLastPlayedPosition; /*!< @brief (optional) true if the backend supports store/retrieve of last played position for recordings. */ } ATTRIBUTE_PACKED PVR_ADDON_CAPABILITIES; /*! @@ -228,7 +240,7 @@ extern "C" { typedef struct PVR_CHANNEL_GROUP_MEMBER { const char * strGroupName; /*!< @brief (required) name of the channel group to add the channel to */ - unsigned int iChannelUniqueId; /*!< @brief (required) unique id of the member */ + unsigned int iChannelUniqueId; /*!< @brief (required) unique id of the channel */ unsigned int iChannelNumber; /*!< @brief (optional) channel number within the group */ } ATTRIBUTE_PACKED PVR_CHANNEL_GROUP_MEMBER; @@ -238,7 +250,7 @@ extern "C" { typedef struct EPG_TAG { unsigned int iUniqueBroadcastId; /*!< @brief (required) identifier for this event */ const char * strTitle; /*!< @brief (required) this event's title */ - unsigned int iChannelNumber; /*!< @brief (required) the number of the channel this event occurs on */ + unsigned int iChannelUniqueId; /*!< @brief (required) unique id of the channel */ time_t startTime; /*!< @brief (required) start time in UTC */ time_t endTime; /*!< @brief (required) end time in UTC */ const char * strPlotOutline; /*!< @brief (optional) plot outline */ @@ -298,6 +310,7 @@ extern "C" { int iLifetime; /*!< @brief (optional) life time in days of this recording */ int iGenreType; /*!< @brief (optional) genre type */ int iGenreSubType; /*!< @brief (optional) genre sub type */ + bool iPlayCount; /*!< @brief (optional) play count of this recording on the client */ } ATTRIBUTE_PACKED PVR_RECORDING; /*! @@ -346,6 +359,9 @@ extern "C" { PVR_ERROR (__cdecl* GetRecordings)(ADDON_HANDLE handle); PVR_ERROR (__cdecl* DeleteRecording)(const PVR_RECORDING &recording); PVR_ERROR (__cdecl* RenameRecording)(const PVR_RECORDING &recording); + PVR_ERROR (__cdecl* SetRecordingPlayCount)(const PVR_RECORDING &recording, int count); + PVR_ERROR (__cdecl* SetRecordingLastPlayedPosition)(const PVR_RECORDING &recording, int lastplayedposition); + int (__cdecl* GetRecordingLastPlayedPosition)(const PVR_RECORDING &recording); //@} /** @name PVR timer methods */ diff --git a/xbmc/xbmc_vis_dll.h b/xbmc/xbmc_vis_dll.h index cd70fe764..42691e8b9 100644 --- a/xbmc/xbmc_vis_dll.h +++ b/xbmc/xbmc_vis_dll.h @@ -29,7 +29,7 @@ extern "C" { // Functions that your visualisation must implement void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); - void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); + void AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); void Render(); bool OnAction(long action, const void *param); void GetInfo(VIS_INFO* pInfo); diff --git a/xbmc/xbmc_vis_types.h b/xbmc/xbmc_vis_types.h index ecb6a3a20..42801b01b 100644 --- a/xbmc/xbmc_vis_types.h +++ b/xbmc/xbmc_vis_types.h @@ -97,7 +97,7 @@ extern "C" struct Visualisation { void (__cdecl* Start)(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); - void (__cdecl* AudioData)(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); + void (__cdecl* AudioData)(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); void (__cdecl* Render) (); void (__cdecl* GetInfo)(VIS_INFO *info); bool (__cdecl* OnAction)(long flags, const void *param);