Skip to content

IPTV Tuner Driver

Overview

The IPTV tuner driver enables ingestion of IPTV streams via M3U playlists and optional XMLTV guide data (EPG). It makes IPTV streams available alongside HDHomeRun/DVB-T tuners in the unified LiveTvManager pipeline.

Architecture

LiveTvManager
├── HdHomeRunTunerDriver (SSDP discovery + HTTP API)
└── IptvTunerDriver (M3U playlist + XMLTV)
    ├── M3UParser (parses #EXTINF entries)
    ├── XmlTvParser (parses <programme> elements)
    ├── IptvDevice (source descriptor)
    └── IptvTunerDriverFactory (builds from config)

M3U Playlist Format

The driver supports extended M3U format with #EXTINF tags:

#EXTM3U
#EXTINF:-1 tvg-id="1" tvg-name="Channel Name" tvg-chno="5" group-title="News",Channel Name
http://example.com/stream.m3u8
#EXTINF:-1 radio="1" tvg-id="2" tvg-name="Radio FM" tvg-chno="100",Radio FM
http://example.com/radio.m3u8

Supported Attributes

AttributeDescriptionExample
tvg-idUnique channel identifiertvg-id="123"
tvg-nameChannel display nametvg-name="BBC One"
tvg-chnoChannel numbertvg-chno="1"
group-titleChannel category/groupgroup-title="News"
tvg-logoChannel logo URLtvg-logo="https://..."
radioRadio channel flagradio="1"

XMLTV Format

The driver parses XMLTV-ng format for programme guide data:

xml
<?xml version="1.0" encoding="UTF-8"?>
<tv>
  <programme channel="bbc_one" start="20240101180000" stop="20240101200000">
    <title>Doctor Who</title>
    <desc>The Doctor returns.</desc>
    <category>Science Fiction</category>
    <episode-num system="onscreen">S01E05</episode-num>
    <rating>
      <value>TV-PG</value>
    </rating>
    <date>20240101</date>
  </programme>
</tv>

Time Format

XMLTV uses YYYYMMDDHHMMSS format with optional timezone offset:

  • 20240101120000 - No timezone (UTC assumed)
  • 20240101120000 +0000 - UTC
  • 20240101120000 -0500 - EST

Configuration

Add IPTV sources to config/livetv.php:

php
'livetv' => [
    // ... existing hdhomerun config ...

    'iptv' => [
        'enabled' => true,
        'sources' => [
            [
                'name' => 'My IPTV',
                'playlist_url' => 'https://example.com/playlist.m3u8',
                'epg_url' => 'https://example.com/epg.xml',
            ],
            // Add more sources as needed
        ],
    ],
],

Class Reference

M3UEntry

Immutable value object for a single M3U playlist entry.

php
new M3UEntry(
    url: 'http://example.com/stream.m3u8',
    name: 'Channel Name',
    tvgId: 1,
    tvgChno: 5,
    group: 'News',
    logo: 'http://example.com/logo.png',
    isRadio: false
);

M3UParser

Parses M3U/M3U8 playlist files.

php
$parser = new M3UParser();

// Parse from string
$entries = $parser->parse($m3uContent);

// Fetch and parse from URL
$entries = $parser->parseUrl('https://example.com/playlist.m3u8');

XmlTvProgramme

Immutable value object for a programme entry.

php
new XmlTvProgramme(
    channelId: 'bbc_one',
    startTime: 1704124800,
    endTime: 1704132000,
    title: 'Doctor Who',
    description: 'The Doctor returns.',
    category: 'Science Fiction',
    episodeNum: 'S01E05',
    rating: 'TV-PG',
    year: 2024
);

XmlTvParser

Parses XMLTV format guide data.

php
$parser = new XmlTvParser();

// Parse from string
$programmes = $parser->parse($xmltvContent);

// Fetch and parse from URL
$programmes = $parser->parseUrl('https://example.com/epg.xml');

IptvDevice

Immutable descriptor for an IPTV source.

php
$device = new IptvDevice(
    sourceId: 'iptv_mysource',
    name: 'My IPTV Service',
    playlistUrl: 'https://example.com/playlist.m3u8',
    epgUrl: 'https://example.com/epg.xml',
    isEnabled: true
);

IptvTunerDriver

Implements TunerDriverInterface for IPTV streaming.

php
$driver = new IptvTunerDriver(
    new M3UParser(),
    new XmlTvParser(),
    $device
);

// Discover devices
$devices = $driver->discoverDevices();

// Get channel lineup
$lineup = $driver->getChannelLineup($device);

// Get stream URL for channel
$url = $driver->getStreamUrl($device, 5);

// Scan channels (also fetches EPG if configured)
$channels = $driver->scanChannels($device);

IptvTunerDriverFactory

Factory for creating drivers from configuration.

php
// Build single driver from first source
$driver = IptvTunerDriverFactory::build($config);

// Get all configured devices
$devices = IptvTunerDriverFactory::buildDevices($config);

Database Schema

The livetv_tuners table stores tuner information with type iptv:

ColumnTypeDescription
tuner_idVARCHAR(36)Unique identifier (e.g., iptv_mysource)
nameVARCHAR(255)Display name
typeVARCHAR(20)Tuner type (iptv, hdhomerun)
statusVARCHAR(20)Current status
capabilitiesJSONTuner capabilities
discovered_atDATETIMEDiscovery timestamp

Integration with LiveTvManager

LiveTvManager automatically discovers and registers IPTV tuners when configured:

php
// In your service provider or bootstrap
$livetvConfig = include 'config/livetv.php';

// Create IPTV driver if enabled
$iptvDriver = IptvTunerDriverFactory::build($livetvConfig, $logger);

// Create LiveTvManager with additional drivers
$manager = new LiveTvManager(
    $db,
    $channelManager,
    $guideManager,
    $recorder,
    $hdhomerunDriver,  // Primary driver
    $logger,
    [$iptvDriver]       // Additional drivers array
);

// Discover all tuners (both HDHomeRun and IPTV)
$tuners = $manager->discoverTuners();

EPG Matching

When GuideManager::upsertProgram() is called with xmltv_id, it can match programme entries to channels by their XMLTV channel ID:

php
$guideManager->upsertProgram([
    'channel_id' => 'ch_123',
    'xmltv_id' => 'bbc_one',  // Matches XMLTV programme channel
    'title' => 'Doctor Who',
    'start_time' => 1704124800,
    'end_time' => 1704132000,
]);

Error Handling

The driver handles common error cases:

  • Invalid M3U content: Returns empty array, logs warning
  • Invalid XMLTV content: Returns empty array, logs warning
  • Failed HTTP fetch: Throws RuntimeException with details
  • Channel not found: Falls back to index-based matching
  • No channels available: Throws RuntimeException

Testing

Run the IPTV tuner tests:

bash
./vendor/bin/phpunit tests/unit/LiveTv/Tuners/Iptv/

See Also

BSD-3-Clause