Kodi Community Forum

Full Version: [POC] EyeTV PVR backend
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi!
I want to share with you my hack of using an EyeTV dongle on Mac OS X for the native Kodi PVR interface.
I am using PVR IPTV Simple Client as the PVR client and the EyeTV application + VLC + a web server as the backend.

This is meant to be a proof-of-concept to show that it is possible to develop an EyeTV backend on Mac OS X for the Kodi PVR interface. The functionality could be ported into a native PVR plugin for a simpler setup, without the need for a separate web server and possibly without the need for VLC.

Benefits over using EyeTV Parser:
- Being able to use the native PVR interface, including EPG listings
- Better video quality
- Faster channel switching

Things that does not work but that could be possible with a native PVR plugin:
- Time-shifting
- Scheduling and recording
- EPG from DVB

The following external applications is required for this setup:
MAMP or any PHP capable server
VLC
EyeTV
VLC EyeTV Capture Plugin

EyeTV will also need to be enabled for iPhone access.

We will use the iPhone service to silently change channels, but VLC to get the video stream.

In the htdocs folder for MAMP is the following files:
.htaccess
Code:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^channel/(.+)$ eyetv-stream.php?serviceID=$1 [L,QSA]
RewriteRule ^eyetv-playlist\.m3u8$ eyetv-playlist.php [L,QSA]

# Protect the htaccess file
<Files .htaccess>
Order Allow,Deny
Deny from all
</Files>

# Disable directory browsing
Options All -Indexes

eyetv-config.php
PHP Code:
<?php

$VLC_PATH 
"/Applications/VLC.app/Contents/MacOS/VLC";
$VLC_PORT "6363";
$EYETV_SERVICE "http://127.0.0.1:2170/";
$PHP_PATH "/usr/bin/php";
$LOGGING_ENABLED false;
$LOG_PATH "/Users/Server/Library/Logs/";
$STREAM_BASE_URL "http://localhost:8080/channel/";

function 
my_log($message)
{
    global 
$LOG_PATH,$LOGGING_ENABLED;
    if(
$LOGGING_ENABLED)
    {
        
file_put_contents($LOG_PATH."eyetv-stream.log",date(DATE_ATOM)." \t".$message."\n",FILE_APPEND);
    }


eyetv-stream.php
PHP Code:
<?php

include "eyetv-config.php";

ini_set('display_errors','off');
if(
$LOGGING_ENABLED)
{
    
ini_set("log_errors"1);
    
ini_set("error_log"$LOG_PATH."eyetv-stream-php-error.log");
}
set_time_limit(0);

my_log($_SERVER['REQUEST_METHOD']."\t".$_GET['serviceID']);

if(
$_GET['serviceID']) {
    
    
//Kodi will request this page 2 times
    
if($_SERVER['REQUEST_METHOD'] == "HEAD")//First request, change channel
    
{
        
//Kill VLC and wait for it to close
        
$pid exec("pgrep -o -x VLC");
        if(
$pid)
        {
            
exec("kill ".$pid);
            
exec("wait ".$pid);
        }
        
//Launch EyeTV if it's not running
        
$pid exec("pgrep -o -x EyeTV");
        if(!
$pid)
        {
            
exec("osascript eyetv-launch.scpt");
            
sleep(4);
        }

        
file_get_contents($EYETV_SERVICE."live/tuneto/1/320/".$_GET['serviceID']);

        
//Wait for the channel to change
        
$eyetv_ready false;
        
$retries 0;
        while(!
$eyetv_ready && $retries 10)
        {
            
sleep(1);
            
$gzip file_get_contents($EYETV_SERVICE."live/ready");
            
$json gzdecode($gzip);
            
$obj json_decode($json);
            
my_log("Waiting for EyeTV");
            
$eyetv_ready $obj->doneEncoding 0;
            
$retries++;
        }
        
//Start VLC streaming
        
exec($VLC_PATH." -I dummy eyetv:// --sout '#standard{access=http,mux=ts,dst=:".$VLC_PORT."}' > /dev/null 2>&1 & echo $!",$return);
        
$vlcpid $return[0];
        
//Wait for streaming to start
        
sleep(1);

        
header("HTTP/1.1 200 OK");
        
header("Content-Type: application/octet-stream");
        exit();
    }
    else  
//Second request, passthrough the video stream
    
{
        
header("HTTP/1.1 200 OK");
        
header("Content-Type: application/octet-stream");

        
//Poll EyeTV to keep the tuner alive
        
exec($PHP_PATH." eyetv-poll.php > /dev/null 2>&1 & echo $!",$return);
        
$pollpid $return[0];

        
//When connection is closed, stop polling EyeTV and kill VLC
        
function shutdown($pollpid)
        {
            
my_log("shutdown()");
            
exec("kill ".$pollpid);
            
exec("killall VLC");
        }
        
register_shutdown_function('shutdown',$pollpid);

        
//Passthrough the VLC stream
        
$file = @fopen("http://127.0.0.1:".$VLC_PORT,"rb");
        if(
$file)
        {
            
fpassthru($file);
            
fclose($file);
        } else {
            
my_log("no connection to stream");
        }

        
my_log("passthru aborted, trying again");
        
sleep(1);
        
$file = @fopen("http://127.0.0.1:".$VLC_PORT,"rb");
        if(
$file)
        {
            
fpassthru($file);
            
fclose($file);
        } else {
            
my_log("no connection to stream");
        }

        
my_log("abort");
    }


eyetv-poll.php
PHP Code:
<?php

include "eyetv-config.php";

set_time_limit(0);

//Sends requests to the EyeTV service every 5 seconds to keep the tuner alive
while(true) {
    
my_log("Polling EyeTV service");
    
file_get_contents($EYETV_SERVICE."live/ready");
    
sleep(5);


eyetv-playlist.php
PHP Code:
<?php

include "eyetv-config.php";

$channels_gzip file_get_contents($EYETV_SERVICE."live/channels");
$channels_json gzdecode($gzip);
$channels json_decode($json);

header("Content-Type: application/vnd.apple.mpegurl");

echo 
"#EXTM3U";

foreach (
$channels->channelList as $channel) {
    echo 
"\n\n";
    echo 
"#EXTINF:-1, ".$channel->name."\n";
    echo 
$STREAM_BASE_URL.$channel->serviceID;
}

echo 
"\n"

eyetv-launch.scpt
Code:
tell application "EyeTV"
    launch with server mode
end tell

Then, in the configuration for PVR IPTV Simple Client, set the m3u playlist to: http://localhost:8080/eyetv-playlist.m3u8 , and the XMLTV to your favorite service. It would be possible to export the EPG from EyeTV, but for my setup it's enough with an external XMLTV service.

Restart Kodi and you should then see all your EyeTV channels in the PVR interface! In uncompressed HD quality.

This setup works pretty flawless once it is set up. But to simplify the installation process and to enable recording and time shifting, someone could develop a native PVR add-on that could read directly from the EyeTV stream provided by the VLC plug-in. It seems like VLC is getting the video stream in MPEG format via a UNIX socket, according to the code available here: vlc/modules/access/eyetv.m
I have rewrote the entire thing in Node.JS so now it can be distributed as one compiled executable. No need to install MAMP or VLC. I will create a separate thread for this in a while. What I have here is a EyeTV to IPTV server that is very efficient and keep the speed of switching channels and the quality equal to the native EyeTV application.
https://github.com/simphax/eyetv-iptv-server