diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c68515a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,24 @@
+project(pvr.octonet)
+
+cmake_minimum_required(VERSION 2.6)
+
+enable_language(CXX)
+
+find_package(kodi REQUIRED)
+find_package(kodiplatform REQUIRED)
+find_package(platform REQUIRED)
+
+include_directories(
+ ${kodiplatform_INCLUDE_DIRS}
+ ${platform_INCLUDE_DIRS}
+ ${KODI_INCLUDE_DIR})
+
+set(DEPLIBS
+ ${platform_LIBRARIES})
+
+set(OCTONET_SOURCES
+ src/client.cpp)
+
+build_addon(pvr.octonet OCTONET DEPLIBS)
+
+include(CPack)
diff --git a/pvr.octonet/addon.xml b/pvr.octonet/addon.xml
new file mode 100644
index 0000000..b5cad6f
--- /dev/null
+++ b/pvr.octonet/addon.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+ Kodi PVR Addon für DigitalDevices Octonet Streams
+ Kodi PVR Addon for DigitalDevices Octonet Streams
+ all
+
+
diff --git a/pvr.octonet/resources/language/resource.language.en_gb/strings.po b/pvr.octonet/resources/language/resource.language.en_gb/strings.po
new file mode 100644
index 0000000..8d44017
--- /dev/null
+++ b/pvr.octonet/resources/language/resource.language.en_gb/strings.po
@@ -0,0 +1,21 @@
+# Kodi Media Center language file
+# Addon Name: PVR Octonet Client
+# Addon id: pvr.octonet
+# Addon Provider: Julian Scheel
+msgid ""
+msgstr ""
+"Project-Id-Version: KODI Main\n"
+"Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
+"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Kodi Translation Team\n"
+"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/kodi-main/language/en_GB/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en_GB\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "#30000"
+msgid "Octonet Server Address"
+msgstr ""
diff --git a/pvr.octonet/resources/language/resource.language.en_us/strings.po b/pvr.octonet/resources/language/resource.language.en_us/strings.po
new file mode 100644
index 0000000..8d44017
--- /dev/null
+++ b/pvr.octonet/resources/language/resource.language.en_us/strings.po
@@ -0,0 +1,21 @@
+# Kodi Media Center language file
+# Addon Name: PVR Octonet Client
+# Addon id: pvr.octonet
+# Addon Provider: Julian Scheel
+msgid ""
+msgstr ""
+"Project-Id-Version: KODI Main\n"
+"Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
+"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Kodi Translation Team\n"
+"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/kodi-main/language/en_GB/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en_GB\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "#30000"
+msgid "Octonet Server Address"
+msgstr ""
diff --git a/pvr.octonet/resources/settings.xml b/pvr.octonet/resources/settings.xml
new file mode 100644
index 0000000..7e1e6fb
--- /dev/null
+++ b/pvr.octonet/resources/settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/client.cpp b/src/client.cpp
new file mode 100644
index 0000000..d5b2719
--- /dev/null
+++ b/src/client.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 Julian Scheel
+ * Copyright (C) 2015 jusst technologies GmbH
+ * Copyright (C) 2015 Digital Devices GmbH
+ *
+ * This program is free software; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ */
+
+#include "client.h"
+#include
+#include
+#include
+#include
+
+using namespace ADDON;
+
+/* setting variables with defaults */
+std::string octonetAddress = "";
+
+/* internal state variables */
+ADDON_STATUS addonStatus = ADDON_STATUS_UNKNOWN;
+CHelper_libXBMC_addon *kodi = NULL;
+CHelper_libXBMC_pvr *pvr = NULL;
+
+/* KODI Core Addon functions
+ * see xbmc_addon_dll.h */
+
+extern "C" {
+
+void ADDON_ReadSettings(void)
+{
+ char buffer[2048];
+ if (kodi->GetSetting("octonetAddress", &buffer))
+ octonetAddress = buffer;
+}
+
+ADDON_STATUS ADDON_Create(void *callbacks, void* props)
+{
+ if (callbacks == NULL || props == NULL)
+ return ADDON_STATUS_UNKNOWN;
+
+ PVR_PROPERTIES *pvrprops = (PVR_PROPERTIES*)props;
+ kodi = new CHelper_libXBMC_addon;
+ if (!kodi->RegisterMe(callbacks)) {
+ kodi->Log(LOG_ERROR, "%s: Failed to register octonet addon", __func__);
+ SAFE_DELETE(kodi);
+ return ADDON_STATUS_PERMANENT_FAILURE;
+ }
+
+ pvr = new CHelper_libXBMC_pvr;
+ if (!pvr->RegisterMe(callbacks)) {
+ kodi->Log(LOG_ERROR, "%s: Failed to register octonet pvr addon", __func__);
+ SAFE_DELETE(pvr);
+ SAFE_DELETE(kodi);
+ return ADDON_STATUS_PERMANENT_FAILURE;
+ }
+
+ kodi->Log(LOG_DEBUG, "%s: Creating octonet pvr addon", __func__);
+ ADDON_ReadSettings();
+
+ addonStatus = ADDON_STATUS_OK;
+ return addonStatus;
+}
+
+void ADDON_Stop() {} /* no-op */
+
+void ADDON_Destroy()
+{
+ delete pvr;
+ delete kodi;
+ addonStatus = ADDON_STATUS_UNKNOWN;
+}
+
+ADDON_STATUS ADDON_GetStatus()
+{
+ return addonStatus;
+}
+
+bool ADDON_HasSettings()
+{
+ return true;
+}
+
+unsigned int ADDON_GetSettings(ADDON_StructSetting ***sSet)
+{
+ return 0;
+}
+
+ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue)
+{
+ /* For simplicity do a full addon restart whenever settings are
+ * changed */
+ return ADDON_STATUS_NEED_RESTART;
+}
+
+void ADDON_FreeSettings() {} /* no-op */
+void ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data) {} /* no-op */
+
+}
+
+
+/* KODI PVR Addon functions
+ * see xbmc_pvr_dll.h */
+extern "C"
+{
+
+const char* GetPVRAPIVersion(void)
+{
+ return XBMC_PVR_API_VERSION;
+}
+
+const char* GetMininumPVRAPIVersion(void)
+{
+ return XBMC_PVR_MIN_API_VERSION;
+}
+
+const char* GetGUIAPIVersion(void)
+{
+ return KODI_GUILIB_API_VERSION;
+}
+
+const char* GetMininumGUIAPIVersion(void)
+{
+ return KODI_GUILIB_MIN_API_VERSION;
+}
+
+PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES *pCapabilities)
+{
+ pCapabilities->bSupportsTV = true;
+ pCapabilities->bSupportsRadio = true;
+
+ return PVR_ERROR_NO_ERROR;
+}
+
+const char* GetBackendName(void)
+{
+ return "DigitalDevice Octonet PVR Addon";
+}
+
+const char* GetBackendVersion(void)
+{
+ return XBMC_PVR_API_VERSION;
+}
+
+const char* GetConnectionString(void)
+{
+ return "connected"; // FIXME: translate?
+}
+
+PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA &item) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* EPG */
+PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* Channel groups */
+int GetChannelGroupsAmount(void) { return -1; }
+PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* Channels */
+PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+int GetChannelsAmount(void)
+{
+ // FIXME: This is a dummy
+ return 2;
+}
+
+PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio)
+{
+ // FIXME: This is a dummy
+ if (!bRadio) {
+ PVR_CHANNEL chan;
+ memset(&chan, 0, sizeof(PVR_CHANNEL));
+
+ chan.iUniqueId = 1;
+ chan.bIsRadio = bRadio;
+ chan.iChannelNumber = 1;
+ snprintf(chan.strChannelName, sizeof(chan.strChannelName) - 1,
+ "Das Erste");
+ snprintf(chan.strStreamURL, sizeof(chan.strStreamURL) - 1,
+ "rtsp://172.27.1.40:8554/channel/1");
+
+ pvr->TransferChannelEntry(handle, &chan);
+ } else {
+ PVR_CHANNEL chan;
+ memset(&chan, 0, sizeof(PVR_CHANNEL));
+
+ chan.iUniqueId = 2;
+ chan.bIsRadio = bRadio;
+ chan.iChannelNumber = 2;
+ snprintf(chan.strChannelName, sizeof(chan.strChannelName) - 1,
+ "NDR 2");
+ snprintf(chan.strStreamURL, sizeof(chan.strStreamURL) - 1,
+ "rtsp://172.27.1.40:8554/channel/10");
+
+ pvr->TransferChannelEntry(handle, &chan);
+ }
+
+ return PVR_ERROR_NO_ERROR;
+}
+
+PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR RenameChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR MoveChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* Recordings */
+int GetRecordingsAmount(bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR DeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR RenameRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
+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 PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY edl[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
+int GetTimersAmount(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR GetTimers(ADDON_HANDLE handle) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR AddTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete) { return PVR_ERROR_NOT_IMPLEMENTED; }
+PVR_ERROR UpdateTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* PVR stream handling */
+/* entirely unused, as we use standard RTSP+TS mux, which can be handlded by
+ * Kodi core */
+bool OpenLiveStream(const PVR_CHANNEL& channel) { return false; }
+void CloseLiveStream(void) {}
+int ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize) { return -1; }
+long long SeekLiveStream(long long iPosition, int iWhence) { return -1; }
+long long PositionLiveStream(void) { return -1; }
+long long LengthLiveStream(void) { return -1; }
+int GetCurrentClientChannel(void) { return -1; }
+bool SwitchChannel(const PVR_CHANNEL& channel) { return false; }
+PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS& signalStatus) { return PVR_ERROR_NOT_IMPLEMENTED; }
+const char* GetLiveStreamURL(const PVR_CHANNEL& channel) { return NULL; }
+PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties) { return PVR_ERROR_NOT_IMPLEMENTED; }
+
+/* Recording stream handling */
+bool OpenRecordedStream(const PVR_RECORDING& recording) { return false; }
+void CloseRecordedStream(void) {}
+int ReadRecordedStream(unsigned char* pBuffer, unsigned int iBufferSize) { return -1; }
+long long SeekRecordedStream(long long iPosition, int iWhence) { return -1; }
+long long PositionRecordedStream(void) { return -1; }
+long long LengthRecordedStream(void) { return -1; }
+
+/* PVR demuxer */
+/* entirey unused, as we use TS */
+void DemuxReset(void) {}
+void DemuxAbort(void) {}
+void DemuxFlush(void) {}
+DemuxPacket* DemuxRead(void) { return NULL; }
+
+/* Various helper functions */
+unsigned int GetChannelSwitchDelay(void) { return 0; }
+bool CanPauseStream() { return false; }
+bool CanSeekStream() { return false; }
+
+/* Callbacks */
+void PauseStream(bool bPaused) {}
+bool SeekTime(int time, bool backwards, double *startpts) { return false; }
+void SetSpeed(int speed) {}
+
+time_t GetPlayingTime() { return 0; }
+time_t GetBufferTimeStart() { return 0; }
+time_t GetBufferTimeEnd() { return 0; }
+
+const char* GetBackendHostname()
+{
+ return octonetAddress.c_str();
+}
+
+}
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..394e56e
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,31 @@
+#pragma once
+/*
+ * Copyright (C) 2015 Julian Scheel
+ * Copyright (C) 2015 jusst technologies GmbH
+ * Copyright (C) 2015 Digital Devices GmbH
+ *
+ * This program is free software; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ */
+
+#include "kodi/libXBMC_addon.h"
+#include "kodi/libXBMC_pvr.h"
+
+extern ADDON::CHelper_libXBMC_addon *kodi;
+extern CHelper_libXBMC_pvr *pvr;
+
+/* IP or hostname of the octonet to be connected to */
+extern std::string octonetAddress;