Skip to content

MarkusEh/vdr-plugin-dynamite

Repository files navigation

This is a "plugin" for the Video Disk Recorder (VDR).

Written by:                  Lars Hanisch <dvb@flensrocker.de>

Project's homepage:          http://projects.vdr-developer.org/projects/plg-dynamite

Latest version available at: git clone git://projects.vdr-developer.org/vdr-plugin-dynamite.git

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.
See the file COPYING for more information.

Description
-----------
This plugin turns the dvbdevices into hotpluggable devices. They
can be dynamically attached and detached while vdr is running.
Don't forget to patch the vdr-source, you find the necessary one
in the "patches" directory of the plugin sources.

How it works
------------
It creates as many devices as it can till the global vdr-device-array
is full. After this plugin is loaded every device created by a
plugin can't be used by vdr. So make sure dynamite is loaded as
the last plugin.

If a device is dynamically attached to vdr, this plugin creates an
instance of the corresponding cDevice-subclass and plugs it into
a free "dumb device" mentioned above. Now this device can do
everything its subdevice can do.

If a device is detached the corresponding subdevice is deleted and
the "dumb device" is dumb again.

A device with receivers at priorities > 0 can't be detached.

How to make other plugins "explosive"
-------------------------------------
Like cDvbDeviceProbe there is a list of probe-objects where a plugin
can hook into (see cDynamicDeviceProbe at the end of patched device.h).
The Probe-function gets an devicepath and if the plugin can handle
this it returns a pointer to a new created device on the heap.
Don't forget to pass through the "ParentDevice" parameter to the cDevice
constructor!

You don't need to remember this pointer, it will be deleted by dynamite.
The devicepath doesn't need to be a valid path like
/dev/dvb/adapter0/frontend0 or /dev/video0 etc. since the plugin decides
what it should do with this string. In dynamite.c you can see an example
of an dynamic dummy device creator. It reacts on the devicepath
"dummydevice" followed by a number e.g. "dummydevice0".

If a plugin wants its device to be dynamically attached/detached it must
not create its devices in its Initialize function. Instead it should
queue the found devicepaths with the helper function
"cDynamicDeviceProbe::QueueDynamicDeviceCommand(ddpcAttach, devpath)".
After initialization the dynamite-plugin is calling every cDynamicDeviceProbe
with the queued devicepaths in its Initialize-function. See the patches
directory for examples.

The devices have to close all their handles in their destructor and clean
up after them. Otherwise this is a potential source of memory leaks.
Plugins which creates a cDvbDeviceProbe should replace it with a
cDynamicDeviceProbe (you can use "#ifdef __DYNAMIC_DEVICE_PROBE" for
conditional compiling).

If you're looking for an example grab the source of pvrinput from:
http://projects.vdr-developer.org/projects/plg-pvrinput

How to attach/detach a device
-----------------------------
There a some new SVDRP commands for the dynamic devices. The string in quotes
above the command is for the internal Service-interface of the vdr-plugins.

"dynamite-AttachDevice-v0.1"
ATTD devicepath
    Asks all cDynamicDeviceProbe-objects to attach the given devicepath
    till one returns a valid pointer. You can control the order by the
    order of the plugins you load
    alternate command: AttachDevice

"dynamite-DetachDevice-v0.1"
DETD devicepath
    Looks through its remembered devicepaths and deletes the attached
    device if found. Case is important!
    Any timeouts or locks set to this slot will be reset to its defaults.
    alternate command: DetachDevice

"dynamite-ForceDetachDevice-v0.1"
FDTD devpath
    Looks through its remembered devicepaths and deletes the attached
    device if found. Case is important!
    The device will be detached regardless of recordings or other locks!
    This is useful for unplugged usb-sticks etc.
    alternate command: ForceDetachDevice

"dynamite-DetachAllDevices-v0.1"
DTAD [force]
    detachs all attached devices
    "force" will ignore recordings and other receivers
    alternate command: DetachAllDevices

"dynamite-ScanDevices-v0.1"
SCND '/dev/path/glob*/pattern*'
    Scan filesystem with pattern and try to attach each found device
    don't forget to enclose the pattern with single quotes
    e.g. SCND '/dev/dvb/adapter*/frontend*'
    alternate command: ScanDevices

"dynamite-LockDevice-v0.1"
LCKD /dev/path/to/device
    Lock the device so it can't be detached
    alternate command: LockDevice

"dynamite-UnlockDevice-v0.1"
UNLD /dev/path/to/device
    Remove the lock of the device so it can be detached
    alternate command: UnlockDevice

"dynamite-SetIdle-v0.1"
SetIdle /dev/path/to/device
    Try to set the device to idle so it won't be used by epg-scan
    and can close all its handles

"dynamite-SetNotIdle-v0.1"
SetNotIdle /dev/path/to/device
    Revoke the idle state of the device

"dynamite-DisableAutoIdle-v0.1"
DisableAutoIdle /dev/path/to/device
    Disables the auto-idle feature on this device

"dynamite-EnableAutoIdle-v0.1"
EnableAutoIdle /dev/path/to/device
    Enables the auto-idle feature on this device if the timeout configured

(no Service-interface)
LSTD
    Lists all devices managed by this plugin. The first column is an id,
    the second column is the devicepath passed with ATTD
    The id can be used with the DETD and UNLD commands instead of the path.
    An asterisk behind the id means that this device is locked and
    can't be detached.
    alternate command: ListDevices

"dynamite-SetGetTSTimeout-v0.1"
SGTT /dev/path/to/device seconds
    Sets the \"GetTSPacket\"-watchdog timeout to specified amount of seconds
    If the device returns no data (Data == NULL) for this period of time,
    the device will be detached. Usefull if you want to reload the driver etc.
    A value of 0 seconds disables the watchdog.
    alternate command: SetGetTSTimeout

"dynamite-SetDefaultGetTSTimeout-v0.1"
SDGT seconds
    Sets the \"GetTSPacket\"-watchdog timeout for all attached devices
    and all devices that will be attached.
    alternate command: SetDefaultGetTSTimeout

"dynamite-AddUdevMonitor-v0.1"
ADUM subsystem begin-of-devnode
    Adds a filter to the udev-monitor.
    If an event occurs whose devnode starts with the supplied parameter
    this devnode will be queued for attaching, e.g.
    AddUdevMonitor video4linux /dev/video
    (this is what pvrinput uses)
    alternate command: AddUdevMonitor

"dynamite-SetGetTSTimeoutHandlerArg-v0.1"
SetGetTSTimeoutHandlerArg /dev/path/to/device arg
    Sets the argument for the timout handler program.

"dynamite-CallGetTSTimeoutHandler-v0.1"
CallGetTSTimeoutHandler arg
    Calls the timout handler program with the given arguments.

"dynamite-SetIdleTimeout-v0.1"
SIDT minutes
    Sets the timeout for an used device to be switched into idle mode,
    a value of 0 will deactivate the auto-idle-mode.
    alternate command: SetIdleTimeout

"dynamite-SetIdleWakeup-v0.1"
SIDW hours
    Sets the timeout for an idle device to be reactivated,
    a lower interval than 1 hour is not possible.
    alternate command: SetIdleWakeup

Don't forget to prefix them with "plug dynamite"...

Controlling dynamite with the OSD
---------------------------------
The main menu item "dynamite" offers the following possibilities:
- list attached devices
- scan for new DVB devices
- detach device
- lock/unlock device
- disable/enable auto-idle of device
- switch device to idle

Signals emitted via cPluginManager::CallAllServices
---------------------------------------------------
On some actions dynamite calls the Service interface of every plugin
so other plugins can react on these.

On attaching a device:
"dynamite-event-DeviceAttached-v0.1" /dev/path/to/device

On detaching a device:
"dynamite-event-DeviceDetached-v0.1" /dev/path/to/device

Parameters in setup.conf
------------------------
dynamite.DefaultGetTSTimeout = 0
dynamite.GetTSTimeoutHandler = /path/to/program
dynamite.FreeDeviceSlots = 0
dynamite.AttachHook = /path/to/program
dynamite.IdleHook = /path/to/program
dynamite.IdleTimeout = 0
dynamite.IdleWakeup = 0

Commandline Arguments
---------------------
-u, --log-udev
        log all udev events to syslog (useful for diagnostics)
-d, --dummy-probe
        start dummy-device probe (useful for experiments)
-t, --GetTSTimeout=n
        set default GetTS-timeout to n seconds
-h, --GetTSTimeoutHandler=/path/to/program
        set program to be called on GetTS-timeout
-f, --free-device-slots=n
        leave n slots free for non-dynamic devices of
        incompatible plugins
-a, --attach-hook=/path/to/program
        set program to be called on device attach/detach
-i, --idle-hook=/path/to/program
        set program to be called on SetIdle and reactivation
-I, --idle-timeout=m
        DEPRECATED if a device is unused for m minutes set it to idle, 0 disables auto-idle (default)
-W, --idle-wakeup=h
        DEPRECATED if a device is idle for h hours wake it up (e.g. for EPG scan)

Attach hook
-----------
If you want 'special action' taken after a device is attached or detached
to vdr you can specify a program either with the commandline parameter
"--attach-hook=/path/to/program" or with an entry in the setup.conf
dynamite.AttachHook = /path/to/program
It will be called with the parameter "--action=[attach|detach] --device=/dev/path".

Idle mode
---------
A device with no active receiver can be set to "idle". Classes derived
from cDevice shall try to close all resources like filehandles in the
method SetIdleDevice. E.g. cDvbDevice will close its frontend so the driver
can enable a power-save mode. And it has been observed that some tuners are
a lot cooler, so it must be good. :-)
An idle device will be ignored by the EIT scanner but will be reactivated
if it's needed for a recording etc.
You can set a programm to be called on every idle-switch. It will receive
the parameters
  --idle=[on|off]
  --device=/dev/path/to/device

If you have set an idle-timeout and idle-wakeup value greater than 0, dynamite
will try to deactivate unused devices on its own. In sporadic intervals it will
test all devices if their "CloseDvr" was last called "idle-minutes" ago (or
OpenDvr got called at all).
After a minimum of "idle-wakeup" hours the device will be reactivated so it can
be used by the EIT scanner or similar modules. The wakeup cannot be disabled,
only a minimum of one hour can be specified.
If there are problems with the auto-idle mode on some devices but you want to use
it on your other devices you can disable it per device via "Service", SVDRP or
udev (see below).

"GetTS" watchdog
----------------
Some DVB cards are known to be unstable - sometimes their driver just hangs
and vdr won't get any data anymore. Mostly you have to stop vdr, reload the
drivers and restart vdr again. But that would affect other recordings etc.
If you have such a card the "Auto-Detach" feature may be useful. Just set
the "GetTS" timeout to 10 or 15 seconds (or whatever you like) and dynamite
will automatically detach this device if its GetTSPacket method returns
no data for this period of time.
WARNING: You have to attach this device manually again! For now there's no
automatism to reload the driver (or whatever is needed) to reanimate the device.
You can use the GetTSTimeoutHandler set in setup.conf for this.

If you want to add a timeout only to specific devices you can do this with udev.
Add a rule which sets with ENV{dynamite_timeout}="10" the needed timeout value.

example for udev rule:
ACTION=="add", SUBSYSTEM=="dvb", ENV{DVB_DEVICE_TYPE}=="frontend" \
  , ENV{dynamite_attach}="yes" \
  , ENV{dynamite_attach_delay}="10" \
  , ENV{dynamite_attach_delay_preopen}="yes" \
  , ENV{dynamite_instanceid}="0" \
  , ENV{dynamite_cardindex}="5" \
  , ENV{dynamite_sources}="C,T" \
  , ENV{dynamite_timeout}="10" \
  , ENV{dynamite_timeout_handler_arg}="%k" \
  , ENV{dynamite_disable_autoidle}="no"

After the device is detached and dynamite.GetTSTimeoutHandler in setup.conf is set
to a path, this program is called. If the udev-property "dynamite_timeout_handler_arg"
is not present the devpath is provided as argument, with which the device was attached.

Udev Properties
---------------
Attaching of devices can be controlled with some udev device properties which can be
set by a udev rule (see example above).

dynamite_attach
    "no", "n", "0", "ignore": don't attach this device, any other string will be like "yes"

dynamite_attach_delay
    n: wait with attaching this device at least n seconds

dynamite_attach_delay_preopen
    "yes", "y", "1": If an attach_delay is specified, dynamite will open the given path
                     before the delay (O_RDWR | O_NONBLOCK) to trigger the load of the firmware.
                     It will be closed immediately and reopened when it's attached.
                     Useful for "bad" usb-box-drivers.

dynamite_instanceid
    n: attach only at vdr with matching instance id

dynamite_cardindex
    n: if possible attach at slot with given cardindex
       if no cardindex is given, the adapter number will be used (see "Known issues")

dynamite_disable_autoidle
    "yes", "y", "disable", "true", "1": disable the auto-idle feature on this device, any other
                                        string or missing of this property will activate the
                                        auto-idle feature if configured

dynamite_sources
    comma separated list of strings from sources.conf
    dynamite will deny all channels from other sources for the subdevice.
    If this variable is missing the subdevice is asked as usual.
    This is useful for hybrid devices which supports multiple delivery systems
    but only one is connected. Or if you have to dishes to different satellites
    connected to two cards.
    It will NOT switch the delivery system on dvb-cards, this is up to the device itself!

dynamite_timeout
    n: set GetTS timeout in seconds on this device

dynamite_timeout_handler_arg
    string: set a argument passed through to the auto-detach script

Known issues
------------
If a device managed by this plugin is the primary device it cannot be
detached. That would imply that vdr searches for a new primary device
or should be forced to transfer mode or something else. Since I don't
know anything about this you have to wait for this feature or teach
me how to do this...

The "no cardindex given" default mechanism doesn't count frontends with
numbers > 0. Make sure you have one frontend per adapter.

TODO
----
...