All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 0/4] Media Device Allocator API
@ 2019-01-24 20:32 Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 1/4] media: " Shuah Khan
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: Shuah Khan @ 2019-01-24 20:32 UTC (permalink / raw)
  To: mchehab, perex, tiwai, hverkuil
  Cc: Shuah Khan, linux-media, linux-kernel, alsa-devel

Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.

- This patch series is tested on 5.0-rc3 and addresses comments on
  v9 series from Hans Verkuil.
- v9 was tested on 4.20-rc6.
- Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
  arecord. When analog is streaming, digital and audio user-space
  applications detect that the tuner is busy and exit. When digital
  is streaming, analog and audio applications detect that the tuner is
  busy and exit. When arecord is owns the tuner, digital and analog
  detect that the tuner is busy and exit.
- Tested media device allocator API with bind/unbind testing on
  snd-usb-audio and au0828 drivers to make sure /dev/mediaX is released
  only when the last driver is unbound.
- Addressed review comments from Hans on the RFC v8 (rebased on 4.19)
- Updated change log to describe the use-case more clearly.
- No changes to 0001,0002 code since the v7 referenced below.
- 0003 is a new patch to enable ALSA defines that have been
  disabled for kernel between 4.9 and 4.19.
- Minor merge conflict resolution in 0004.
- Added SPDX to new files.

Changes since v9:
- Patch 1: Fix mutex assert warning from find_module() calls. This
  code was written before the change to find_module() that requires
  callers to hold module_mutex. I missed this during my testing on
  4.20-rc6. Hans Verkuil reported the problem.
- Patch 4: sound/usb: Initializes all the entities it can before
  registering the device based on comments from Hans Verkuil
- Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
- No changes to Patches 2 and 3.

References:
https://lkml.org/lkml/2018/11/2/169
https://www.mail-archive.com/linux-media@vger.kernel.org/msg105854.html

Shuah Khan (4):
  media: Media Device Allocator API
  media: change au0828 to use Media Device Allocator API
  media: media.h: Enable ALSA MEDIA_INTF_T* interface types
  sound/usb: Use Media Controller API to share media resources

 Documentation/media/kapi/mc-core.rst   |  41 ++++
 drivers/media/Makefile                 |   4 +
 drivers/media/media-dev-allocator.c    | 144 +++++++++++
 drivers/media/usb/au0828/au0828-core.c |  12 +-
 drivers/media/usb/au0828/au0828.h      |   1 +
 include/media/media-dev-allocator.h    |  53 ++++
 include/uapi/linux/media.h             |  25 +-
 sound/usb/Kconfig                      |   4 +
 sound/usb/Makefile                     |   2 +
 sound/usb/card.c                       |  14 ++
 sound/usb/card.h                       |   3 +
 sound/usb/media.c                      | 327 +++++++++++++++++++++++++
 sound/usb/media.h                      |  74 ++++++
 sound/usb/mixer.h                      |   3 +
 sound/usb/pcm.c                        |  29 ++-
 sound/usb/quirks-table.h               |   1 +
 sound/usb/stream.c                     |   2 +
 sound/usb/usbaudio.h                   |   6 +
 18 files changed, 723 insertions(+), 22 deletions(-)
 create mode 100644 drivers/media/media-dev-allocator.c
 create mode 100644 include/media/media-dev-allocator.h
 create mode 100644 sound/usb/media.c
 create mode 100644 sound/usb/media.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v10 1/4] media: Media Device Allocator API
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
@ 2019-01-24 20:32 ` Shuah Khan
  2019-01-25 15:38   ` Sakari Ailus
  2019-01-24 20:32 ` [PATCH v10 2/4] media: change au0828 to use " Shuah Khan
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: Shuah Khan @ 2019-01-24 20:32 UTC (permalink / raw)
  To: mchehab, perex, tiwai, hverkuil
  Cc: Shuah Khan, linux-media, linux-kernel, alsa-devel

Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.

Signed-off-by: Shuah Khan <shuah@kernel.org>
---
 Documentation/media/kapi/mc-core.rst |  41 ++++++++
 drivers/media/Makefile               |   4 +
 drivers/media/media-dev-allocator.c  | 144 +++++++++++++++++++++++++++
 include/media/media-dev-allocator.h  |  53 ++++++++++
 4 files changed, 242 insertions(+)
 create mode 100644 drivers/media/media-dev-allocator.c
 create mode 100644 include/media/media-dev-allocator.h

diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
index 0bcfeadbc52d..07f2a6a90af2 100644
--- a/Documentation/media/kapi/mc-core.rst
+++ b/Documentation/media/kapi/mc-core.rst
@@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific
 helper functions to provide easy access for commonly needed information, and
 in the end provide a way to use driver-specific callbacks.
 
+Media Controller Device Allocator API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the media device belongs to more than one driver, the shared media
+device is allocated with the shared struct device as the key for look ups.
+
+The shared media device should stay in registered state until the last
+driver unregisters it. In addition, the media device should be released when
+all the references are released. Each driver gets a reference to the media
+device during probe, when it allocates the media device. If media device is
+already allocated, the allocate API bumps up the refcount and returns the
+existing media device. The driver puts the reference back in its disconnect
+routine when it calls :c:func:`media_device_delete()`.
+
+The media device is unregistered and cleaned up from the kref put handler to
+ensure that the media device stays in registered state until the last driver
+unregisters the media device.
+
+**Driver Usage**
+
+Drivers should use the appropriate media-core routines to manage the shared
+media device life-time handling the two states:
+1. allocate -> register -> delete
+2. get reference to already registered device -> delete
+
+call :c:func:`media_device_delete()` routine to make sure the shared media
+device delete is handled correctly.
+
+**driver probe:**
+Call :c:func:`media_device_usb_allocate()` to allocate or get a reference
+Call :c:func:`media_device_register()`, if media devnode isn't registered
+
+**driver disconnect:**
+Call :c:func:`media_device_delete()` to free the media_device. Freeing is
+handled by the kref put handler.
+
+API Definitions
+^^^^^^^^^^^^^^^
+
 .. kernel-doc:: include/media/media-device.h
 
 .. kernel-doc:: include/media/media-devnode.h
@@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks.
 .. kernel-doc:: include/media/media-entity.h
 
 .. kernel-doc:: include/media/media-request.h
+
+.. kernel-doc:: include/media/media-dev-allocator.h
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 985d35ec6b29..1d7653318af6 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -6,6 +6,10 @@
 media-objs	:= media-device.o media-devnode.o media-entity.o \
 		   media-request.o
 
+ifeq ($(CONFIG_USB),y)
+	media-objs += media-dev-allocator.o
+endif
+
 #
 # I2C drivers should come before other drivers, otherwise they'll fail
 # when compiled as builtin drivers
diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c
new file mode 100644
index 000000000000..4606456c1e86
--- /dev/null
+++ b/drivers/media/media-dev-allocator.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * media-dev-allocator.c - Media Controller Device Allocator API
+ *
+ * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
+ *
+ * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+/*
+ * This file adds a global refcounted Media Controller Device Instance API.
+ * A system wide global media device list is managed and each media device
+ * includes a kref count. The last put on the media device releases the media
+ * device instance.
+ *
+ */
+
+#include <linux/kref.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/media-device.h>
+
+static LIST_HEAD(media_device_list);
+static DEFINE_MUTEX(media_device_lock);
+
+struct media_device_instance {
+	struct media_device mdev;
+	struct module *owner;
+	struct list_head list;
+	struct kref refcount;
+};
+
+static inline struct media_device_instance *
+to_media_device_instance(struct media_device *mdev)
+{
+	return container_of(mdev, struct media_device_instance, mdev);
+}
+
+static void media_device_instance_release(struct kref *kref)
+{
+	struct media_device_instance *mdi =
+		container_of(kref, struct media_device_instance, refcount);
+
+	dev_dbg(mdi->mdev.dev, "%s: mdev=%p\n", __func__, &mdi->mdev);
+
+	mutex_lock(&media_device_lock);
+
+	media_device_unregister(&mdi->mdev);
+	media_device_cleanup(&mdi->mdev);
+
+	list_del(&mdi->list);
+	mutex_unlock(&media_device_lock);
+
+	kfree(mdi);
+}
+
+/* Callers should hold media_device_lock when calling this function */
+static struct media_device *__media_device_get(struct device *dev,
+						const char *module_name,
+						struct module *modp)
+{
+	struct media_device_instance *mdi;
+
+	list_for_each_entry(mdi, &media_device_list, list) {
+
+		if (mdi->mdev.dev != dev)
+			continue;
+
+		kref_get(&mdi->refcount);
+
+		/* get module reference for the media_device owner */
+		if (modp != mdi->owner && !try_module_get(mdi->owner))
+			dev_err(dev, "%s: try_module_get() error\n", __func__);
+		dev_dbg(dev, "%s: get mdev=%p module_name %s\n",
+			__func__, &mdi->mdev, module_name);
+		return &mdi->mdev;
+	}
+
+	mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
+	if (!mdi)
+		return NULL;
+
+	mdi->owner = modp;
+	kref_init(&mdi->refcount);
+	list_add_tail(&mdi->list, &media_device_list);
+
+	dev_dbg(dev, "%s: alloc mdev=%p module_name %s\n", __func__,
+		&mdi->mdev, module_name);
+	return &mdi->mdev;
+}
+
+#if IS_ENABLED(CONFIG_USB)
+struct media_device *media_device_usb_allocate(struct usb_device *udev,
+					       const char *module_name)
+{
+	struct media_device *mdev;
+	struct module *modptr;
+
+	mutex_lock(&module_mutex);
+	modptr = find_module(module_name);
+	mutex_unlock(&module_mutex);
+
+	mutex_lock(&media_device_lock);
+	mdev = __media_device_get(&udev->dev, module_name, modptr);
+	if (!mdev) {
+		mutex_unlock(&media_device_lock);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* check if media device is already initialized */
+	if (!mdev->dev)
+		__media_device_usb_init(mdev, udev, udev->product,
+					module_name);
+	mutex_unlock(&media_device_lock);
+	return mdev;
+}
+EXPORT_SYMBOL_GPL(media_device_usb_allocate);
+#endif
+
+void media_device_delete(struct media_device *mdev, const char *module_name)
+{
+	struct media_device_instance *mdi = to_media_device_instance(mdev);
+	struct module *modptr;
+
+	dev_dbg(mdi->mdev.dev, "%s: mdev=%p module_name %s\n",
+		__func__, &mdi->mdev, module_name);
+
+	mutex_lock(&module_mutex);
+	modptr = find_module(module_name);
+	mutex_unlock(&module_mutex);
+
+	mutex_lock(&media_device_lock);
+	/* put module reference if media_device owner is not THIS_MODULE */
+	if (mdi->owner != modptr) {
+		module_put(mdi->owner);
+		dev_dbg(mdi->mdev.dev,
+			"%s decremented owner module reference\n", __func__);
+	}
+	mutex_unlock(&media_device_lock);
+	kref_put(&mdi->refcount, media_device_instance_release);
+}
+EXPORT_SYMBOL_GPL(media_device_delete);
diff --git a/include/media/media-dev-allocator.h b/include/media/media-dev-allocator.h
new file mode 100644
index 000000000000..9164795e911c
--- /dev/null
+++ b/include/media/media-dev-allocator.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * media-dev-allocator.h - Media Controller Device Allocator API
+ *
+ * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
+ *
+ * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+/*
+ * This file adds a global ref-counted Media Controller Device Instance API.
+ * A system wide global media device list is managed and each media device
+ * includes a kref count. The last put on the media device releases the media
+ * device instance.
+ */
+
+#ifndef _MEDIA_DEV_ALLOCTOR_H
+#define _MEDIA_DEV_ALLOCTOR_H
+
+struct usb_device;
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_USB)
+/**
+ * media_device_usb_allocate() - Allocate and return struct &media device
+ *
+ * @udev:		struct &usb_device pointer
+ * @module_name:	should be filled with %KBUILD_MODNAME
+ *
+ * This interface should be called to allocate a Media Device when multiple
+ * drivers share usb_device and the media device. This interface allocates
+ * &media_device structure and calls media_device_usb_init() to initialize
+ * it.
+ *
+ */
+struct media_device *media_device_usb_allocate(struct usb_device *udev,
+					       char *module_name);
+/**
+ * media_device_delete() - Release media device. Calls kref_put().
+ *
+ * @mdev:		struct &media_device pointer
+ * @module_name:	should be filled with %KBUILD_MODNAME
+ *
+ * This interface should be called to put Media Device Instance kref.
+ */
+void media_device_delete(struct media_device *mdev, char *module_name);
+#else
+static inline struct media_device *media_device_usb_allocate(
+			struct usb_device *udev, char *module_name)
+			{ return NULL; }
+static inline void media_device_delete(
+			struct media_device *mdev, char *module_name) { }
+#endif /* CONFIG_MEDIA_CONTROLLER */
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v10 2/4] media: change au0828 to use Media Device Allocator API
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 1/4] media: " Shuah Khan
@ 2019-01-24 20:32 ` Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 3/4] media: media.h: Enable ALSA MEDIA_INTF_T* interface types Shuah Khan
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Shuah Khan @ 2019-01-24 20:32 UTC (permalink / raw)
  To: mchehab, perex, tiwai, hverkuil
  Cc: Shuah Khan, linux-media, linux-kernel, alsa-devel

Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.

Change au0828 to use Media Device Allocator API to allocate media device
with the parent usb struct device as the key, so it can be shared with the
snd_usb_audio driver.

Signed-off-by: Shuah Khan <shuah@kernel.org>
---
 drivers/media/usb/au0828/au0828-core.c | 12 ++++--------
 drivers/media/usb/au0828/au0828.h      |  1 +
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 1fdb1601dc65..4b0a395d59aa 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -155,9 +155,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
 	dev->media_dev->disable_source = NULL;
 	mutex_unlock(&mdev->graph_mutex);
 
-	media_device_unregister(dev->media_dev);
-	media_device_cleanup(dev->media_dev);
-	kfree(dev->media_dev);
+	media_device_delete(dev->media_dev, KBUILD_MODNAME);
 	dev->media_dev = NULL;
 #endif
 }
@@ -210,14 +208,10 @@ static int au0828_media_device_init(struct au0828_dev *dev,
 #ifdef CONFIG_MEDIA_CONTROLLER
 	struct media_device *mdev;
 
-	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+	mdev = media_device_usb_allocate(udev, KBUILD_MODNAME);
 	if (!mdev)
 		return -ENOMEM;
 
-	/* check if media device is already initialized */
-	if (!mdev->dev)
-		media_device_usb_init(mdev, udev, udev->product);
-
 	dev->media_dev = mdev;
 #endif
 	return 0;
@@ -480,6 +474,8 @@ static int au0828_media_device_register(struct au0828_dev *dev,
 		/* register media device */
 		ret = media_device_register(dev->media_dev);
 		if (ret) {
+			media_device_delete(dev->media_dev, KBUILD_MODNAME);
+			dev->media_dev = NULL;
 			dev_err(&udev->dev,
 				"Media Device Register Error: %d\n", ret);
 			return ret;
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 004eadef55c7..7dbe3db15ebe 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -31,6 +31,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
 #include <media/media-device.h>
+#include <media/media-dev-allocator.h>
 
 /* DVB */
 #include <media/demux.h>
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v10 3/4] media: media.h: Enable ALSA MEDIA_INTF_T* interface types
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 1/4] media: " Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 2/4] media: change au0828 to use " Shuah Khan
@ 2019-01-24 20:32 ` Shuah Khan
  2019-01-24 20:32 ` [PATCH v10 4/4] sound/usb: Use Media Controller API to share media resources Shuah Khan
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Shuah Khan @ 2019-01-24 20:32 UTC (permalink / raw)
  To: mchehab, perex, tiwai, hverkuil
  Cc: Shuah Khan, linux-media, linux-kernel, alsa-devel

Move PCM_CAPTURE, PCM_PLAYBACK, and CONTROL ALSA MEDIA_INTF_T* interface
types back into __KERNEL__ scope to get ready for adding ALSA support for
these to the media controller.

Signed-off-by: Shuah Khan <shuah@kernel.org>
---
 include/uapi/linux/media.h | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index e5d0c5c611b5..9aedb187bc48 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -262,6 +262,11 @@ struct media_links_enum {
 #define MEDIA_INTF_T_V4L_SWRADIO		(MEDIA_INTF_T_V4L_BASE + 4)
 #define MEDIA_INTF_T_V4L_TOUCH			(MEDIA_INTF_T_V4L_BASE + 5)
 
+#define MEDIA_INTF_T_ALSA_BASE			0x00000300
+#define MEDIA_INTF_T_ALSA_PCM_CAPTURE		(MEDIA_INTF_T_ALSA_BASE)
+#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK		(MEDIA_INTF_T_ALSA_BASE + 1)
+#define MEDIA_INTF_T_ALSA_CONTROL		(MEDIA_INTF_T_ALSA_BASE + 2)
+
 #if defined(__KERNEL__)
 
 /*
@@ -413,19 +418,19 @@ struct media_v2_topology {
 #define MEDIA_ENT_F_DTV_DECODER			MEDIA_ENT_F_DV_DECODER
 
 /*
- * There is still no ALSA support in the media controller. These
+ * There is still no full ALSA support in the media controller. These
  * defines should not have been added and we leave them here only
  * in case some application tries to use these defines.
+ *
+ * The ALSA defines that are in use have been moved into __KERNEL__
+ * scope. As support gets added to these interface types, they should
+ * be moved into __KERNEL__ scope with the code that uses them.
  */
-#define MEDIA_INTF_T_ALSA_BASE			0x00000300
-#define MEDIA_INTF_T_ALSA_PCM_CAPTURE		(MEDIA_INTF_T_ALSA_BASE)
-#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK		(MEDIA_INTF_T_ALSA_BASE + 1)
-#define MEDIA_INTF_T_ALSA_CONTROL		(MEDIA_INTF_T_ALSA_BASE + 2)
-#define MEDIA_INTF_T_ALSA_COMPRESS		(MEDIA_INTF_T_ALSA_BASE + 3)
-#define MEDIA_INTF_T_ALSA_RAWMIDI		(MEDIA_INTF_T_ALSA_BASE + 4)
-#define MEDIA_INTF_T_ALSA_HWDEP			(MEDIA_INTF_T_ALSA_BASE + 5)
-#define MEDIA_INTF_T_ALSA_SEQUENCER		(MEDIA_INTF_T_ALSA_BASE + 6)
-#define MEDIA_INTF_T_ALSA_TIMER			(MEDIA_INTF_T_ALSA_BASE + 7)
+#define MEDIA_INTF_T_ALSA_COMPRESS             (MEDIA_INTF_T_ALSA_BASE + 3)
+#define MEDIA_INTF_T_ALSA_RAWMIDI              (MEDIA_INTF_T_ALSA_BASE + 4)
+#define MEDIA_INTF_T_ALSA_HWDEP                (MEDIA_INTF_T_ALSA_BASE + 5)
+#define MEDIA_INTF_T_ALSA_SEQUENCER            (MEDIA_INTF_T_ALSA_BASE + 6)
+#define MEDIA_INTF_T_ALSA_TIMER                (MEDIA_INTF_T_ALSA_BASE + 7)
 
 /* Obsolete symbol for media_version, no longer used in the kernel */
 #define MEDIA_API_VERSION			((0 << 16) | (1 << 8) | 0)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v10 4/4] sound/usb: Use Media Controller API to share media resources
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
                   ` (2 preceding siblings ...)
  2019-01-24 20:32 ` [PATCH v10 3/4] media: media.h: Enable ALSA MEDIA_INTF_T* interface types Shuah Khan
@ 2019-01-24 20:32 ` Shuah Khan
  2019-01-25 15:28   ` Sakari Ailus
  2019-01-28 12:03 ` Hans Verkuil
  5 siblings, 0 replies; 23+ messages in thread
From: Shuah Khan @ 2019-01-24 20:32 UTC (permalink / raw)
  To: mchehab, perex, tiwai, hverkuil
  Cc: Shuah Khan, linux-media, linux-kernel, alsa-devel

Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.

Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.

Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.

The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.

snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.

Media specific cleanup is done in usb_audio_disconnect().

Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
---
 sound/usb/Kconfig        |   4 +
 sound/usb/Makefile       |   2 +
 sound/usb/card.c         |  14 ++
 sound/usb/card.h         |   3 +
 sound/usb/media.c        | 327 +++++++++++++++++++++++++++++++++++++++
 sound/usb/media.h        |  74 +++++++++
 sound/usb/mixer.h        |   3 +
 sound/usb/pcm.c          |  29 +++-
 sound/usb/quirks-table.h |   1 +
 sound/usb/stream.c       |   2 +
 sound/usb/usbaudio.h     |   6 +
 11 files changed, 461 insertions(+), 4 deletions(-)
 create mode 100644 sound/usb/media.c
 create mode 100644 sound/usb/media.h

diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index f61b5662bb89..6319b544ba3a 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -15,6 +15,7 @@ config SND_USB_AUDIO
 	select SND_RAWMIDI
 	select SND_PCM
 	select BITREVERSE
+	select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO)
 	help
 	  Say Y here to include support for USB audio and USB MIDI
 	  devices.
@@ -22,6 +23,9 @@ config SND_USB_AUDIO
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-usb-audio.
 
+config SND_USB_AUDIO_USE_MEDIA_CONTROLLER
+	bool
+
 config SND_USB_UA101
 	tristate "Edirol UA-101/UA-1000 driver"
 	select SND_PCM
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index d330f74c90e6..e1ce257ab705 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -18,6 +18,8 @@ snd-usb-audio-objs := 	card.o \
 			quirks.o \
 			stream.o
 
+snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
+
 snd-usbmidi-lib-objs := midi.o
 
 # Toplevel Module Dependency
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 746a72e23cf9..cc6b23e282ec 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -68,6 +68,7 @@
 #include "format.h"
 #include "power.h"
 #include "stream.h"
+#include "media.h"
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("USB Audio");
@@ -673,6 +674,11 @@ static int usb_audio_probe(struct usb_interface *intf,
 	if (err < 0)
 		goto __error;
 
+	if (quirk && quirk->shares_media_device) {
+		/* don't want to fail when snd_media_device_create() fails */
+		snd_media_device_create(chip, intf);
+	}
+
 	usb_chip[chip->index] = chip;
 	chip->num_interfaces++;
 	usb_set_intfdata(intf, chip);
@@ -732,6 +738,14 @@ static void usb_audio_disconnect(struct usb_interface *intf)
 		list_for_each(p, &chip->midi_list) {
 			snd_usbmidi_disconnect(p);
 		}
+		/*
+		 * Nice to check quirk && quirk->shares_media_device and
+		 * then call the snd_media_device_delete(). Don't have
+		 * access to the quirk here. snd_media_device_delete()
+		 * accesses mixer_list
+		 */
+		snd_media_device_delete(chip);
+
 		/* release mixer resources */
 		list_for_each_entry(mixer, &chip->mixer_list, list) {
 			snd_usb_mixer_disconnect(mixer);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ac785d15ced4..5dd3538ed6b5 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -108,6 +108,8 @@ struct snd_usb_endpoint {
 	struct list_head list;
 };
 
+struct media_ctl;
+
 struct snd_usb_substream {
 	struct snd_usb_stream *stream;
 	struct usb_device *dev;
@@ -160,6 +162,7 @@ struct snd_usb_substream {
 	} dsd_dop;
 
 	bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
+	struct media_ctl *media_ctl;
 };
 
 struct snd_usb_stream {
diff --git a/sound/usb/media.c b/sound/usb/media.c
new file mode 100644
index 000000000000..c657ed45a703
--- /dev/null
+++ b/sound/usb/media.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * media.c - Media Controller specific ALSA driver code
+ *
+ * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
+ *
+ */
+
+/*
+ * This file adds Media Controller support to the ALSA driver
+ * to use the Media Controller API to share the tuner with DVB
+ * and V4L2 drivers that control the media device.
+ *
+ * The media device is created based on the existing quirks framework.
+ * Using this approach, the media controller API usage can be added for
+ * a specific device.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <sound/pcm.h>
+#include <sound/core.h>
+
+#include "usbaudio.h"
+#include "card.h"
+#include "mixer.h"
+#include "media.h"
+
+int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
+			  int stream)
+{
+	struct media_device *mdev;
+	struct media_ctl *mctl;
+	struct device *pcm_dev = &pcm->streams[stream].dev;
+	u32 intf_type;
+	int ret = 0;
+	u16 mixer_pad;
+	struct media_entity *entity;
+
+	mdev = subs->stream->chip->media_dev;
+	if (!mdev)
+		return 0;
+
+	if (subs->media_ctl)
+		return 0;
+
+	/* allocate media_ctl */
+	mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
+	if (!mctl)
+		return -ENOMEM;
+
+	mctl->media_dev = mdev;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK;
+		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK;
+		mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE;
+		mixer_pad = 1;
+	} else {
+		intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE;
+		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE;
+		mctl->media_pad.flags = MEDIA_PAD_FL_SINK;
+		mixer_pad = 2;
+	}
+	mctl->media_entity.name = pcm->name;
+	media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad);
+	ret =  media_device_register_entity(mctl->media_dev,
+					    &mctl->media_entity);
+	if (ret)
+		goto free_mctl;
+
+	mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
+						  MAJOR(pcm_dev->devt),
+						  MINOR(pcm_dev->devt));
+	if (!mctl->intf_devnode) {
+		ret = -ENOMEM;
+		goto unregister_entity;
+	}
+	mctl->intf_link = media_create_intf_link(&mctl->media_entity,
+						 &mctl->intf_devnode->intf,
+						 MEDIA_LNK_FL_ENABLED);
+	if (!mctl->intf_link) {
+		ret = -ENOMEM;
+		goto devnode_remove;
+	}
+
+	/* create link between mixer and audio */
+	media_device_for_each_entity(entity, mdev) {
+		switch (entity->function) {
+		case MEDIA_ENT_F_AUDIO_MIXER:
+			ret = media_create_pad_link(entity, mixer_pad,
+						    &mctl->media_entity, 0,
+						    MEDIA_LNK_FL_ENABLED);
+			if (ret)
+				goto remove_intf_link;
+			break;
+		}
+	}
+
+	subs->media_ctl = mctl;
+	return 0;
+
+remove_intf_link:
+	media_remove_intf_link(mctl->intf_link);
+devnode_remove:
+	media_devnode_remove(mctl->intf_devnode);
+unregister_entity:
+	media_device_unregister_entity(&mctl->media_entity);
+free_mctl:
+	kfree(mctl);
+	return ret;
+}
+
+void snd_media_stream_delete(struct snd_usb_substream *subs)
+{
+	struct media_ctl *mctl = subs->media_ctl;
+
+	if (mctl) {
+		struct media_device *mdev;
+
+		mdev = mctl->media_dev;
+		if (mdev && media_devnode_is_registered(mdev->devnode)) {
+			media_devnode_remove(mctl->intf_devnode);
+			media_device_unregister_entity(&mctl->media_entity);
+			media_entity_cleanup(&mctl->media_entity);
+		}
+		kfree(mctl);
+		subs->media_ctl = NULL;
+	}
+}
+
+int snd_media_start_pipeline(struct snd_usb_substream *subs)
+{
+	struct media_ctl *mctl = subs->media_ctl;
+	int ret = 0;
+
+	if (!mctl)
+		return 0;
+
+	mutex_lock(&mctl->media_dev->graph_mutex);
+	if (mctl->media_dev->enable_source)
+		ret = mctl->media_dev->enable_source(&mctl->media_entity,
+						     &mctl->media_pipe);
+	mutex_unlock(&mctl->media_dev->graph_mutex);
+	return ret;
+}
+
+void snd_media_stop_pipeline(struct snd_usb_substream *subs)
+{
+	struct media_ctl *mctl = subs->media_ctl;
+
+	if (!mctl)
+		return;
+
+	mutex_lock(&mctl->media_dev->graph_mutex);
+	if (mctl->media_dev->disable_source)
+		mctl->media_dev->disable_source(&mctl->media_entity);
+	mutex_unlock(&mctl->media_dev->graph_mutex);
+}
+
+static int snd_media_mixer_init(struct snd_usb_audio *chip)
+{
+	struct device *ctl_dev = &chip->card->ctl_dev;
+	struct media_intf_devnode *ctl_intf;
+	struct usb_mixer_interface *mixer;
+	struct media_device *mdev = chip->media_dev;
+	struct media_mixer_ctl *mctl;
+	u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL;
+	int ret;
+
+	if (!mdev)
+		return -ENODEV;
+
+	ctl_intf = chip->ctl_intf_media_devnode;
+	if (!ctl_intf) {
+		ctl_intf = media_devnode_create(mdev, intf_type, 0,
+						MAJOR(ctl_dev->devt),
+						MINOR(ctl_dev->devt));
+		if (!ctl_intf)
+			return -ENOMEM;
+		chip->ctl_intf_media_devnode = ctl_intf;
+	}
+
+	list_for_each_entry(mixer, &chip->mixer_list, list) {
+
+		if (mixer->media_mixer_ctl)
+			continue;
+
+		/* allocate media_mixer_ctl */
+		mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
+		if (!mctl)
+			return -ENOMEM;
+
+		mctl->media_dev = mdev;
+		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER;
+		mctl->media_entity.name = chip->card->mixername;
+		mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK;
+		mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE;
+		mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE;
+		media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX,
+				  mctl->media_pad);
+		ret =  media_device_register_entity(mctl->media_dev,
+						    &mctl->media_entity);
+		if (ret) {
+			kfree(mctl);
+			return ret;
+		}
+
+		mctl->intf_link = media_create_intf_link(&mctl->media_entity,
+							 &ctl_intf->intf,
+							 MEDIA_LNK_FL_ENABLED);
+		if (!mctl->intf_link) {
+			media_device_unregister_entity(&mctl->media_entity);
+			media_entity_cleanup(&mctl->media_entity);
+			kfree(mctl);
+			return -ENOMEM;
+		}
+		mctl->intf_devnode = ctl_intf;
+		mixer->media_mixer_ctl = mctl;
+	}
+	return 0;
+}
+
+static void snd_media_mixer_delete(struct snd_usb_audio *chip)
+{
+	struct usb_mixer_interface *mixer;
+	struct media_device *mdev = chip->media_dev;
+
+	if (!mdev)
+		return;
+
+	list_for_each_entry(mixer, &chip->mixer_list, list) {
+		struct media_mixer_ctl *mctl;
+
+		mctl = mixer->media_mixer_ctl;
+		if (!mixer->media_mixer_ctl)
+			continue;
+
+		if (media_devnode_is_registered(mdev->devnode)) {
+			media_device_unregister_entity(&mctl->media_entity);
+			media_entity_cleanup(&mctl->media_entity);
+		}
+		kfree(mctl);
+		mixer->media_mixer_ctl = NULL;
+	}
+	if (media_devnode_is_registered(mdev->devnode))
+		media_devnode_remove(chip->ctl_intf_media_devnode);
+	chip->ctl_intf_media_devnode = NULL;
+}
+
+int snd_media_device_create(struct snd_usb_audio *chip,
+			struct usb_interface *iface)
+{
+	struct media_device *mdev;
+	struct usb_device *usbdev = interface_to_usbdev(iface);
+	int ret = 0;
+
+	/* usb-audio driver is probed for each usb interface, and
+	 * there are multiple interfaces per device. Avoid calling
+	 * media_device_usb_allocate() each time usb_audio_probe()
+	 * is called. Do it only once.
+	 */
+	if (chip->media_dev) {
+		mdev = chip->media_dev;
+		goto snd_mixer_init;
+	}
+
+	mdev = media_device_usb_allocate(usbdev, KBUILD_MODNAME);
+	if (!mdev)
+		return -ENOMEM;
+
+	/* save media device - avoid lookups */
+	chip->media_dev = mdev;
+
+snd_mixer_init:
+	/* Create media entities for mixer and control dev */
+	ret = snd_media_mixer_init(chip);
+	/* media_device might be registered, print error and continue */
+	if (ret)
+		dev_err(&usbdev->dev,
+			"Couldn't create media mixer entities. Error: %d\n",
+			ret);
+
+	if (!media_devnode_is_registered(mdev->devnode)) {
+		/* dont'register if snd_media_mixer_init() failed */
+		if (ret)
+			goto create_fail;
+
+		/* register media_device */
+		ret = media_device_register(mdev);
+create_fail:
+		if (ret) {
+			snd_media_mixer_delete(chip);
+			media_device_delete(mdev, KBUILD_MODNAME);
+			/* clear saved media_dev */
+			chip->media_dev = NULL;
+			dev_err(&usbdev->dev,
+				"Couldn't register media device. Error: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+void snd_media_device_delete(struct snd_usb_audio *chip)
+{
+	struct media_device *mdev = chip->media_dev;
+	struct snd_usb_stream *stream;
+
+	/* release resources */
+	list_for_each_entry(stream, &chip->pcm_list, list) {
+		snd_media_stream_delete(&stream->substream[0]);
+		snd_media_stream_delete(&stream->substream[1]);
+	}
+
+	snd_media_mixer_delete(chip);
+
+	if (mdev) {
+		media_device_delete(mdev, KBUILD_MODNAME);
+		chip->media_dev = NULL;
+	}
+}
diff --git a/sound/usb/media.h b/sound/usb/media.h
new file mode 100644
index 000000000000..0e8a4785f858
--- /dev/null
+++ b/sound/usb/media.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * media.h - Media Controller specific ALSA driver code
+ *
+ * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
+ *
+ */
+
+/*
+ * This file adds Media Controller support to the ALSA driver
+ * to use the Media Controller API to share the tuner with DVB
+ * and V4L2 drivers that control the media device.
+ *
+ * The media device is created based on the existing quirks framework.
+ * Using this approach, the media controller API usage can be added for
+ * a specific device.
+ */
+#ifndef __MEDIA_H
+
+#ifdef CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER
+
+#include <linux/media.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/media-dev-allocator.h>
+#include <sound/asound.h>
+
+struct media_ctl {
+	struct media_device *media_dev;
+	struct media_entity media_entity;
+	struct media_intf_devnode *intf_devnode;
+	struct media_link *intf_link;
+	struct media_pad media_pad;
+	struct media_pipeline media_pipe;
+};
+
+/*
+ * One source pad each for SNDRV_PCM_STREAM_CAPTURE and
+ * SNDRV_PCM_STREAM_PLAYBACK. One for sink pad to link
+ * to AUDIO Source
+ */
+#define MEDIA_MIXER_PAD_MAX    (SNDRV_PCM_STREAM_LAST + 2)
+
+struct media_mixer_ctl {
+	struct media_device *media_dev;
+	struct media_entity media_entity;
+	struct media_intf_devnode *intf_devnode;
+	struct media_link *intf_link;
+	struct media_pad media_pad[MEDIA_MIXER_PAD_MAX];
+	struct media_pipeline media_pipe;
+};
+
+int snd_media_device_create(struct snd_usb_audio *chip,
+			    struct usb_interface *iface);
+void snd_media_device_delete(struct snd_usb_audio *chip);
+int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
+			  int stream);
+void snd_media_stream_delete(struct snd_usb_substream *subs);
+int snd_media_start_pipeline(struct snd_usb_substream *subs);
+void snd_media_stop_pipeline(struct snd_usb_substream *subs);
+#else
+static inline int snd_media_device_create(struct snd_usb_audio *chip,
+					  struct usb_interface *iface)
+						{ return 0; }
+static inline void snd_media_device_delete(struct snd_usb_audio *chip) { }
+static inline int snd_media_stream_init(struct snd_usb_substream *subs,
+					struct snd_pcm *pcm, int stream)
+						{ return 0; }
+static inline void snd_media_stream_delete(struct snd_usb_substream *subs) { }
+static inline int snd_media_start_pipeline(struct snd_usb_substream *subs)
+					{ return 0; }
+static inline void snd_media_stop_pipeline(struct snd_usb_substream *subs) { }
+#endif
+#endif /* __MEDIA_H */
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3d12af8bf191..394cd9107507 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -4,6 +4,8 @@
 
 #include <sound/info.h>
 
+struct media_mixer_ctl;
+
 struct usb_mixer_interface {
 	struct snd_usb_audio *chip;
 	struct usb_host_interface *hostif;
@@ -23,6 +25,7 @@ struct usb_mixer_interface {
 	struct urb *rc_urb;
 	struct usb_ctrlrequest *rc_setup_packet;
 	u8 rc_buffer[6];
+	struct media_mixer_ctl *media_mixer_ctl;
 
 	bool disconnected;
 };
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 382847154227..538ed10ab66d 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -35,6 +35,7 @@
 #include "pcm.h"
 #include "clock.h"
 #include "power.h"
+#include "media.h"
 
 #define SUBSTREAM_FLAG_DATA_EP_STARTED	0
 #define SUBSTREAM_FLAG_SYNC_EP_STARTED	1
@@ -776,6 +777,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 	struct audioformat *fmt;
 	int ret;
 
+	ret = snd_media_start_pipeline(subs);
+	if (ret)
+		return ret;
+
 	if (snd_usb_use_vmalloc)
 		ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 						       params_buffer_bytes(hw_params));
@@ -783,7 +788,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 		ret = snd_pcm_lib_malloc_pages(substream,
 					       params_buffer_bytes(hw_params));
 	if (ret < 0)
-		return ret;
+		goto stop_pipeline;
 
 	subs->pcm_format = params_format(hw_params);
 	subs->period_bytes = params_period_bytes(hw_params);
@@ -797,12 +802,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 		dev_dbg(&subs->dev->dev,
 			"cannot set format: format = %#x, rate = %d, channels = %d\n",
 			   subs->pcm_format, subs->cur_rate, subs->channels);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto stop_pipeline;
 	}
 
 	ret = snd_usb_lock_shutdown(subs->stream->chip);
 	if (ret < 0)
-		return ret;
+		goto stop_pipeline;
 
 	ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
 	if (ret < 0)
@@ -818,6 +824,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 
  unlock:
 	snd_usb_unlock_shutdown(subs->stream->chip);
+	if (ret < 0)
+		goto stop_pipeline;
+	return ret;
+
+ stop_pipeline:
+	snd_media_stop_pipeline(subs);
 	return ret;
 }
 
@@ -830,6 +842,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_usb_substream *subs = substream->runtime->private_data;
 
+	snd_media_stop_pipeline(subs);
 	subs->cur_audiofmt = NULL;
 	subs->cur_rate = 0;
 	subs->period_bytes = 0;
@@ -1302,6 +1315,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usb_substream *subs = &as->substream[direction];
+	int ret;
 
 	subs->interface = -1;
 	subs->altset_idx = 0;
@@ -1315,7 +1329,13 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 	subs->dsd_dop.channel = 0;
 	subs->dsd_dop.marker = 1;
 
-	return setup_hw_info(runtime, subs);
+	ret = setup_hw_info(runtime, subs);
+	if (ret == 0) {
+		ret = snd_media_stream_init(subs, as->pcm, direction);
+		if (ret)
+			snd_usb_autosuspend(subs->stream->chip);
+	}
+	return ret;
 }
 
 static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
@@ -1326,6 +1346,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
 	int ret;
 
 	stop_endpoints(subs, true);
+	snd_media_stop_pipeline(subs);
 
 	if (!as->chip->keep_iface &&
 	    subs->interface >= 0 &&
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index b345beb447bd..6835665d311f 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2887,6 +2887,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		.product_name = pname, \
 		.ifnum = QUIRK_ANY_INTERFACE, \
 		.type = QUIRK_AUDIO_ALIGN_TRANSFER, \
+		.shares_media_device = 1, \
 	} \
 }
 
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index d9e3de495c16..9f1623e37fb3 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -38,6 +38,7 @@
 #include "clock.h"
 #include "stream.h"
 #include "power.h"
+#include "media.h"
 
 /*
  * free a substream
@@ -55,6 +56,7 @@ static void free_substream(struct snd_usb_substream *subs)
 	}
 	kfree(subs->rate_list.list);
 	kfree(subs->str_pd);
+	snd_media_stream_delete(subs);
 }
 
 
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index b9faeca645fd..0968a45c8925 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -30,6 +30,9 @@
  *
  */
 
+struct media_device;
+struct media_intf_devnode;
+
 struct snd_usb_audio {
 	int index;
 	struct usb_device *dev;
@@ -66,6 +69,8 @@ struct snd_usb_audio {
 					 */
 
 	struct usb_host_interface *ctrl_intf;	/* the audio control interface */
+	struct media_device *media_dev;
+	struct media_intf_devnode *ctl_intf_media_devnode;
 };
 
 #define usb_audio_err(chip, fmt, args...) \
@@ -117,6 +122,7 @@ struct snd_usb_audio_quirk {
 	const char *profile_name;	/* override the card->longname */
 	int16_t ifnum;
 	uint16_t type;
+	bool shares_media_device;
 	const void *data;
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
@ 2019-01-25 15:28   ` Sakari Ailus
  2019-01-24 20:32 ` [PATCH v10 2/4] media: change au0828 to use " Shuah Khan
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Sakari Ailus @ 2019-01-25 15:28 UTC (permalink / raw)
  To: Shuah Khan
  Cc: mchehab, perex, tiwai, hverkuil, linux-media, linux-kernel, alsa-devel

Hi Shuah,

On Thu, Jan 24, 2019 at 01:32:37PM -0700, Shuah Khan wrote:
> Media Device Allocator API to allows multiple drivers share a media device.
> This API solves a very common use-case for media devices where one physical
> device (an USB stick) provides both audio and video. When such media device
> exposes a standard USB Audio class, a proprietary Video class, two or more
> independent drivers will share a single physical USB bridge. In such cases,
> it is necessary to coordinate access to the shared resource.
> 
> Using this API, drivers can allocate a media device with the shared struct
> device as the key. Once the media device is allocated by a driver, other
> drivers can get a reference to it. The media device is released when all
> the references are released.

Thanks for the update. I have to apologise I haven't ended up reviewing the
set for some time. After taking a look at the current version, I'm happy to
see that a number of issues recognised during earlier review rounds have
been addressed.

Would you happen to have a media graph (media-ctl --print-dot and media-ctl
-p) from the device? That'd help understanding the device a bit better for
those who are not familiar with it.

> 
> - This patch series is tested on 5.0-rc3 and addresses comments on
>   v9 series from Hans Verkuil.
> - v9 was tested on 4.20-rc6.
> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>   arecord. When analog is streaming, digital and audio user-space
>   applications detect that the tuner is busy and exit. When digital
>   is streaming, analog and audio applications detect that the tuner is
>   busy and exit. When arecord is owns the tuner, digital and analog
>   detect that the tuner is busy and exit.
> - Tested media device allocator API with bind/unbind testing on
>   snd-usb-audio and au0828 drivers to make sure /dev/mediaX is released
>   only when the last driver is unbound.
> - Addressed review comments from Hans on the RFC v8 (rebased on 4.19)
> - Updated change log to describe the use-case more clearly.
> - No changes to 0001,0002 code since the v7 referenced below.
> - 0003 is a new patch to enable ALSA defines that have been
>   disabled for kernel between 4.9 and 4.19.
> - Minor merge conflict resolution in 0004.
> - Added SPDX to new files.
> 
> Changes since v9:
> - Patch 1: Fix mutex assert warning from find_module() calls. This
>   code was written before the change to find_module() that requires
>   callers to hold module_mutex. I missed this during my testing on
>   4.20-rc6. Hans Verkuil reported the problem.
> - Patch 4: sound/usb: Initializes all the entities it can before
>   registering the device based on comments from Hans Verkuil
> - Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
> - No changes to Patches 2 and 3.
> 
> References:
> https://lkml.org/lkml/2018/11/2/169
> https://www.mail-archive.com/linux-media@vger.kernel.org/msg105854.html
> 
> Shuah Khan (4):
>   media: Media Device Allocator API
>   media: change au0828 to use Media Device Allocator API
>   media: media.h: Enable ALSA MEDIA_INTF_T* interface types
>   sound/usb: Use Media Controller API to share media resources
> 
>  Documentation/media/kapi/mc-core.rst   |  41 ++++
>  drivers/media/Makefile                 |   4 +
>  drivers/media/media-dev-allocator.c    | 144 +++++++++++
>  drivers/media/usb/au0828/au0828-core.c |  12 +-
>  drivers/media/usb/au0828/au0828.h      |   1 +
>  include/media/media-dev-allocator.h    |  53 ++++
>  include/uapi/linux/media.h             |  25 +-
>  sound/usb/Kconfig                      |   4 +
>  sound/usb/Makefile                     |   2 +
>  sound/usb/card.c                       |  14 ++
>  sound/usb/card.h                       |   3 +
>  sound/usb/media.c                      | 327 +++++++++++++++++++++++++
>  sound/usb/media.h                      |  74 ++++++
>  sound/usb/mixer.h                      |   3 +
>  sound/usb/pcm.c                        |  29 ++-
>  sound/usb/quirks-table.h               |   1 +
>  sound/usb/stream.c                     |   2 +
>  sound/usb/usbaudio.h                   |   6 +
>  18 files changed, 723 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/media/media-dev-allocator.c
>  create mode 100644 include/media/media-dev-allocator.h
>  create mode 100644 sound/usb/media.c
>  create mode 100644 sound/usb/media.h
> 

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
@ 2019-01-25 15:28   ` Sakari Ailus
  0 siblings, 0 replies; 23+ messages in thread
From: Sakari Ailus @ 2019-01-25 15:28 UTC (permalink / raw)
  To: Shuah Khan
  Cc: alsa-devel, linux-kernel, tiwai, hverkuil, mchehab, linux-media

Hi Shuah,

On Thu, Jan 24, 2019 at 01:32:37PM -0700, Shuah Khan wrote:
> Media Device Allocator API to allows multiple drivers share a media device.
> This API solves a very common use-case for media devices where one physical
> device (an USB stick) provides both audio and video. When such media device
> exposes a standard USB Audio class, a proprietary Video class, two or more
> independent drivers will share a single physical USB bridge. In such cases,
> it is necessary to coordinate access to the shared resource.
> 
> Using this API, drivers can allocate a media device with the shared struct
> device as the key. Once the media device is allocated by a driver, other
> drivers can get a reference to it. The media device is released when all
> the references are released.

Thanks for the update. I have to apologise I haven't ended up reviewing the
set for some time. After taking a look at the current version, I'm happy to
see that a number of issues recognised during earlier review rounds have
been addressed.

Would you happen to have a media graph (media-ctl --print-dot and media-ctl
-p) from the device? That'd help understanding the device a bit better for
those who are not familiar with it.

> 
> - This patch series is tested on 5.0-rc3 and addresses comments on
>   v9 series from Hans Verkuil.
> - v9 was tested on 4.20-rc6.
> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>   arecord. When analog is streaming, digital and audio user-space
>   applications detect that the tuner is busy and exit. When digital
>   is streaming, analog and audio applications detect that the tuner is
>   busy and exit. When arecord is owns the tuner, digital and analog
>   detect that the tuner is busy and exit.
> - Tested media device allocator API with bind/unbind testing on
>   snd-usb-audio and au0828 drivers to make sure /dev/mediaX is released
>   only when the last driver is unbound.
> - Addressed review comments from Hans on the RFC v8 (rebased on 4.19)
> - Updated change log to describe the use-case more clearly.
> - No changes to 0001,0002 code since the v7 referenced below.
> - 0003 is a new patch to enable ALSA defines that have been
>   disabled for kernel between 4.9 and 4.19.
> - Minor merge conflict resolution in 0004.
> - Added SPDX to new files.
> 
> Changes since v9:
> - Patch 1: Fix mutex assert warning from find_module() calls. This
>   code was written before the change to find_module() that requires
>   callers to hold module_mutex. I missed this during my testing on
>   4.20-rc6. Hans Verkuil reported the problem.
> - Patch 4: sound/usb: Initializes all the entities it can before
>   registering the device based on comments from Hans Verkuil
> - Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
> - No changes to Patches 2 and 3.
> 
> References:
> https://lkml.org/lkml/2018/11/2/169
> https://www.mail-archive.com/linux-media@vger.kernel.org/msg105854.html
> 
> Shuah Khan (4):
>   media: Media Device Allocator API
>   media: change au0828 to use Media Device Allocator API
>   media: media.h: Enable ALSA MEDIA_INTF_T* interface types
>   sound/usb: Use Media Controller API to share media resources
> 
>  Documentation/media/kapi/mc-core.rst   |  41 ++++
>  drivers/media/Makefile                 |   4 +
>  drivers/media/media-dev-allocator.c    | 144 +++++++++++
>  drivers/media/usb/au0828/au0828-core.c |  12 +-
>  drivers/media/usb/au0828/au0828.h      |   1 +
>  include/media/media-dev-allocator.h    |  53 ++++
>  include/uapi/linux/media.h             |  25 +-
>  sound/usb/Kconfig                      |   4 +
>  sound/usb/Makefile                     |   2 +
>  sound/usb/card.c                       |  14 ++
>  sound/usb/card.h                       |   3 +
>  sound/usb/media.c                      | 327 +++++++++++++++++++++++++
>  sound/usb/media.h                      |  74 ++++++
>  sound/usb/mixer.h                      |   3 +
>  sound/usb/pcm.c                        |  29 ++-
>  sound/usb/quirks-table.h               |   1 +
>  sound/usb/stream.c                     |   2 +
>  sound/usb/usbaudio.h                   |   6 +
>  18 files changed, 723 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/media/media-dev-allocator.c
>  create mode 100644 include/media/media-dev-allocator.h
>  create mode 100644 sound/usb/media.c
>  create mode 100644 sound/usb/media.h
> 

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 1/4] media: Media Device Allocator API
  2019-01-24 20:32 ` [PATCH v10 1/4] media: " Shuah Khan
@ 2019-01-25 15:38   ` Sakari Ailus
  2019-01-26  0:27       ` shuah
  0 siblings, 1 reply; 23+ messages in thread
From: Sakari Ailus @ 2019-01-25 15:38 UTC (permalink / raw)
  To: Shuah Khan
  Cc: mchehab, perex, tiwai, hverkuil, linux-media, linux-kernel, alsa-devel

Hi Shuah,

On Thu, Jan 24, 2019 at 01:32:38PM -0700, Shuah Khan wrote:
> Media Device Allocator API to allows multiple drivers share a media device.
> This API solves a very common use-case for media devices where one physical
> device (an USB stick) provides both audio and video. When such media device
> exposes a standard USB Audio class, a proprietary Video class, two or more
> independent drivers will share a single physical USB bridge. In such cases,
> it is necessary to coordinate access to the shared resource.
> 
> Using this API, drivers can allocate a media device with the shared struct
> device as the key. Once the media device is allocated by a driver, other
> drivers can get a reference to it. The media device is released when all
> the references are released.

Are there real, non-USB devices that could use the same API?

> 
> Signed-off-by: Shuah Khan <shuah@kernel.org>
> ---
>  Documentation/media/kapi/mc-core.rst |  41 ++++++++
>  drivers/media/Makefile               |   4 +
>  drivers/media/media-dev-allocator.c  | 144 +++++++++++++++++++++++++++
>  include/media/media-dev-allocator.h  |  53 ++++++++++
>  4 files changed, 242 insertions(+)
>  create mode 100644 drivers/media/media-dev-allocator.c
>  create mode 100644 include/media/media-dev-allocator.h
> 
> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> index 0bcfeadbc52d..07f2a6a90af2 100644
> --- a/Documentation/media/kapi/mc-core.rst
> +++ b/Documentation/media/kapi/mc-core.rst
> @@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific
>  helper functions to provide easy access for commonly needed information, and
>  in the end provide a way to use driver-specific callbacks.
>  
> +Media Controller Device Allocator API
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +When the media device belongs to more than one driver, the shared media
> +device is allocated with the shared struct device as the key for look ups.
> +
> +The shared media device should stay in registered state until the last
> +driver unregisters it. In addition, the media device should be released when
> +all the references are released. Each driver gets a reference to the media
> +device during probe, when it allocates the media device. If media device is
> +already allocated, the allocate API bumps up the refcount and returns the
> +existing media device. The driver puts the reference back in its disconnect
> +routine when it calls :c:func:`media_device_delete()`.
> +
> +The media device is unregistered and cleaned up from the kref put handler to
> +ensure that the media device stays in registered state until the last driver
> +unregisters the media device.
> +
> +**Driver Usage**
> +
> +Drivers should use the appropriate media-core routines to manage the shared
> +media device life-time handling the two states:
> +1. allocate -> register -> delete
> +2. get reference to already registered device -> delete
> +
> +call :c:func:`media_device_delete()` routine to make sure the shared media
> +device delete is handled correctly.
> +
> +**driver probe:**
> +Call :c:func:`media_device_usb_allocate()` to allocate or get a reference
> +Call :c:func:`media_device_register()`, if media devnode isn't registered
> +
> +**driver disconnect:**
> +Call :c:func:`media_device_delete()` to free the media_device. Freeing is
> +handled by the kref put handler.
> +
> +API Definitions
> +^^^^^^^^^^^^^^^
> +
>  .. kernel-doc:: include/media/media-device.h
>  
>  .. kernel-doc:: include/media/media-devnode.h
> @@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks.
>  .. kernel-doc:: include/media/media-entity.h
>  
>  .. kernel-doc:: include/media/media-request.h
> +
> +.. kernel-doc:: include/media/media-dev-allocator.h
> diff --git a/drivers/media/Makefile b/drivers/media/Makefile
> index 985d35ec6b29..1d7653318af6 100644
> --- a/drivers/media/Makefile
> +++ b/drivers/media/Makefile
> @@ -6,6 +6,10 @@
>  media-objs	:= media-device.o media-devnode.o media-entity.o \
>  		   media-request.o
>  
> +ifeq ($(CONFIG_USB),y)
> +	media-objs += media-dev-allocator.o
> +endif
> +
>  #
>  # I2C drivers should come before other drivers, otherwise they'll fail
>  # when compiled as builtin drivers
> diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c
> new file mode 100644
> index 000000000000..4606456c1e86
> --- /dev/null
> +++ b/drivers/media/media-dev-allocator.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later

GPL-2.0+

> +/*
> + * media-dev-allocator.c - Media Controller Device Allocator API
> + *
> + * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
> + *
> + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + */
> +
> +/*
> + * This file adds a global refcounted Media Controller Device Instance API.
> + * A system wide global media device list is managed and each media device
> + * includes a kref count. The last put on the media device releases the media
> + * device instance.
> + *
> + */
> +
> +#include <linux/kref.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/usb.h>
> +
> +#include <media/media-device.h>
> +
> +static LIST_HEAD(media_device_list);
> +static DEFINE_MUTEX(media_device_lock);
> +
> +struct media_device_instance {
> +	struct media_device mdev;
> +	struct module *owner;
> +	struct list_head list;
> +	struct kref refcount;
> +};
> +
> +static inline struct media_device_instance *
> +to_media_device_instance(struct media_device *mdev)
> +{
> +	return container_of(mdev, struct media_device_instance, mdev);
> +}
> +
> +static void media_device_instance_release(struct kref *kref)
> +{
> +	struct media_device_instance *mdi =
> +		container_of(kref, struct media_device_instance, refcount);
> +
> +	dev_dbg(mdi->mdev.dev, "%s: mdev=%p\n", __func__, &mdi->mdev);
> +
> +	mutex_lock(&media_device_lock);
> +
> +	media_device_unregister(&mdi->mdev);
> +	media_device_cleanup(&mdi->mdev);

This is a problem, albeit not really more of a problem than it is in a
driver. The refcounting changes can be made here instead. I'll take this
into account in the media device refcounting series I'm planning to start
working on again; would you be perhaps able to help testing with this
device once I have patches in that shape? I have no access to the hardware.

> +
> +	list_del(&mdi->list);
> +	mutex_unlock(&media_device_lock);
> +
> +	kfree(mdi);
> +}
> +
> +/* Callers should hold media_device_lock when calling this function */
> +static struct media_device *__media_device_get(struct device *dev,
> +						const char *module_name,
> +						struct module *modp)
> +{
> +	struct media_device_instance *mdi;
> +
> +	list_for_each_entry(mdi, &media_device_list, list) {
> +
> +		if (mdi->mdev.dev != dev)
> +			continue;
> +
> +		kref_get(&mdi->refcount);
> +
> +		/* get module reference for the media_device owner */
> +		if (modp != mdi->owner && !try_module_get(mdi->owner))
> +			dev_err(dev, "%s: try_module_get() error\n", __func__);
> +		dev_dbg(dev, "%s: get mdev=%p module_name %s\n",
> +			__func__, &mdi->mdev, module_name);
> +		return &mdi->mdev;
> +	}
> +
> +	mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
> +	if (!mdi)
> +		return NULL;
> +
> +	mdi->owner = modp;
> +	kref_init(&mdi->refcount);
> +	list_add_tail(&mdi->list, &media_device_list);
> +
> +	dev_dbg(dev, "%s: alloc mdev=%p module_name %s\n", __func__,
> +		&mdi->mdev, module_name);
> +	return &mdi->mdev;
> +}
> +
> +#if IS_ENABLED(CONFIG_USB)

You already compile the file only if CONFIG_USB is enabled. I think you
could remove this.

> +struct media_device *media_device_usb_allocate(struct usb_device *udev,
> +					       const char *module_name)

I'd like to suggest working based on usb_interface instead of usb_device
here: that object already exists and you can find out the device based on
it. It seems all callers of this function already have the usb_interface
around.

> +{
> +	struct media_device *mdev;
> +	struct module *modptr;
> +
> +	mutex_lock(&module_mutex);
> +	modptr = find_module(module_name);
> +	mutex_unlock(&module_mutex);
> +
> +	mutex_lock(&media_device_lock);
> +	mdev = __media_device_get(&udev->dev, module_name, modptr);
> +	if (!mdev) {
> +		mutex_unlock(&media_device_lock);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	/* check if media device is already initialized */
> +	if (!mdev->dev)
> +		__media_device_usb_init(mdev, udev, udev->product,
> +					module_name);
> +	mutex_unlock(&media_device_lock);
> +	return mdev;
> +}
> +EXPORT_SYMBOL_GPL(media_device_usb_allocate);
> +#endif
> +
> +void media_device_delete(struct media_device *mdev, const char *module_name)

Same here. The use of the module name seems a bit hackish to me, albeit I
suppose it'd work, too.

> +{
> +	struct media_device_instance *mdi = to_media_device_instance(mdev);
> +	struct module *modptr;
> +
> +	dev_dbg(mdi->mdev.dev, "%s: mdev=%p module_name %s\n",
> +		__func__, &mdi->mdev, module_name);
> +
> +	mutex_lock(&module_mutex);
> +	modptr = find_module(module_name);
> +	mutex_unlock(&module_mutex);
> +
> +	mutex_lock(&media_device_lock);
> +	/* put module reference if media_device owner is not THIS_MODULE */
> +	if (mdi->owner != modptr) {
> +		module_put(mdi->owner);
> +		dev_dbg(mdi->mdev.dev,
> +			"%s decremented owner module reference\n", __func__);
> +	}
> +	mutex_unlock(&media_device_lock);
> +	kref_put(&mdi->refcount, media_device_instance_release);
> +}
> +EXPORT_SYMBOL_GPL(media_device_delete);
> diff --git a/include/media/media-dev-allocator.h b/include/media/media-dev-allocator.h
> new file mode 100644
> index 000000000000..9164795e911c
> --- /dev/null
> +++ b/include/media/media-dev-allocator.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * media-dev-allocator.h - Media Controller Device Allocator API
> + *
> + * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
> + *
> + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + */
> +
> +/*
> + * This file adds a global ref-counted Media Controller Device Instance API.
> + * A system wide global media device list is managed and each media device
> + * includes a kref count. The last put on the media device releases the media
> + * device instance.
> + */
> +
> +#ifndef _MEDIA_DEV_ALLOCTOR_H
> +#define _MEDIA_DEV_ALLOCTOR_H
> +
> +struct usb_device;
> +
> +#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_USB)
> +/**
> + * media_device_usb_allocate() - Allocate and return struct &media device
> + *
> + * @udev:		struct &usb_device pointer
> + * @module_name:	should be filled with %KBUILD_MODNAME
> + *
> + * This interface should be called to allocate a Media Device when multiple
> + * drivers share usb_device and the media device. This interface allocates
> + * &media_device structure and calls media_device_usb_init() to initialize
> + * it.
> + *
> + */
> +struct media_device *media_device_usb_allocate(struct usb_device *udev,
> +					       char *module_name);
> +/**
> + * media_device_delete() - Release media device. Calls kref_put().
> + *
> + * @mdev:		struct &media_device pointer
> + * @module_name:	should be filled with %KBUILD_MODNAME
> + *
> + * This interface should be called to put Media Device Instance kref.
> + */
> +void media_device_delete(struct media_device *mdev, char *module_name);
> +#else
> +static inline struct media_device *media_device_usb_allocate(
> +			struct usb_device *udev, char *module_name)
> +			{ return NULL; }
> +static inline void media_device_delete(
> +			struct media_device *mdev, char *module_name) { }
> +#endif /* CONFIG_MEDIA_CONTROLLER */
> +#endif

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-25 15:28   ` Sakari Ailus
@ 2019-01-26  0:19     ` shuah
  -1 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-26  0:19 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, perex, tiwai, hverkuil, linux-media, linux-kernel,
	alsa-devel, shuah

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

Hi Sakari,

On 1/25/19 8:28 AM, Sakari Ailus wrote:
> Hi Shuah,
> 
> On Thu, Jan 24, 2019 at 01:32:37PM -0700, Shuah Khan wrote:
>> Media Device Allocator API to allows multiple drivers share a media device.
>> This API solves a very common use-case for media devices where one physical
>> device (an USB stick) provides both audio and video. When such media device
>> exposes a standard USB Audio class, a proprietary Video class, two or more
>> independent drivers will share a single physical USB bridge. In such cases,
>> it is necessary to coordinate access to the shared resource.
>>
>> Using this API, drivers can allocate a media device with the shared struct
>> device as the key. Once the media device is allocated by a driver, other
>> drivers can get a reference to it. The media device is released when all
>> the references are released.
> 
> Thanks for the update. I have to apologise I haven't ended up reviewing the
> set for some time. After taking a look at the current version, I'm happy to
> see that a number of issues recognised during earlier review rounds have
> been addressed.
> 
> Would you happen to have a media graph (media-ctl --print-dot and media-ctl
> -p) from the device? That'd help understanding the device a bit better for
> those who are not familiar with it.
> 

Please see the attached files for the below. It came in very handy
for testing partial graphs as I did bind and unbind of the drivers
in this mix.

media-ctl --print-dot and
media-ctl --print-topology

thanks,
-- Shuah

[-- Attachment #2: media_graph_topo --]
[-- Type: text/plain, Size: 87218 bytes --]

Media controller API version 5.0.0

Media device information
------------------------
driver          au0828
model           WinTV HVR-950
serial          4035198866
bus info        usb-0000:00:1a.0-1.4
hw revision     0x5
driver version  5.0.0

Device topology
- entity 1: au8522 13-0047 (3 pads, 6 links)
            type V4L2 subdev subtype Decoder flags 0
	pad0: Sink
		<- "Xceive XC5000":1 []
		<- "Composite":0 []
		<- "S-Video":0 []
	pad1: Source
		-> "au0828a video":0 [ENABLED]
		-> "au0828a vbi":0 [ENABLED]
	pad2: Source
		-> "USB Mixer":0 [ENABLED]

- entity 5: Xceive XC5000 (3 pads, 3 links)
            type V4L2 subdev subtype Tuner flags 0
	pad0: Sink
		-> "Auvitek AU8522 QAM/8VSB Fronten":0 []
		<- "Television":0 [ENABLED]
	pad1: Source
		-> "au8522 13-0047":0 []
	pad2: Source

- entity 9: Television (1 pad, 1 link)
            type Node subtype Unknown flags 2
	pad0: Source
		-> "Xceive XC5000":0 [ENABLED]

- entity 11: Composite (1 pad, 1 link)
             type Node subtype Unknown flags 2
	pad0: Source
		-> "au8522 13-0047":0 []

- entity 13: S-Video (1 pad, 1 link)
             type Node subtype Unknown flags 2
	pad0: Source
		-> "au8522 13-0047":0 []

- entity 15: au0828a video (1 pad, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/video0
	pad0: Sink
		<- "au8522 13-0047":1 [ENABLED]

- entity 19: au0828a vbi (1 pad, 1 link)
             type Node subtype Unknown flags 0
             device node name /dev/vbi0
	pad0: Sink
		<- "au8522 13-0047":1 [ENABLED]

- entity 35: Auvitek AU8522 QAM/8VSB Fronten (2 pads, 2 links)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "Xceive XC5000":0 []
	pad1: Source
		-> "dvb-demux":0 [ENABLED]

- entity 40: demux-tsout #0 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":1 []

- entity 42: demux-tsout #1 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":2 []

- entity 44: demux-tsout #2 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":3 []

- entity 46: demux-tsout #3 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":4 []

- entity 48: demux-tsout #4 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":5 []

- entity 50: demux-tsout #5 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":6 []

- entity 52: demux-tsout #6 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":7 []

- entity 54: demux-tsout #7 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":8 []

- entity 56: demux-tsout #8 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":9 []

- entity 58: demux-tsout #9 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":10 []

- entity 60: demux-tsout #10 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":11 []

- entity 62: demux-tsout #11 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":12 []

- entity 64: demux-tsout #12 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":13 []

- entity 66: demux-tsout #13 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":14 []

- entity 68: demux-tsout #14 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":15 []

- entity 70: demux-tsout #15 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":16 []

- entity 72: demux-tsout #16 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":17 []

- entity 74: demux-tsout #17 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":18 []

- entity 76: demux-tsout #18 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":19 []

- entity 78: demux-tsout #19 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":20 []

- entity 80: demux-tsout #20 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":21 []

- entity 82: demux-tsout #21 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":22 []

- entity 84: demux-tsout #22 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":23 []

- entity 86: demux-tsout #23 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":24 []

- entity 88: demux-tsout #24 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":25 []

- entity 90: demux-tsout #25 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":26 []

- entity 92: demux-tsout #26 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":27 []

- entity 94: demux-tsout #27 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":28 []

- entity 96: demux-tsout #28 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":29 []

- entity 98: demux-tsout #29 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":30 []

- entity 100: demux-tsout #30 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":31 []

- entity 102: demux-tsout #31 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":32 []

- entity 104: demux-tsout #32 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":33 []

- entity 106: demux-tsout #33 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":34 []

- entity 108: demux-tsout #34 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":35 []

- entity 110: demux-tsout #35 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":36 []

- entity 112: demux-tsout #36 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":37 []

- entity 114: demux-tsout #37 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":38 []

- entity 116: demux-tsout #38 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":39 []

- entity 118: demux-tsout #39 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":40 []

- entity 120: demux-tsout #40 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":41 []

- entity 122: demux-tsout #41 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":42 []

- entity 124: demux-tsout #42 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":43 []

- entity 126: demux-tsout #43 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":44 []

- entity 128: demux-tsout #44 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":45 []

- entity 130: demux-tsout #45 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":46 []

- entity 132: demux-tsout #46 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":47 []

- entity 134: demux-tsout #47 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":48 []

- entity 136: demux-tsout #48 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":49 []

- entity 138: demux-tsout #49 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":50 []

- entity 140: demux-tsout #50 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":51 []

- entity 142: demux-tsout #51 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":52 []

- entity 144: demux-tsout #52 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":53 []

- entity 146: demux-tsout #53 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":54 []

- entity 148: demux-tsout #54 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":55 []

- entity 150: demux-tsout #55 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":56 []

- entity 152: demux-tsout #56 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":57 []

- entity 154: demux-tsout #57 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":58 []

- entity 156: demux-tsout #58 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":59 []

- entity 158: demux-tsout #59 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":60 []

- entity 160: demux-tsout #60 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":61 []

- entity 162: demux-tsout #61 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":62 []

- entity 164: demux-tsout #62 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":63 []

- entity 166: demux-tsout #63 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":64 []

- entity 168: demux-tsout #64 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":65 []

- entity 170: demux-tsout #65 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":66 []

- entity 172: demux-tsout #66 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":67 []

- entity 174: demux-tsout #67 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":68 []

- entity 176: demux-tsout #68 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":69 []

- entity 178: demux-tsout #69 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":70 []

- entity 180: demux-tsout #70 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":71 []

- entity 182: demux-tsout #71 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":72 []

- entity 184: demux-tsout #72 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":73 []

- entity 186: demux-tsout #73 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":74 []

- entity 188: demux-tsout #74 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":75 []

- entity 190: demux-tsout #75 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":76 []

- entity 192: demux-tsout #76 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":77 []

- entity 194: demux-tsout #77 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":78 []

- entity 196: demux-tsout #78 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":79 []

- entity 198: demux-tsout #79 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":80 []

- entity 200: demux-tsout #80 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":81 []

- entity 202: demux-tsout #81 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":82 []

- entity 204: demux-tsout #82 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":83 []

- entity 206: demux-tsout #83 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":84 []

- entity 208: demux-tsout #84 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":85 []

- entity 210: demux-tsout #85 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":86 []

- entity 212: demux-tsout #86 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":87 []

- entity 214: demux-tsout #87 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":88 []

- entity 216: demux-tsout #88 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":89 []

- entity 218: demux-tsout #89 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":90 []

- entity 220: demux-tsout #90 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":91 []

- entity 222: demux-tsout #91 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":92 []

- entity 224: demux-tsout #92 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":93 []

- entity 226: demux-tsout #93 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":94 []

- entity 228: demux-tsout #94 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":95 []

- entity 230: demux-tsout #95 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":96 []

- entity 232: demux-tsout #96 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":97 []

- entity 234: demux-tsout #97 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":98 []

- entity 236: demux-tsout #98 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":99 []

- entity 238: demux-tsout #99 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":100 []

- entity 240: demux-tsout #100 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":101 []

- entity 242: demux-tsout #101 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":102 []

- entity 244: demux-tsout #102 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":103 []

- entity 246: demux-tsout #103 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":104 []

- entity 248: demux-tsout #104 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":105 []

- entity 250: demux-tsout #105 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":106 []

- entity 252: demux-tsout #106 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":107 []

- entity 254: demux-tsout #107 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":108 []

- entity 256: demux-tsout #108 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":109 []

- entity 258: demux-tsout #109 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":110 []

- entity 260: demux-tsout #110 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":111 []

- entity 262: demux-tsout #111 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":112 []

- entity 264: demux-tsout #112 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":113 []

- entity 266: demux-tsout #113 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":114 []

- entity 268: demux-tsout #114 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":115 []

- entity 270: demux-tsout #115 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":116 []

- entity 272: demux-tsout #116 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":117 []

- entity 274: demux-tsout #117 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":118 []

- entity 276: demux-tsout #118 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":119 []

- entity 278: demux-tsout #119 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":120 []

- entity 280: demux-tsout #120 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":121 []

- entity 282: demux-tsout #121 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":122 []

- entity 284: demux-tsout #122 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":123 []

- entity 286: demux-tsout #123 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":124 []

- entity 288: demux-tsout #124 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":125 []

- entity 290: demux-tsout #125 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":126 []

- entity 292: demux-tsout #126 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":127 []

- entity 294: demux-tsout #127 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":128 []

- entity 296: demux-tsout #128 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":129 []

- entity 298: demux-tsout #129 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":130 []

- entity 300: demux-tsout #130 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":131 []

- entity 302: demux-tsout #131 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":132 []

- entity 304: demux-tsout #132 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":133 []

- entity 306: demux-tsout #133 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":134 []

- entity 308: demux-tsout #134 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":135 []

- entity 310: demux-tsout #135 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":136 []

- entity 312: demux-tsout #136 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":137 []

- entity 314: demux-tsout #137 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":138 []

- entity 316: demux-tsout #138 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":139 []

- entity 318: demux-tsout #139 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":140 []

- entity 320: demux-tsout #140 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":141 []

- entity 322: demux-tsout #141 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":142 []

- entity 324: demux-tsout #142 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":143 []

- entity 326: demux-tsout #143 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":144 []

- entity 328: demux-tsout #144 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":145 []

- entity 330: demux-tsout #145 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":146 []

- entity 332: demux-tsout #146 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":147 []

- entity 334: demux-tsout #147 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":148 []

- entity 336: demux-tsout #148 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":149 []

- entity 338: demux-tsout #149 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":150 []

- entity 340: demux-tsout #150 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":151 []

- entity 342: demux-tsout #151 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":152 []

- entity 344: demux-tsout #152 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":153 []

- entity 346: demux-tsout #153 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":154 []

- entity 348: demux-tsout #154 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":155 []

- entity 350: demux-tsout #155 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":156 []

- entity 352: demux-tsout #156 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":157 []

- entity 354: demux-tsout #157 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":158 []

- entity 356: demux-tsout #158 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":159 []

- entity 358: demux-tsout #159 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":160 []

- entity 360: demux-tsout #160 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":161 []

- entity 362: demux-tsout #161 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":162 []

- entity 364: demux-tsout #162 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":163 []

- entity 366: demux-tsout #163 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":164 []

- entity 368: demux-tsout #164 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":165 []

- entity 370: demux-tsout #165 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":166 []

- entity 372: demux-tsout #166 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":167 []

- entity 374: demux-tsout #167 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":168 []

- entity 376: demux-tsout #168 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":169 []

- entity 378: demux-tsout #169 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":170 []

- entity 380: demux-tsout #170 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":171 []

- entity 382: demux-tsout #171 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":172 []

- entity 384: demux-tsout #172 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":173 []

- entity 386: demux-tsout #173 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":174 []

- entity 388: demux-tsout #174 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":175 []

- entity 390: demux-tsout #175 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":176 []

- entity 392: demux-tsout #176 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":177 []

- entity 394: demux-tsout #177 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":178 []

- entity 396: demux-tsout #178 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":179 []

- entity 398: demux-tsout #179 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":180 []

- entity 400: demux-tsout #180 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":181 []

- entity 402: demux-tsout #181 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":182 []

- entity 404: demux-tsout #182 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":183 []

- entity 406: demux-tsout #183 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":184 []

- entity 408: demux-tsout #184 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":185 []

- entity 410: demux-tsout #185 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":186 []

- entity 412: demux-tsout #186 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":187 []

- entity 414: demux-tsout #187 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":188 []

- entity 416: demux-tsout #188 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":189 []

- entity 418: demux-tsout #189 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":190 []

- entity 420: demux-tsout #190 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":191 []

- entity 422: demux-tsout #191 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":192 []

- entity 424: demux-tsout #192 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":193 []

- entity 426: demux-tsout #193 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":194 []

- entity 428: demux-tsout #194 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":195 []

- entity 430: demux-tsout #195 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":196 []

- entity 432: demux-tsout #196 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":197 []

- entity 434: demux-tsout #197 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":198 []

- entity 436: demux-tsout #198 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":199 []

- entity 438: demux-tsout #199 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":200 []

- entity 440: demux-tsout #200 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":201 []

- entity 442: demux-tsout #201 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":202 []

- entity 444: demux-tsout #202 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":203 []

- entity 446: demux-tsout #203 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":204 []

- entity 448: demux-tsout #204 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":205 []

- entity 450: demux-tsout #205 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":206 []

- entity 452: demux-tsout #206 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":207 []

- entity 454: demux-tsout #207 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":208 []

- entity 456: demux-tsout #208 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":209 []

- entity 458: demux-tsout #209 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":210 []

- entity 460: demux-tsout #210 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":211 []

- entity 462: demux-tsout #211 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":212 []

- entity 464: demux-tsout #212 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":213 []

- entity 466: demux-tsout #213 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":214 []

- entity 468: demux-tsout #214 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":215 []

- entity 470: demux-tsout #215 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":216 []

- entity 472: demux-tsout #216 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":217 []

- entity 474: demux-tsout #217 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":218 []

- entity 476: demux-tsout #218 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":219 []

- entity 478: demux-tsout #219 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":220 []

- entity 480: demux-tsout #220 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":221 []

- entity 482: demux-tsout #221 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":222 []

- entity 484: demux-tsout #222 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":223 []

- entity 486: demux-tsout #223 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":224 []

- entity 488: demux-tsout #224 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":225 []

- entity 490: demux-tsout #225 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":226 []

- entity 492: demux-tsout #226 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":227 []

- entity 494: demux-tsout #227 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":228 []

- entity 496: demux-tsout #228 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":229 []

- entity 498: demux-tsout #229 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":230 []

- entity 500: demux-tsout #230 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":231 []

- entity 502: demux-tsout #231 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":232 []

- entity 504: demux-tsout #232 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":233 []

- entity 506: demux-tsout #233 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":234 []

- entity 508: demux-tsout #234 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":235 []

- entity 510: demux-tsout #235 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":236 []

- entity 512: demux-tsout #236 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":237 []

- entity 514: demux-tsout #237 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":238 []

- entity 516: demux-tsout #238 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":239 []

- entity 518: demux-tsout #239 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":240 []

- entity 520: demux-tsout #240 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":241 []

- entity 522: demux-tsout #241 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":242 []

- entity 524: demux-tsout #242 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":243 []

- entity 526: demux-tsout #243 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":244 []

- entity 528: demux-tsout #244 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":245 []

- entity 530: demux-tsout #245 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":246 []

- entity 532: demux-tsout #246 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":247 []

- entity 534: demux-tsout #247 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":248 []

- entity 536: demux-tsout #248 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":249 []

- entity 538: demux-tsout #249 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":250 []

- entity 540: demux-tsout #250 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":251 []

- entity 542: demux-tsout #251 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":252 []

- entity 544: demux-tsout #252 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":253 []

- entity 546: demux-tsout #253 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":254 []

- entity 548: demux-tsout #254 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":255 []

- entity 550: demux-tsout #255 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":256 []

- entity 552: dvb-demux (257 pads, 513 links)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "Auvitek AU8522 QAM/8VSB Fronten":1 [ENABLED]
	pad1: Source
		-> "demux-tsout #0":0 []
		-> "dvr-tsout #0":0 []
	pad2: Source
		-> "demux-tsout #1":0 []
		-> "dvr-tsout #1":0 []
	pad3: Source
		-> "demux-tsout #2":0 []
		-> "dvr-tsout #2":0 []
	pad4: Source
		-> "demux-tsout #3":0 []
		-> "dvr-tsout #3":0 []
	pad5: Source
		-> "demux-tsout #4":0 []
		-> "dvr-tsout #4":0 []
	pad6: Source
		-> "demux-tsout #5":0 []
		-> "dvr-tsout #5":0 []
	pad7: Source
		-> "demux-tsout #6":0 []
		-> "dvr-tsout #6":0 []
	pad8: Source
		-> "demux-tsout #7":0 []
		-> "dvr-tsout #7":0 []
	pad9: Source
		-> "demux-tsout #8":0 []
		-> "dvr-tsout #8":0 []
	pad10: Source
		-> "demux-tsout #9":0 []
		-> "dvr-tsout #9":0 []
	pad11: Source
		-> "demux-tsout #10":0 []
		-> "dvr-tsout #10":0 []
	pad12: Source
		-> "demux-tsout #11":0 []
		-> "dvr-tsout #11":0 []
	pad13: Source
		-> "demux-tsout #12":0 []
		-> "dvr-tsout #12":0 []
	pad14: Source
		-> "demux-tsout #13":0 []
		-> "dvr-tsout #13":0 []
	pad15: Source
		-> "demux-tsout #14":0 []
		-> "dvr-tsout #14":0 []
	pad16: Source
		-> "demux-tsout #15":0 []
		-> "dvr-tsout #15":0 []
	pad17: Source
		-> "demux-tsout #16":0 []
		-> "dvr-tsout #16":0 []
	pad18: Source
		-> "demux-tsout #17":0 []
		-> "dvr-tsout #17":0 []
	pad19: Source
		-> "demux-tsout #18":0 []
		-> "dvr-tsout #18":0 []
	pad20: Source
		-> "demux-tsout #19":0 []
		-> "dvr-tsout #19":0 []
	pad21: Source
		-> "demux-tsout #20":0 []
		-> "dvr-tsout #20":0 []
	pad22: Source
		-> "demux-tsout #21":0 []
		-> "dvr-tsout #21":0 []
	pad23: Source
		-> "demux-tsout #22":0 []
		-> "dvr-tsout #22":0 []
	pad24: Source
		-> "demux-tsout #23":0 []
		-> "dvr-tsout #23":0 []
	pad25: Source
		-> "demux-tsout #24":0 []
		-> "dvr-tsout #24":0 []
	pad26: Source
		-> "demux-tsout #25":0 []
		-> "dvr-tsout #25":0 []
	pad27: Source
		-> "demux-tsout #26":0 []
		-> "dvr-tsout #26":0 []
	pad28: Source
		-> "demux-tsout #27":0 []
		-> "dvr-tsout #27":0 []
	pad29: Source
		-> "demux-tsout #28":0 []
		-> "dvr-tsout #28":0 []
	pad30: Source
		-> "demux-tsout #29":0 []
		-> "dvr-tsout #29":0 []
	pad31: Source
		-> "demux-tsout #30":0 []
		-> "dvr-tsout #30":0 []
	pad32: Source
		-> "demux-tsout #31":0 []
		-> "dvr-tsout #31":0 []
	pad33: Source
		-> "demux-tsout #32":0 []
		-> "dvr-tsout #32":0 []
	pad34: Source
		-> "demux-tsout #33":0 []
		-> "dvr-tsout #33":0 []
	pad35: Source
		-> "demux-tsout #34":0 []
		-> "dvr-tsout #34":0 []
	pad36: Source
		-> "demux-tsout #35":0 []
		-> "dvr-tsout #35":0 []
	pad37: Source
		-> "demux-tsout #36":0 []
		-> "dvr-tsout #36":0 []
	pad38: Source
		-> "demux-tsout #37":0 []
		-> "dvr-tsout #37":0 []
	pad39: Source
		-> "demux-tsout #38":0 []
		-> "dvr-tsout #38":0 []
	pad40: Source
		-> "demux-tsout #39":0 []
		-> "dvr-tsout #39":0 []
	pad41: Source
		-> "demux-tsout #40":0 []
		-> "dvr-tsout #40":0 []
	pad42: Source
		-> "demux-tsout #41":0 []
		-> "dvr-tsout #41":0 []
	pad43: Source
		-> "demux-tsout #42":0 []
		-> "dvr-tsout #42":0 []
	pad44: Source
		-> "demux-tsout #43":0 []
		-> "dvr-tsout #43":0 []
	pad45: Source
		-> "demux-tsout #44":0 []
		-> "dvr-tsout #44":0 []
	pad46: Source
		-> "demux-tsout #45":0 []
		-> "dvr-tsout #45":0 []
	pad47: Source
		-> "demux-tsout #46":0 []
		-> "dvr-tsout #46":0 []
	pad48: Source
		-> "demux-tsout #47":0 []
		-> "dvr-tsout #47":0 []
	pad49: Source
		-> "demux-tsout #48":0 []
		-> "dvr-tsout #48":0 []
	pad50: Source
		-> "demux-tsout #49":0 []
		-> "dvr-tsout #49":0 []
	pad51: Source
		-> "demux-tsout #50":0 []
		-> "dvr-tsout #50":0 []
	pad52: Source
		-> "demux-tsout #51":0 []
		-> "dvr-tsout #51":0 []
	pad53: Source
		-> "demux-tsout #52":0 []
		-> "dvr-tsout #52":0 []
	pad54: Source
		-> "demux-tsout #53":0 []
		-> "dvr-tsout #53":0 []
	pad55: Source
		-> "demux-tsout #54":0 []
		-> "dvr-tsout #54":0 []
	pad56: Source
		-> "demux-tsout #55":0 []
		-> "dvr-tsout #55":0 []
	pad57: Source
		-> "demux-tsout #56":0 []
		-> "dvr-tsout #56":0 []
	pad58: Source
		-> "demux-tsout #57":0 []
		-> "dvr-tsout #57":0 []
	pad59: Source
		-> "demux-tsout #58":0 []
		-> "dvr-tsout #58":0 []
	pad60: Source
		-> "demux-tsout #59":0 []
		-> "dvr-tsout #59":0 []
	pad61: Source
		-> "demux-tsout #60":0 []
		-> "dvr-tsout #60":0 []
	pad62: Source
		-> "demux-tsout #61":0 []
		-> "dvr-tsout #61":0 []
	pad63: Source
		-> "demux-tsout #62":0 []
		-> "dvr-tsout #62":0 []
	pad64: Source
		-> "demux-tsout #63":0 []
		-> "dvr-tsout #63":0 []
	pad65: Source
		-> "demux-tsout #64":0 []
		-> "dvr-tsout #64":0 []
	pad66: Source
		-> "demux-tsout #65":0 []
		-> "dvr-tsout #65":0 []
	pad67: Source
		-> "demux-tsout #66":0 []
		-> "dvr-tsout #66":0 []
	pad68: Source
		-> "demux-tsout #67":0 []
		-> "dvr-tsout #67":0 []
	pad69: Source
		-> "demux-tsout #68":0 []
		-> "dvr-tsout #68":0 []
	pad70: Source
		-> "demux-tsout #69":0 []
		-> "dvr-tsout #69":0 []
	pad71: Source
		-> "demux-tsout #70":0 []
		-> "dvr-tsout #70":0 []
	pad72: Source
		-> "demux-tsout #71":0 []
		-> "dvr-tsout #71":0 []
	pad73: Source
		-> "demux-tsout #72":0 []
		-> "dvr-tsout #72":0 []
	pad74: Source
		-> "demux-tsout #73":0 []
		-> "dvr-tsout #73":0 []
	pad75: Source
		-> "demux-tsout #74":0 []
		-> "dvr-tsout #74":0 []
	pad76: Source
		-> "demux-tsout #75":0 []
		-> "dvr-tsout #75":0 []
	pad77: Source
		-> "demux-tsout #76":0 []
		-> "dvr-tsout #76":0 []
	pad78: Source
		-> "demux-tsout #77":0 []
		-> "dvr-tsout #77":0 []
	pad79: Source
		-> "demux-tsout #78":0 []
		-> "dvr-tsout #78":0 []
	pad80: Source
		-> "demux-tsout #79":0 []
		-> "dvr-tsout #79":0 []
	pad81: Source
		-> "demux-tsout #80":0 []
		-> "dvr-tsout #80":0 []
	pad82: Source
		-> "demux-tsout #81":0 []
		-> "dvr-tsout #81":0 []
	pad83: Source
		-> "demux-tsout #82":0 []
		-> "dvr-tsout #82":0 []
	pad84: Source
		-> "demux-tsout #83":0 []
		-> "dvr-tsout #83":0 []
	pad85: Source
		-> "demux-tsout #84":0 []
		-> "dvr-tsout #84":0 []
	pad86: Source
		-> "demux-tsout #85":0 []
		-> "dvr-tsout #85":0 []
	pad87: Source
		-> "demux-tsout #86":0 []
		-> "dvr-tsout #86":0 []
	pad88: Source
		-> "demux-tsout #87":0 []
		-> "dvr-tsout #87":0 []
	pad89: Source
		-> "demux-tsout #88":0 []
		-> "dvr-tsout #88":0 []
	pad90: Source
		-> "demux-tsout #89":0 []
		-> "dvr-tsout #89":0 []
	pad91: Source
		-> "demux-tsout #90":0 []
		-> "dvr-tsout #90":0 []
	pad92: Source
		-> "demux-tsout #91":0 []
		-> "dvr-tsout #91":0 []
	pad93: Source
		-> "demux-tsout #92":0 []
		-> "dvr-tsout #92":0 []
	pad94: Source
		-> "demux-tsout #93":0 []
		-> "dvr-tsout #93":0 []
	pad95: Source
		-> "demux-tsout #94":0 []
		-> "dvr-tsout #94":0 []
	pad96: Source
		-> "demux-tsout #95":0 []
		-> "dvr-tsout #95":0 []
	pad97: Source
		-> "demux-tsout #96":0 []
		-> "dvr-tsout #96":0 []
	pad98: Source
		-> "demux-tsout #97":0 []
		-> "dvr-tsout #97":0 []
	pad99: Source
		-> "demux-tsout #98":0 []
		-> "dvr-tsout #98":0 []
	pad100: Source
		-> "demux-tsout #99":0 []
		-> "dvr-tsout #99":0 []
	pad101: Source
		-> "demux-tsout #100":0 []
		-> "dvr-tsout #100":0 []
	pad102: Source
		-> "demux-tsout #101":0 []
		-> "dvr-tsout #101":0 []
	pad103: Source
		-> "demux-tsout #102":0 []
		-> "dvr-tsout #102":0 []
	pad104: Source
		-> "demux-tsout #103":0 []
		-> "dvr-tsout #103":0 []
	pad105: Source
		-> "demux-tsout #104":0 []
		-> "dvr-tsout #104":0 []
	pad106: Source
		-> "demux-tsout #105":0 []
		-> "dvr-tsout #105":0 []
	pad107: Source
		-> "demux-tsout #106":0 []
		-> "dvr-tsout #106":0 []
	pad108: Source
		-> "demux-tsout #107":0 []
		-> "dvr-tsout #107":0 []
	pad109: Source
		-> "demux-tsout #108":0 []
		-> "dvr-tsout #108":0 []
	pad110: Source
		-> "demux-tsout #109":0 []
		-> "dvr-tsout #109":0 []
	pad111: Source
		-> "demux-tsout #110":0 []
		-> "dvr-tsout #110":0 []
	pad112: Source
		-> "demux-tsout #111":0 []
		-> "dvr-tsout #111":0 []
	pad113: Source
		-> "demux-tsout #112":0 []
		-> "dvr-tsout #112":0 []
	pad114: Source
		-> "demux-tsout #113":0 []
		-> "dvr-tsout #113":0 []
	pad115: Source
		-> "demux-tsout #114":0 []
		-> "dvr-tsout #114":0 []
	pad116: Source
		-> "demux-tsout #115":0 []
		-> "dvr-tsout #115":0 []
	pad117: Source
		-> "demux-tsout #116":0 []
		-> "dvr-tsout #116":0 []
	pad118: Source
		-> "demux-tsout #117":0 []
		-> "dvr-tsout #117":0 []
	pad119: Source
		-> "demux-tsout #118":0 []
		-> "dvr-tsout #118":0 []
	pad120: Source
		-> "demux-tsout #119":0 []
		-> "dvr-tsout #119":0 []
	pad121: Source
		-> "demux-tsout #120":0 []
		-> "dvr-tsout #120":0 []
	pad122: Source
		-> "demux-tsout #121":0 []
		-> "dvr-tsout #121":0 []
	pad123: Source
		-> "demux-tsout #122":0 []
		-> "dvr-tsout #122":0 []
	pad124: Source
		-> "demux-tsout #123":0 []
		-> "dvr-tsout #123":0 []
	pad125: Source
		-> "demux-tsout #124":0 []
		-> "dvr-tsout #124":0 []
	pad126: Source
		-> "demux-tsout #125":0 []
		-> "dvr-tsout #125":0 []
	pad127: Source
		-> "demux-tsout #126":0 []
		-> "dvr-tsout #126":0 []
	pad128: Source
		-> "demux-tsout #127":0 []
		-> "dvr-tsout #127":0 []
	pad129: Source
		-> "demux-tsout #128":0 []
		-> "dvr-tsout #128":0 []
	pad130: Source
		-> "demux-tsout #129":0 []
		-> "dvr-tsout #129":0 []
	pad131: Source
		-> "demux-tsout #130":0 []
		-> "dvr-tsout #130":0 []
	pad132: Source
		-> "demux-tsout #131":0 []
		-> "dvr-tsout #131":0 []
	pad133: Source
		-> "demux-tsout #132":0 []
		-> "dvr-tsout #132":0 []
	pad134: Source
		-> "demux-tsout #133":0 []
		-> "dvr-tsout #133":0 []
	pad135: Source
		-> "demux-tsout #134":0 []
		-> "dvr-tsout #134":0 []
	pad136: Source
		-> "demux-tsout #135":0 []
		-> "dvr-tsout #135":0 []
	pad137: Source
		-> "demux-tsout #136":0 []
		-> "dvr-tsout #136":0 []
	pad138: Source
		-> "demux-tsout #137":0 []
		-> "dvr-tsout #137":0 []
	pad139: Source
		-> "demux-tsout #138":0 []
		-> "dvr-tsout #138":0 []
	pad140: Source
		-> "demux-tsout #139":0 []
		-> "dvr-tsout #139":0 []
	pad141: Source
		-> "demux-tsout #140":0 []
		-> "dvr-tsout #140":0 []
	pad142: Source
		-> "demux-tsout #141":0 []
		-> "dvr-tsout #141":0 []
	pad143: Source
		-> "demux-tsout #142":0 []
		-> "dvr-tsout #142":0 []
	pad144: Source
		-> "demux-tsout #143":0 []
		-> "dvr-tsout #143":0 []
	pad145: Source
		-> "demux-tsout #144":0 []
		-> "dvr-tsout #144":0 []
	pad146: Source
		-> "demux-tsout #145":0 []
		-> "dvr-tsout #145":0 []
	pad147: Source
		-> "demux-tsout #146":0 []
		-> "dvr-tsout #146":0 []
	pad148: Source
		-> "demux-tsout #147":0 []
		-> "dvr-tsout #147":0 []
	pad149: Source
		-> "demux-tsout #148":0 []
		-> "dvr-tsout #148":0 []
	pad150: Source
		-> "demux-tsout #149":0 []
		-> "dvr-tsout #149":0 []
	pad151: Source
		-> "demux-tsout #150":0 []
		-> "dvr-tsout #150":0 []
	pad152: Source
		-> "demux-tsout #151":0 []
		-> "dvr-tsout #151":0 []
	pad153: Source
		-> "demux-tsout #152":0 []
		-> "dvr-tsout #152":0 []
	pad154: Source
		-> "demux-tsout #153":0 []
		-> "dvr-tsout #153":0 []
	pad155: Source
		-> "demux-tsout #154":0 []
		-> "dvr-tsout #154":0 []
	pad156: Source
		-> "demux-tsout #155":0 []
		-> "dvr-tsout #155":0 []
	pad157: Source
		-> "demux-tsout #156":0 []
		-> "dvr-tsout #156":0 []
	pad158: Source
		-> "demux-tsout #157":0 []
		-> "dvr-tsout #157":0 []
	pad159: Source
		-> "demux-tsout #158":0 []
		-> "dvr-tsout #158":0 []
	pad160: Source
		-> "demux-tsout #159":0 []
		-> "dvr-tsout #159":0 []
	pad161: Source
		-> "demux-tsout #160":0 []
		-> "dvr-tsout #160":0 []
	pad162: Source
		-> "demux-tsout #161":0 []
		-> "dvr-tsout #161":0 []
	pad163: Source
		-> "demux-tsout #162":0 []
		-> "dvr-tsout #162":0 []
	pad164: Source
		-> "demux-tsout #163":0 []
		-> "dvr-tsout #163":0 []
	pad165: Source
		-> "demux-tsout #164":0 []
		-> "dvr-tsout #164":0 []
	pad166: Source
		-> "demux-tsout #165":0 []
		-> "dvr-tsout #165":0 []
	pad167: Source
		-> "demux-tsout #166":0 []
		-> "dvr-tsout #166":0 []
	pad168: Source
		-> "demux-tsout #167":0 []
		-> "dvr-tsout #167":0 []
	pad169: Source
		-> "demux-tsout #168":0 []
		-> "dvr-tsout #168":0 []
	pad170: Source
		-> "demux-tsout #169":0 []
		-> "dvr-tsout #169":0 []
	pad171: Source
		-> "demux-tsout #170":0 []
		-> "dvr-tsout #170":0 []
	pad172: Source
		-> "demux-tsout #171":0 []
		-> "dvr-tsout #171":0 []
	pad173: Source
		-> "demux-tsout #172":0 []
		-> "dvr-tsout #172":0 []
	pad174: Source
		-> "demux-tsout #173":0 []
		-> "dvr-tsout #173":0 []
	pad175: Source
		-> "demux-tsout #174":0 []
		-> "dvr-tsout #174":0 []
	pad176: Source
		-> "demux-tsout #175":0 []
		-> "dvr-tsout #175":0 []
	pad177: Source
		-> "demux-tsout #176":0 []
		-> "dvr-tsout #176":0 []
	pad178: Source
		-> "demux-tsout #177":0 []
		-> "dvr-tsout #177":0 []
	pad179: Source
		-> "demux-tsout #178":0 []
		-> "dvr-tsout #178":0 []
	pad180: Source
		-> "demux-tsout #179":0 []
		-> "dvr-tsout #179":0 []
	pad181: Source
		-> "demux-tsout #180":0 []
		-> "dvr-tsout #180":0 []
	pad182: Source
		-> "demux-tsout #181":0 []
		-> "dvr-tsout #181":0 []
	pad183: Source
		-> "demux-tsout #182":0 []
		-> "dvr-tsout #182":0 []
	pad184: Source
		-> "demux-tsout #183":0 []
		-> "dvr-tsout #183":0 []
	pad185: Source
		-> "demux-tsout #184":0 []
		-> "dvr-tsout #184":0 []
	pad186: Source
		-> "demux-tsout #185":0 []
		-> "dvr-tsout #185":0 []
	pad187: Source
		-> "demux-tsout #186":0 []
		-> "dvr-tsout #186":0 []
	pad188: Source
		-> "demux-tsout #187":0 []
		-> "dvr-tsout #187":0 []
	pad189: Source
		-> "demux-tsout #188":0 []
		-> "dvr-tsout #188":0 []
	pad190: Source
		-> "demux-tsout #189":0 []
		-> "dvr-tsout #189":0 []
	pad191: Source
		-> "demux-tsout #190":0 []
		-> "dvr-tsout #190":0 []
	pad192: Source
		-> "demux-tsout #191":0 []
		-> "dvr-tsout #191":0 []
	pad193: Source
		-> "demux-tsout #192":0 []
		-> "dvr-tsout #192":0 []
	pad194: Source
		-> "demux-tsout #193":0 []
		-> "dvr-tsout #193":0 []
	pad195: Source
		-> "demux-tsout #194":0 []
		-> "dvr-tsout #194":0 []
	pad196: Source
		-> "demux-tsout #195":0 []
		-> "dvr-tsout #195":0 []
	pad197: Source
		-> "demux-tsout #196":0 []
		-> "dvr-tsout #196":0 []
	pad198: Source
		-> "demux-tsout #197":0 []
		-> "dvr-tsout #197":0 []
	pad199: Source
		-> "demux-tsout #198":0 []
		-> "dvr-tsout #198":0 []
	pad200: Source
		-> "demux-tsout #199":0 []
		-> "dvr-tsout #199":0 []
	pad201: Source
		-> "demux-tsout #200":0 []
		-> "dvr-tsout #200":0 []
	pad202: Source
		-> "demux-tsout #201":0 []
		-> "dvr-tsout #201":0 []
	pad203: Source
		-> "demux-tsout #202":0 []
		-> "dvr-tsout #202":0 []
	pad204: Source
		-> "demux-tsout #203":0 []
		-> "dvr-tsout #203":0 []
	pad205: Source
		-> "demux-tsout #204":0 []
		-> "dvr-tsout #204":0 []
	pad206: Source
		-> "demux-tsout #205":0 []
		-> "dvr-tsout #205":0 []
	pad207: Source
		-> "demux-tsout #206":0 []
		-> "dvr-tsout #206":0 []
	pad208: Source
		-> "demux-tsout #207":0 []
		-> "dvr-tsout #207":0 []
	pad209: Source
		-> "demux-tsout #208":0 []
		-> "dvr-tsout #208":0 []
	pad210: Source
		-> "demux-tsout #209":0 []
		-> "dvr-tsout #209":0 []
	pad211: Source
		-> "demux-tsout #210":0 []
		-> "dvr-tsout #210":0 []
	pad212: Source
		-> "demux-tsout #211":0 []
		-> "dvr-tsout #211":0 []
	pad213: Source
		-> "demux-tsout #212":0 []
		-> "dvr-tsout #212":0 []
	pad214: Source
		-> "demux-tsout #213":0 []
		-> "dvr-tsout #213":0 []
	pad215: Source
		-> "demux-tsout #214":0 []
		-> "dvr-tsout #214":0 []
	pad216: Source
		-> "demux-tsout #215":0 []
		-> "dvr-tsout #215":0 []
	pad217: Source
		-> "demux-tsout #216":0 []
		-> "dvr-tsout #216":0 []
	pad218: Source
		-> "demux-tsout #217":0 []
		-> "dvr-tsout #217":0 []
	pad219: Source
		-> "demux-tsout #218":0 []
		-> "dvr-tsout #218":0 []
	pad220: Source
		-> "demux-tsout #219":0 []
		-> "dvr-tsout #219":0 []
	pad221: Source
		-> "demux-tsout #220":0 []
		-> "dvr-tsout #220":0 []
	pad222: Source
		-> "demux-tsout #221":0 []
		-> "dvr-tsout #221":0 []
	pad223: Source
		-> "demux-tsout #222":0 []
		-> "dvr-tsout #222":0 []
	pad224: Source
		-> "demux-tsout #223":0 []
		-> "dvr-tsout #223":0 []
	pad225: Source
		-> "demux-tsout #224":0 []
		-> "dvr-tsout #224":0 []
	pad226: Source
		-> "demux-tsout #225":0 []
		-> "dvr-tsout #225":0 []
	pad227: Source
		-> "demux-tsout #226":0 []
		-> "dvr-tsout #226":0 []
	pad228: Source
		-> "demux-tsout #227":0 []
		-> "dvr-tsout #227":0 []
	pad229: Source
		-> "demux-tsout #228":0 []
		-> "dvr-tsout #228":0 []
	pad230: Source
		-> "demux-tsout #229":0 []
		-> "dvr-tsout #229":0 []
	pad231: Source
		-> "demux-tsout #230":0 []
		-> "dvr-tsout #230":0 []
	pad232: Source
		-> "demux-tsout #231":0 []
		-> "dvr-tsout #231":0 []
	pad233: Source
		-> "demux-tsout #232":0 []
		-> "dvr-tsout #232":0 []
	pad234: Source
		-> "demux-tsout #233":0 []
		-> "dvr-tsout #233":0 []
	pad235: Source
		-> "demux-tsout #234":0 []
		-> "dvr-tsout #234":0 []
	pad236: Source
		-> "demux-tsout #235":0 []
		-> "dvr-tsout #235":0 []
	pad237: Source
		-> "demux-tsout #236":0 []
		-> "dvr-tsout #236":0 []
	pad238: Source
		-> "demux-tsout #237":0 []
		-> "dvr-tsout #237":0 []
	pad239: Source
		-> "demux-tsout #238":0 []
		-> "dvr-tsout #238":0 []
	pad240: Source
		-> "demux-tsout #239":0 []
		-> "dvr-tsout #239":0 []
	pad241: Source
		-> "demux-tsout #240":0 []
		-> "dvr-tsout #240":0 []
	pad242: Source
		-> "demux-tsout #241":0 []
		-> "dvr-tsout #241":0 []
	pad243: Source
		-> "demux-tsout #242":0 []
		-> "dvr-tsout #242":0 []
	pad244: Source
		-> "demux-tsout #243":0 []
		-> "dvr-tsout #243":0 []
	pad245: Source
		-> "demux-tsout #244":0 []
		-> "dvr-tsout #244":0 []
	pad246: Source
		-> "demux-tsout #245":0 []
		-> "dvr-tsout #245":0 []
	pad247: Source
		-> "demux-tsout #246":0 []
		-> "dvr-tsout #246":0 []
	pad248: Source
		-> "demux-tsout #247":0 []
		-> "dvr-tsout #247":0 []
	pad249: Source
		-> "demux-tsout #248":0 []
		-> "dvr-tsout #248":0 []
	pad250: Source
		-> "demux-tsout #249":0 []
		-> "dvr-tsout #249":0 []
	pad251: Source
		-> "demux-tsout #250":0 []
		-> "dvr-tsout #250":0 []
	pad252: Source
		-> "demux-tsout #251":0 []
		-> "dvr-tsout #251":0 []
	pad253: Source
		-> "demux-tsout #252":0 []
		-> "dvr-tsout #252":0 []
	pad254: Source
		-> "demux-tsout #253":0 []
		-> "dvr-tsout #253":0 []
	pad255: Source
		-> "demux-tsout #254":0 []
		-> "dvr-tsout #254":0 []
	pad256: Source
		-> "demux-tsout #255":0 []
		-> "dvr-tsout #255":0 []

- entity 812: dvr-tsout #0 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":1 []

- entity 814: dvr-tsout #1 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":2 []

- entity 816: dvr-tsout #2 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":3 []

- entity 818: dvr-tsout #3 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":4 []

- entity 820: dvr-tsout #4 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":5 []

- entity 822: dvr-tsout #5 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":6 []

- entity 824: dvr-tsout #6 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":7 []

- entity 826: dvr-tsout #7 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":8 []

- entity 828: dvr-tsout #8 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":9 []

- entity 830: dvr-tsout #9 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":10 []

- entity 832: dvr-tsout #10 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":11 []

- entity 834: dvr-tsout #11 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":12 []

- entity 836: dvr-tsout #12 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":13 []

- entity 838: dvr-tsout #13 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":14 []

- entity 840: dvr-tsout #14 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":15 []

- entity 842: dvr-tsout #15 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":16 []

- entity 844: dvr-tsout #16 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":17 []

- entity 846: dvr-tsout #17 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":18 []

- entity 848: dvr-tsout #18 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":19 []

- entity 850: dvr-tsout #19 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":20 []

- entity 852: dvr-tsout #20 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":21 []

- entity 854: dvr-tsout #21 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":22 []

- entity 856: dvr-tsout #22 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":23 []

- entity 858: dvr-tsout #23 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":24 []

- entity 860: dvr-tsout #24 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":25 []

- entity 862: dvr-tsout #25 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":26 []

- entity 864: dvr-tsout #26 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":27 []

- entity 866: dvr-tsout #27 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":28 []

- entity 868: dvr-tsout #28 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":29 []

- entity 870: dvr-tsout #29 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":30 []

- entity 872: dvr-tsout #30 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":31 []

- entity 874: dvr-tsout #31 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":32 []

- entity 876: dvr-tsout #32 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":33 []

- entity 878: dvr-tsout #33 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":34 []

- entity 880: dvr-tsout #34 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":35 []

- entity 882: dvr-tsout #35 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":36 []

- entity 884: dvr-tsout #36 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":37 []

- entity 886: dvr-tsout #37 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":38 []

- entity 888: dvr-tsout #38 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":39 []

- entity 890: dvr-tsout #39 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":40 []

- entity 892: dvr-tsout #40 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":41 []

- entity 894: dvr-tsout #41 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":42 []

- entity 896: dvr-tsout #42 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":43 []

- entity 898: dvr-tsout #43 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":44 []

- entity 900: dvr-tsout #44 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":45 []

- entity 902: dvr-tsout #45 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":46 []

- entity 904: dvr-tsout #46 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":47 []

- entity 906: dvr-tsout #47 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":48 []

- entity 908: dvr-tsout #48 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":49 []

- entity 910: dvr-tsout #49 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":50 []

- entity 912: dvr-tsout #50 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":51 []

- entity 914: dvr-tsout #51 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":52 []

- entity 916: dvr-tsout #52 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":53 []

- entity 918: dvr-tsout #53 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":54 []

- entity 920: dvr-tsout #54 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":55 []

- entity 922: dvr-tsout #55 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":56 []

- entity 924: dvr-tsout #56 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":57 []

- entity 926: dvr-tsout #57 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":58 []

- entity 928: dvr-tsout #58 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":59 []

- entity 930: dvr-tsout #59 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":60 []

- entity 932: dvr-tsout #60 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":61 []

- entity 934: dvr-tsout #61 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":62 []

- entity 936: dvr-tsout #62 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":63 []

- entity 938: dvr-tsout #63 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":64 []

- entity 940: dvr-tsout #64 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":65 []

- entity 942: dvr-tsout #65 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":66 []

- entity 944: dvr-tsout #66 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":67 []

- entity 946: dvr-tsout #67 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":68 []

- entity 948: dvr-tsout #68 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":69 []

- entity 950: dvr-tsout #69 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":70 []

- entity 952: dvr-tsout #70 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":71 []

- entity 954: dvr-tsout #71 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":72 []

- entity 956: dvr-tsout #72 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":73 []

- entity 958: dvr-tsout #73 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":74 []

- entity 960: dvr-tsout #74 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":75 []

- entity 962: dvr-tsout #75 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":76 []

- entity 964: dvr-tsout #76 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":77 []

- entity 966: dvr-tsout #77 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":78 []

- entity 968: dvr-tsout #78 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":79 []

- entity 970: dvr-tsout #79 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":80 []

- entity 972: dvr-tsout #80 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":81 []

- entity 974: dvr-tsout #81 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":82 []

- entity 976: dvr-tsout #82 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":83 []

- entity 978: dvr-tsout #83 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":84 []

- entity 980: dvr-tsout #84 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":85 []

- entity 982: dvr-tsout #85 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":86 []

- entity 984: dvr-tsout #86 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":87 []

- entity 986: dvr-tsout #87 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":88 []

- entity 988: dvr-tsout #88 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":89 []

- entity 990: dvr-tsout #89 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":90 []

- entity 992: dvr-tsout #90 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":91 []

- entity 994: dvr-tsout #91 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":92 []

- entity 996: dvr-tsout #92 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":93 []

- entity 998: dvr-tsout #93 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":94 []

- entity 1000: dvr-tsout #94 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":95 []

- entity 1002: dvr-tsout #95 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":96 []

- entity 1004: dvr-tsout #96 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":97 []

- entity 1006: dvr-tsout #97 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":98 []

- entity 1008: dvr-tsout #98 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":99 []

- entity 1010: dvr-tsout #99 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":100 []

- entity 1012: dvr-tsout #100 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":101 []

- entity 1014: dvr-tsout #101 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":102 []

- entity 1016: dvr-tsout #102 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":103 []

- entity 1018: dvr-tsout #103 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":104 []

- entity 1020: dvr-tsout #104 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":105 []

- entity 1022: dvr-tsout #105 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":106 []

- entity 1024: dvr-tsout #106 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":107 []

- entity 1026: dvr-tsout #107 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":108 []

- entity 1028: dvr-tsout #108 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":109 []

- entity 1030: dvr-tsout #109 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":110 []

- entity 1032: dvr-tsout #110 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":111 []

- entity 1034: dvr-tsout #111 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":112 []

- entity 1036: dvr-tsout #112 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":113 []

- entity 1038: dvr-tsout #113 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":114 []

- entity 1040: dvr-tsout #114 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":115 []

- entity 1042: dvr-tsout #115 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":116 []

- entity 1044: dvr-tsout #116 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":117 []

- entity 1046: dvr-tsout #117 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":118 []

- entity 1048: dvr-tsout #118 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":119 []

- entity 1050: dvr-tsout #119 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":120 []

- entity 1052: dvr-tsout #120 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":121 []

- entity 1054: dvr-tsout #121 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":122 []

- entity 1056: dvr-tsout #122 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":123 []

- entity 1058: dvr-tsout #123 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":124 []

- entity 1060: dvr-tsout #124 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":125 []

- entity 1062: dvr-tsout #125 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":126 []

- entity 1064: dvr-tsout #126 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":127 []

- entity 1066: dvr-tsout #127 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":128 []

- entity 1068: dvr-tsout #128 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":129 []

- entity 1070: dvr-tsout #129 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":130 []

- entity 1072: dvr-tsout #130 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":131 []

- entity 1074: dvr-tsout #131 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":132 []

- entity 1076: dvr-tsout #132 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":133 []

- entity 1078: dvr-tsout #133 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":134 []

- entity 1080: dvr-tsout #134 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":135 []

- entity 1082: dvr-tsout #135 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":136 []

- entity 1084: dvr-tsout #136 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":137 []

- entity 1086: dvr-tsout #137 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":138 []

- entity 1088: dvr-tsout #138 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":139 []

- entity 1090: dvr-tsout #139 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":140 []

- entity 1092: dvr-tsout #140 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":141 []

- entity 1094: dvr-tsout #141 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":142 []

- entity 1096: dvr-tsout #142 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":143 []

- entity 1098: dvr-tsout #143 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":144 []

- entity 1100: dvr-tsout #144 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":145 []

- entity 1102: dvr-tsout #145 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":146 []

- entity 1104: dvr-tsout #146 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":147 []

- entity 1106: dvr-tsout #147 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":148 []

- entity 1108: dvr-tsout #148 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":149 []

- entity 1110: dvr-tsout #149 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":150 []

- entity 1112: dvr-tsout #150 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":151 []

- entity 1114: dvr-tsout #151 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":152 []

- entity 1116: dvr-tsout #152 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":153 []

- entity 1118: dvr-tsout #153 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":154 []

- entity 1120: dvr-tsout #154 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":155 []

- entity 1122: dvr-tsout #155 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":156 []

- entity 1124: dvr-tsout #156 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":157 []

- entity 1126: dvr-tsout #157 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":158 []

- entity 1128: dvr-tsout #158 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":159 []

- entity 1130: dvr-tsout #159 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":160 []

- entity 1132: dvr-tsout #160 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":161 []

- entity 1134: dvr-tsout #161 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":162 []

- entity 1136: dvr-tsout #162 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":163 []

- entity 1138: dvr-tsout #163 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":164 []

- entity 1140: dvr-tsout #164 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":165 []

- entity 1142: dvr-tsout #165 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":166 []

- entity 1144: dvr-tsout #166 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":167 []

- entity 1146: dvr-tsout #167 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":168 []

- entity 1148: dvr-tsout #168 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":169 []

- entity 1150: dvr-tsout #169 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":170 []

- entity 1152: dvr-tsout #170 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":171 []

- entity 1154: dvr-tsout #171 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":172 []

- entity 1156: dvr-tsout #172 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":173 []

- entity 1158: dvr-tsout #173 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":174 []

- entity 1160: dvr-tsout #174 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":175 []

- entity 1162: dvr-tsout #175 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":176 []

- entity 1164: dvr-tsout #176 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":177 []

- entity 1166: dvr-tsout #177 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":178 []

- entity 1168: dvr-tsout #178 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":179 []

- entity 1170: dvr-tsout #179 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":180 []

- entity 1172: dvr-tsout #180 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":181 []

- entity 1174: dvr-tsout #181 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":182 []

- entity 1176: dvr-tsout #182 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":183 []

- entity 1178: dvr-tsout #183 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":184 []

- entity 1180: dvr-tsout #184 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":185 []

- entity 1182: dvr-tsout #185 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":186 []

- entity 1184: dvr-tsout #186 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":187 []

- entity 1186: dvr-tsout #187 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":188 []

- entity 1188: dvr-tsout #188 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":189 []

- entity 1190: dvr-tsout #189 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":190 []

- entity 1192: dvr-tsout #190 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":191 []

- entity 1194: dvr-tsout #191 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":192 []

- entity 1196: dvr-tsout #192 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":193 []

- entity 1198: dvr-tsout #193 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":194 []

- entity 1200: dvr-tsout #194 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":195 []

- entity 1202: dvr-tsout #195 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":196 []

- entity 1204: dvr-tsout #196 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":197 []

- entity 1206: dvr-tsout #197 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":198 []

- entity 1208: dvr-tsout #198 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":199 []

- entity 1210: dvr-tsout #199 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":200 []

- entity 1212: dvr-tsout #200 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":201 []

- entity 1214: dvr-tsout #201 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":202 []

- entity 1216: dvr-tsout #202 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":203 []

- entity 1218: dvr-tsout #203 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":204 []

- entity 1220: dvr-tsout #204 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":205 []

- entity 1222: dvr-tsout #205 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":206 []

- entity 1224: dvr-tsout #206 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":207 []

- entity 1226: dvr-tsout #207 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":208 []

- entity 1228: dvr-tsout #208 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":209 []

- entity 1230: dvr-tsout #209 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":210 []

- entity 1232: dvr-tsout #210 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":211 []

- entity 1234: dvr-tsout #211 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":212 []

- entity 1236: dvr-tsout #212 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":213 []

- entity 1238: dvr-tsout #213 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":214 []

- entity 1240: dvr-tsout #214 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":215 []

- entity 1242: dvr-tsout #215 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":216 []

- entity 1244: dvr-tsout #216 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":217 []

- entity 1246: dvr-tsout #217 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":218 []

- entity 1248: dvr-tsout #218 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":219 []

- entity 1250: dvr-tsout #219 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":220 []

- entity 1252: dvr-tsout #220 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":221 []

- entity 1254: dvr-tsout #221 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":222 []

- entity 1256: dvr-tsout #222 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":223 []

- entity 1258: dvr-tsout #223 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":224 []

- entity 1260: dvr-tsout #224 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":225 []

- entity 1262: dvr-tsout #225 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":226 []

- entity 1264: dvr-tsout #226 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":227 []

- entity 1266: dvr-tsout #227 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":228 []

- entity 1268: dvr-tsout #228 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":229 []

- entity 1270: dvr-tsout #229 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":230 []

- entity 1272: dvr-tsout #230 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":231 []

- entity 1274: dvr-tsout #231 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":232 []

- entity 1276: dvr-tsout #232 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":233 []

- entity 1278: dvr-tsout #233 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":234 []

- entity 1280: dvr-tsout #234 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":235 []

- entity 1282: dvr-tsout #235 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":236 []

- entity 1284: dvr-tsout #236 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":237 []

- entity 1286: dvr-tsout #237 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":238 []

- entity 1288: dvr-tsout #238 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":239 []

- entity 1290: dvr-tsout #239 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":240 []

- entity 1292: dvr-tsout #240 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":241 []

- entity 1294: dvr-tsout #241 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":242 []

- entity 1296: dvr-tsout #242 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":243 []

- entity 1298: dvr-tsout #243 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":244 []

- entity 1300: dvr-tsout #244 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":245 []

- entity 1302: dvr-tsout #245 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":246 []

- entity 1304: dvr-tsout #246 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":247 []

- entity 1306: dvr-tsout #247 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":248 []

- entity 1308: dvr-tsout #248 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":249 []

- entity 1310: dvr-tsout #249 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":250 []

- entity 1312: dvr-tsout #250 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":251 []

- entity 1314: dvr-tsout #251 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":252 []

- entity 1316: dvr-tsout #252 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":253 []

- entity 1318: dvr-tsout #253 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":254 []

- entity 1320: dvr-tsout #254 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":255 []

- entity 1322: dvr-tsout #255 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":256 []

- entity 2868: USB Mixer (3 pads, 2 links)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "au8522 13-0047":2 [ENABLED]
	pad1: Source
	pad2: Source
		-> "USB Audio":0 [ENABLED]

- entity 2875: USB Audio (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "USB Mixer":2 [ENABLED]


[-- Attachment #3: media_graph.dot --]
[-- Type: application/msword-template, Size: 63098 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
@ 2019-01-26  0:19     ` shuah
  0 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-26  0:19 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: alsa-devel, linux-kernel, tiwai, hverkuil, mchehab, shuah, linux-media

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

Hi Sakari,

On 1/25/19 8:28 AM, Sakari Ailus wrote:
> Hi Shuah,
> 
> On Thu, Jan 24, 2019 at 01:32:37PM -0700, Shuah Khan wrote:
>> Media Device Allocator API to allows multiple drivers share a media device.
>> This API solves a very common use-case for media devices where one physical
>> device (an USB stick) provides both audio and video. When such media device
>> exposes a standard USB Audio class, a proprietary Video class, two or more
>> independent drivers will share a single physical USB bridge. In such cases,
>> it is necessary to coordinate access to the shared resource.
>>
>> Using this API, drivers can allocate a media device with the shared struct
>> device as the key. Once the media device is allocated by a driver, other
>> drivers can get a reference to it. The media device is released when all
>> the references are released.
> 
> Thanks for the update. I have to apologise I haven't ended up reviewing the
> set for some time. After taking a look at the current version, I'm happy to
> see that a number of issues recognised during earlier review rounds have
> been addressed.
> 
> Would you happen to have a media graph (media-ctl --print-dot and media-ctl
> -p) from the device? That'd help understanding the device a bit better for
> those who are not familiar with it.
> 

Please see the attached files for the below. It came in very handy
for testing partial graphs as I did bind and unbind of the drivers
in this mix.

media-ctl --print-dot and
media-ctl --print-topology

thanks,
-- Shuah

[-- Attachment #2: media_graph_topo --]
[-- Type: text/plain, Size: 87218 bytes --]

Media controller API version 5.0.0

Media device information
------------------------
driver          au0828
model           WinTV HVR-950
serial          4035198866
bus info        usb-0000:00:1a.0-1.4
hw revision     0x5
driver version  5.0.0

Device topology
- entity 1: au8522 13-0047 (3 pads, 6 links)
            type V4L2 subdev subtype Decoder flags 0
	pad0: Sink
		<- "Xceive XC5000":1 []
		<- "Composite":0 []
		<- "S-Video":0 []
	pad1: Source
		-> "au0828a video":0 [ENABLED]
		-> "au0828a vbi":0 [ENABLED]
	pad2: Source
		-> "USB Mixer":0 [ENABLED]

- entity 5: Xceive XC5000 (3 pads, 3 links)
            type V4L2 subdev subtype Tuner flags 0
	pad0: Sink
		-> "Auvitek AU8522 QAM/8VSB Fronten":0 []
		<- "Television":0 [ENABLED]
	pad1: Source
		-> "au8522 13-0047":0 []
	pad2: Source

- entity 9: Television (1 pad, 1 link)
            type Node subtype Unknown flags 2
	pad0: Source
		-> "Xceive XC5000":0 [ENABLED]

- entity 11: Composite (1 pad, 1 link)
             type Node subtype Unknown flags 2
	pad0: Source
		-> "au8522 13-0047":0 []

- entity 13: S-Video (1 pad, 1 link)
             type Node subtype Unknown flags 2
	pad0: Source
		-> "au8522 13-0047":0 []

- entity 15: au0828a video (1 pad, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/video0
	pad0: Sink
		<- "au8522 13-0047":1 [ENABLED]

- entity 19: au0828a vbi (1 pad, 1 link)
             type Node subtype Unknown flags 0
             device node name /dev/vbi0
	pad0: Sink
		<- "au8522 13-0047":1 [ENABLED]

- entity 35: Auvitek AU8522 QAM/8VSB Fronten (2 pads, 2 links)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "Xceive XC5000":0 []
	pad1: Source
		-> "dvb-demux":0 [ENABLED]

- entity 40: demux-tsout #0 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":1 []

- entity 42: demux-tsout #1 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":2 []

- entity 44: demux-tsout #2 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":3 []

- entity 46: demux-tsout #3 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":4 []

- entity 48: demux-tsout #4 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":5 []

- entity 50: demux-tsout #5 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":6 []

- entity 52: demux-tsout #6 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":7 []

- entity 54: demux-tsout #7 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":8 []

- entity 56: demux-tsout #8 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":9 []

- entity 58: demux-tsout #9 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":10 []

- entity 60: demux-tsout #10 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":11 []

- entity 62: demux-tsout #11 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":12 []

- entity 64: demux-tsout #12 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":13 []

- entity 66: demux-tsout #13 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":14 []

- entity 68: demux-tsout #14 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":15 []

- entity 70: demux-tsout #15 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":16 []

- entity 72: demux-tsout #16 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":17 []

- entity 74: demux-tsout #17 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":18 []

- entity 76: demux-tsout #18 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":19 []

- entity 78: demux-tsout #19 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":20 []

- entity 80: demux-tsout #20 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":21 []

- entity 82: demux-tsout #21 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":22 []

- entity 84: demux-tsout #22 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":23 []

- entity 86: demux-tsout #23 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":24 []

- entity 88: demux-tsout #24 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":25 []

- entity 90: demux-tsout #25 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":26 []

- entity 92: demux-tsout #26 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":27 []

- entity 94: demux-tsout #27 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":28 []

- entity 96: demux-tsout #28 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":29 []

- entity 98: demux-tsout #29 (1 pad, 1 link)
             type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":30 []

- entity 100: demux-tsout #30 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":31 []

- entity 102: demux-tsout #31 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":32 []

- entity 104: demux-tsout #32 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":33 []

- entity 106: demux-tsout #33 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":34 []

- entity 108: demux-tsout #34 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":35 []

- entity 110: demux-tsout #35 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":36 []

- entity 112: demux-tsout #36 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":37 []

- entity 114: demux-tsout #37 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":38 []

- entity 116: demux-tsout #38 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":39 []

- entity 118: demux-tsout #39 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":40 []

- entity 120: demux-tsout #40 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":41 []

- entity 122: demux-tsout #41 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":42 []

- entity 124: demux-tsout #42 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":43 []

- entity 126: demux-tsout #43 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":44 []

- entity 128: demux-tsout #44 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":45 []

- entity 130: demux-tsout #45 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":46 []

- entity 132: demux-tsout #46 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":47 []

- entity 134: demux-tsout #47 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":48 []

- entity 136: demux-tsout #48 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":49 []

- entity 138: demux-tsout #49 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":50 []

- entity 140: demux-tsout #50 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":51 []

- entity 142: demux-tsout #51 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":52 []

- entity 144: demux-tsout #52 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":53 []

- entity 146: demux-tsout #53 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":54 []

- entity 148: demux-tsout #54 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":55 []

- entity 150: demux-tsout #55 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":56 []

- entity 152: demux-tsout #56 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":57 []

- entity 154: demux-tsout #57 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":58 []

- entity 156: demux-tsout #58 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":59 []

- entity 158: demux-tsout #59 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":60 []

- entity 160: demux-tsout #60 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":61 []

- entity 162: demux-tsout #61 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":62 []

- entity 164: demux-tsout #62 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":63 []

- entity 166: demux-tsout #63 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":64 []

- entity 168: demux-tsout #64 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":65 []

- entity 170: demux-tsout #65 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":66 []

- entity 172: demux-tsout #66 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":67 []

- entity 174: demux-tsout #67 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":68 []

- entity 176: demux-tsout #68 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":69 []

- entity 178: demux-tsout #69 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":70 []

- entity 180: demux-tsout #70 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":71 []

- entity 182: demux-tsout #71 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":72 []

- entity 184: demux-tsout #72 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":73 []

- entity 186: demux-tsout #73 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":74 []

- entity 188: demux-tsout #74 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":75 []

- entity 190: demux-tsout #75 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":76 []

- entity 192: demux-tsout #76 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":77 []

- entity 194: demux-tsout #77 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":78 []

- entity 196: demux-tsout #78 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":79 []

- entity 198: demux-tsout #79 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":80 []

- entity 200: demux-tsout #80 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":81 []

- entity 202: demux-tsout #81 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":82 []

- entity 204: demux-tsout #82 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":83 []

- entity 206: demux-tsout #83 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":84 []

- entity 208: demux-tsout #84 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":85 []

- entity 210: demux-tsout #85 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":86 []

- entity 212: demux-tsout #86 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":87 []

- entity 214: demux-tsout #87 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":88 []

- entity 216: demux-tsout #88 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":89 []

- entity 218: demux-tsout #89 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":90 []

- entity 220: demux-tsout #90 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":91 []

- entity 222: demux-tsout #91 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":92 []

- entity 224: demux-tsout #92 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":93 []

- entity 226: demux-tsout #93 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":94 []

- entity 228: demux-tsout #94 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":95 []

- entity 230: demux-tsout #95 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":96 []

- entity 232: demux-tsout #96 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":97 []

- entity 234: demux-tsout #97 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":98 []

- entity 236: demux-tsout #98 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":99 []

- entity 238: demux-tsout #99 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":100 []

- entity 240: demux-tsout #100 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":101 []

- entity 242: demux-tsout #101 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":102 []

- entity 244: demux-tsout #102 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":103 []

- entity 246: demux-tsout #103 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":104 []

- entity 248: demux-tsout #104 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":105 []

- entity 250: demux-tsout #105 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":106 []

- entity 252: demux-tsout #106 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":107 []

- entity 254: demux-tsout #107 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":108 []

- entity 256: demux-tsout #108 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":109 []

- entity 258: demux-tsout #109 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":110 []

- entity 260: demux-tsout #110 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":111 []

- entity 262: demux-tsout #111 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":112 []

- entity 264: demux-tsout #112 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":113 []

- entity 266: demux-tsout #113 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":114 []

- entity 268: demux-tsout #114 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":115 []

- entity 270: demux-tsout #115 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":116 []

- entity 272: demux-tsout #116 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":117 []

- entity 274: demux-tsout #117 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":118 []

- entity 276: demux-tsout #118 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":119 []

- entity 278: demux-tsout #119 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":120 []

- entity 280: demux-tsout #120 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":121 []

- entity 282: demux-tsout #121 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":122 []

- entity 284: demux-tsout #122 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":123 []

- entity 286: demux-tsout #123 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":124 []

- entity 288: demux-tsout #124 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":125 []

- entity 290: demux-tsout #125 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":126 []

- entity 292: demux-tsout #126 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":127 []

- entity 294: demux-tsout #127 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":128 []

- entity 296: demux-tsout #128 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":129 []

- entity 298: demux-tsout #129 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":130 []

- entity 300: demux-tsout #130 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":131 []

- entity 302: demux-tsout #131 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":132 []

- entity 304: demux-tsout #132 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":133 []

- entity 306: demux-tsout #133 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":134 []

- entity 308: demux-tsout #134 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":135 []

- entity 310: demux-tsout #135 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":136 []

- entity 312: demux-tsout #136 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":137 []

- entity 314: demux-tsout #137 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":138 []

- entity 316: demux-tsout #138 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":139 []

- entity 318: demux-tsout #139 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":140 []

- entity 320: demux-tsout #140 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":141 []

- entity 322: demux-tsout #141 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":142 []

- entity 324: demux-tsout #142 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":143 []

- entity 326: demux-tsout #143 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":144 []

- entity 328: demux-tsout #144 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":145 []

- entity 330: demux-tsout #145 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":146 []

- entity 332: demux-tsout #146 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":147 []

- entity 334: demux-tsout #147 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":148 []

- entity 336: demux-tsout #148 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":149 []

- entity 338: demux-tsout #149 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":150 []

- entity 340: demux-tsout #150 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":151 []

- entity 342: demux-tsout #151 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":152 []

- entity 344: demux-tsout #152 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":153 []

- entity 346: demux-tsout #153 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":154 []

- entity 348: demux-tsout #154 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":155 []

- entity 350: demux-tsout #155 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":156 []

- entity 352: demux-tsout #156 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":157 []

- entity 354: demux-tsout #157 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":158 []

- entity 356: demux-tsout #158 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":159 []

- entity 358: demux-tsout #159 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":160 []

- entity 360: demux-tsout #160 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":161 []

- entity 362: demux-tsout #161 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":162 []

- entity 364: demux-tsout #162 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":163 []

- entity 366: demux-tsout #163 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":164 []

- entity 368: demux-tsout #164 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":165 []

- entity 370: demux-tsout #165 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":166 []

- entity 372: demux-tsout #166 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":167 []

- entity 374: demux-tsout #167 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":168 []

- entity 376: demux-tsout #168 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":169 []

- entity 378: demux-tsout #169 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":170 []

- entity 380: demux-tsout #170 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":171 []

- entity 382: demux-tsout #171 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":172 []

- entity 384: demux-tsout #172 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":173 []

- entity 386: demux-tsout #173 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":174 []

- entity 388: demux-tsout #174 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":175 []

- entity 390: demux-tsout #175 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":176 []

- entity 392: demux-tsout #176 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":177 []

- entity 394: demux-tsout #177 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":178 []

- entity 396: demux-tsout #178 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":179 []

- entity 398: demux-tsout #179 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":180 []

- entity 400: demux-tsout #180 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":181 []

- entity 402: demux-tsout #181 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":182 []

- entity 404: demux-tsout #182 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":183 []

- entity 406: demux-tsout #183 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":184 []

- entity 408: demux-tsout #184 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":185 []

- entity 410: demux-tsout #185 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":186 []

- entity 412: demux-tsout #186 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":187 []

- entity 414: demux-tsout #187 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":188 []

- entity 416: demux-tsout #188 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":189 []

- entity 418: demux-tsout #189 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":190 []

- entity 420: demux-tsout #190 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":191 []

- entity 422: demux-tsout #191 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":192 []

- entity 424: demux-tsout #192 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":193 []

- entity 426: demux-tsout #193 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":194 []

- entity 428: demux-tsout #194 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":195 []

- entity 430: demux-tsout #195 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":196 []

- entity 432: demux-tsout #196 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":197 []

- entity 434: demux-tsout #197 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":198 []

- entity 436: demux-tsout #198 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":199 []

- entity 438: demux-tsout #199 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":200 []

- entity 440: demux-tsout #200 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":201 []

- entity 442: demux-tsout #201 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":202 []

- entity 444: demux-tsout #202 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":203 []

- entity 446: demux-tsout #203 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":204 []

- entity 448: demux-tsout #204 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":205 []

- entity 450: demux-tsout #205 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":206 []

- entity 452: demux-tsout #206 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":207 []

- entity 454: demux-tsout #207 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":208 []

- entity 456: demux-tsout #208 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":209 []

- entity 458: demux-tsout #209 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":210 []

- entity 460: demux-tsout #210 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":211 []

- entity 462: demux-tsout #211 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":212 []

- entity 464: demux-tsout #212 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":213 []

- entity 466: demux-tsout #213 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":214 []

- entity 468: demux-tsout #214 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":215 []

- entity 470: demux-tsout #215 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":216 []

- entity 472: demux-tsout #216 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":217 []

- entity 474: demux-tsout #217 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":218 []

- entity 476: demux-tsout #218 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":219 []

- entity 478: demux-tsout #219 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":220 []

- entity 480: demux-tsout #220 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":221 []

- entity 482: demux-tsout #221 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":222 []

- entity 484: demux-tsout #222 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":223 []

- entity 486: demux-tsout #223 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":224 []

- entity 488: demux-tsout #224 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":225 []

- entity 490: demux-tsout #225 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":226 []

- entity 492: demux-tsout #226 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":227 []

- entity 494: demux-tsout #227 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":228 []

- entity 496: demux-tsout #228 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":229 []

- entity 498: demux-tsout #229 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":230 []

- entity 500: demux-tsout #230 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":231 []

- entity 502: demux-tsout #231 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":232 []

- entity 504: demux-tsout #232 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":233 []

- entity 506: demux-tsout #233 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":234 []

- entity 508: demux-tsout #234 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":235 []

- entity 510: demux-tsout #235 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":236 []

- entity 512: demux-tsout #236 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":237 []

- entity 514: demux-tsout #237 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":238 []

- entity 516: demux-tsout #238 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":239 []

- entity 518: demux-tsout #239 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":240 []

- entity 520: demux-tsout #240 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":241 []

- entity 522: demux-tsout #241 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":242 []

- entity 524: demux-tsout #242 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":243 []

- entity 526: demux-tsout #243 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":244 []

- entity 528: demux-tsout #244 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":245 []

- entity 530: demux-tsout #245 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":246 []

- entity 532: demux-tsout #246 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":247 []

- entity 534: demux-tsout #247 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":248 []

- entity 536: demux-tsout #248 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":249 []

- entity 538: demux-tsout #249 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":250 []

- entity 540: demux-tsout #250 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":251 []

- entity 542: demux-tsout #251 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":252 []

- entity 544: demux-tsout #252 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":253 []

- entity 546: demux-tsout #253 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":254 []

- entity 548: demux-tsout #254 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":255 []

- entity 550: demux-tsout #255 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":256 []

- entity 552: dvb-demux (257 pads, 513 links)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "Auvitek AU8522 QAM/8VSB Fronten":1 [ENABLED]
	pad1: Source
		-> "demux-tsout #0":0 []
		-> "dvr-tsout #0":0 []
	pad2: Source
		-> "demux-tsout #1":0 []
		-> "dvr-tsout #1":0 []
	pad3: Source
		-> "demux-tsout #2":0 []
		-> "dvr-tsout #2":0 []
	pad4: Source
		-> "demux-tsout #3":0 []
		-> "dvr-tsout #3":0 []
	pad5: Source
		-> "demux-tsout #4":0 []
		-> "dvr-tsout #4":0 []
	pad6: Source
		-> "demux-tsout #5":0 []
		-> "dvr-tsout #5":0 []
	pad7: Source
		-> "demux-tsout #6":0 []
		-> "dvr-tsout #6":0 []
	pad8: Source
		-> "demux-tsout #7":0 []
		-> "dvr-tsout #7":0 []
	pad9: Source
		-> "demux-tsout #8":0 []
		-> "dvr-tsout #8":0 []
	pad10: Source
		-> "demux-tsout #9":0 []
		-> "dvr-tsout #9":0 []
	pad11: Source
		-> "demux-tsout #10":0 []
		-> "dvr-tsout #10":0 []
	pad12: Source
		-> "demux-tsout #11":0 []
		-> "dvr-tsout #11":0 []
	pad13: Source
		-> "demux-tsout #12":0 []
		-> "dvr-tsout #12":0 []
	pad14: Source
		-> "demux-tsout #13":0 []
		-> "dvr-tsout #13":0 []
	pad15: Source
		-> "demux-tsout #14":0 []
		-> "dvr-tsout #14":0 []
	pad16: Source
		-> "demux-tsout #15":0 []
		-> "dvr-tsout #15":0 []
	pad17: Source
		-> "demux-tsout #16":0 []
		-> "dvr-tsout #16":0 []
	pad18: Source
		-> "demux-tsout #17":0 []
		-> "dvr-tsout #17":0 []
	pad19: Source
		-> "demux-tsout #18":0 []
		-> "dvr-tsout #18":0 []
	pad20: Source
		-> "demux-tsout #19":0 []
		-> "dvr-tsout #19":0 []
	pad21: Source
		-> "demux-tsout #20":0 []
		-> "dvr-tsout #20":0 []
	pad22: Source
		-> "demux-tsout #21":0 []
		-> "dvr-tsout #21":0 []
	pad23: Source
		-> "demux-tsout #22":0 []
		-> "dvr-tsout #22":0 []
	pad24: Source
		-> "demux-tsout #23":0 []
		-> "dvr-tsout #23":0 []
	pad25: Source
		-> "demux-tsout #24":0 []
		-> "dvr-tsout #24":0 []
	pad26: Source
		-> "demux-tsout #25":0 []
		-> "dvr-tsout #25":0 []
	pad27: Source
		-> "demux-tsout #26":0 []
		-> "dvr-tsout #26":0 []
	pad28: Source
		-> "demux-tsout #27":0 []
		-> "dvr-tsout #27":0 []
	pad29: Source
		-> "demux-tsout #28":0 []
		-> "dvr-tsout #28":0 []
	pad30: Source
		-> "demux-tsout #29":0 []
		-> "dvr-tsout #29":0 []
	pad31: Source
		-> "demux-tsout #30":0 []
		-> "dvr-tsout #30":0 []
	pad32: Source
		-> "demux-tsout #31":0 []
		-> "dvr-tsout #31":0 []
	pad33: Source
		-> "demux-tsout #32":0 []
		-> "dvr-tsout #32":0 []
	pad34: Source
		-> "demux-tsout #33":0 []
		-> "dvr-tsout #33":0 []
	pad35: Source
		-> "demux-tsout #34":0 []
		-> "dvr-tsout #34":0 []
	pad36: Source
		-> "demux-tsout #35":0 []
		-> "dvr-tsout #35":0 []
	pad37: Source
		-> "demux-tsout #36":0 []
		-> "dvr-tsout #36":0 []
	pad38: Source
		-> "demux-tsout #37":0 []
		-> "dvr-tsout #37":0 []
	pad39: Source
		-> "demux-tsout #38":0 []
		-> "dvr-tsout #38":0 []
	pad40: Source
		-> "demux-tsout #39":0 []
		-> "dvr-tsout #39":0 []
	pad41: Source
		-> "demux-tsout #40":0 []
		-> "dvr-tsout #40":0 []
	pad42: Source
		-> "demux-tsout #41":0 []
		-> "dvr-tsout #41":0 []
	pad43: Source
		-> "demux-tsout #42":0 []
		-> "dvr-tsout #42":0 []
	pad44: Source
		-> "demux-tsout #43":0 []
		-> "dvr-tsout #43":0 []
	pad45: Source
		-> "demux-tsout #44":0 []
		-> "dvr-tsout #44":0 []
	pad46: Source
		-> "demux-tsout #45":0 []
		-> "dvr-tsout #45":0 []
	pad47: Source
		-> "demux-tsout #46":0 []
		-> "dvr-tsout #46":0 []
	pad48: Source
		-> "demux-tsout #47":0 []
		-> "dvr-tsout #47":0 []
	pad49: Source
		-> "demux-tsout #48":0 []
		-> "dvr-tsout #48":0 []
	pad50: Source
		-> "demux-tsout #49":0 []
		-> "dvr-tsout #49":0 []
	pad51: Source
		-> "demux-tsout #50":0 []
		-> "dvr-tsout #50":0 []
	pad52: Source
		-> "demux-tsout #51":0 []
		-> "dvr-tsout #51":0 []
	pad53: Source
		-> "demux-tsout #52":0 []
		-> "dvr-tsout #52":0 []
	pad54: Source
		-> "demux-tsout #53":0 []
		-> "dvr-tsout #53":0 []
	pad55: Source
		-> "demux-tsout #54":0 []
		-> "dvr-tsout #54":0 []
	pad56: Source
		-> "demux-tsout #55":0 []
		-> "dvr-tsout #55":0 []
	pad57: Source
		-> "demux-tsout #56":0 []
		-> "dvr-tsout #56":0 []
	pad58: Source
		-> "demux-tsout #57":0 []
		-> "dvr-tsout #57":0 []
	pad59: Source
		-> "demux-tsout #58":0 []
		-> "dvr-tsout #58":0 []
	pad60: Source
		-> "demux-tsout #59":0 []
		-> "dvr-tsout #59":0 []
	pad61: Source
		-> "demux-tsout #60":0 []
		-> "dvr-tsout #60":0 []
	pad62: Source
		-> "demux-tsout #61":0 []
		-> "dvr-tsout #61":0 []
	pad63: Source
		-> "demux-tsout #62":0 []
		-> "dvr-tsout #62":0 []
	pad64: Source
		-> "demux-tsout #63":0 []
		-> "dvr-tsout #63":0 []
	pad65: Source
		-> "demux-tsout #64":0 []
		-> "dvr-tsout #64":0 []
	pad66: Source
		-> "demux-tsout #65":0 []
		-> "dvr-tsout #65":0 []
	pad67: Source
		-> "demux-tsout #66":0 []
		-> "dvr-tsout #66":0 []
	pad68: Source
		-> "demux-tsout #67":0 []
		-> "dvr-tsout #67":0 []
	pad69: Source
		-> "demux-tsout #68":0 []
		-> "dvr-tsout #68":0 []
	pad70: Source
		-> "demux-tsout #69":0 []
		-> "dvr-tsout #69":0 []
	pad71: Source
		-> "demux-tsout #70":0 []
		-> "dvr-tsout #70":0 []
	pad72: Source
		-> "demux-tsout #71":0 []
		-> "dvr-tsout #71":0 []
	pad73: Source
		-> "demux-tsout #72":0 []
		-> "dvr-tsout #72":0 []
	pad74: Source
		-> "demux-tsout #73":0 []
		-> "dvr-tsout #73":0 []
	pad75: Source
		-> "demux-tsout #74":0 []
		-> "dvr-tsout #74":0 []
	pad76: Source
		-> "demux-tsout #75":0 []
		-> "dvr-tsout #75":0 []
	pad77: Source
		-> "demux-tsout #76":0 []
		-> "dvr-tsout #76":0 []
	pad78: Source
		-> "demux-tsout #77":0 []
		-> "dvr-tsout #77":0 []
	pad79: Source
		-> "demux-tsout #78":0 []
		-> "dvr-tsout #78":0 []
	pad80: Source
		-> "demux-tsout #79":0 []
		-> "dvr-tsout #79":0 []
	pad81: Source
		-> "demux-tsout #80":0 []
		-> "dvr-tsout #80":0 []
	pad82: Source
		-> "demux-tsout #81":0 []
		-> "dvr-tsout #81":0 []
	pad83: Source
		-> "demux-tsout #82":0 []
		-> "dvr-tsout #82":0 []
	pad84: Source
		-> "demux-tsout #83":0 []
		-> "dvr-tsout #83":0 []
	pad85: Source
		-> "demux-tsout #84":0 []
		-> "dvr-tsout #84":0 []
	pad86: Source
		-> "demux-tsout #85":0 []
		-> "dvr-tsout #85":0 []
	pad87: Source
		-> "demux-tsout #86":0 []
		-> "dvr-tsout #86":0 []
	pad88: Source
		-> "demux-tsout #87":0 []
		-> "dvr-tsout #87":0 []
	pad89: Source
		-> "demux-tsout #88":0 []
		-> "dvr-tsout #88":0 []
	pad90: Source
		-> "demux-tsout #89":0 []
		-> "dvr-tsout #89":0 []
	pad91: Source
		-> "demux-tsout #90":0 []
		-> "dvr-tsout #90":0 []
	pad92: Source
		-> "demux-tsout #91":0 []
		-> "dvr-tsout #91":0 []
	pad93: Source
		-> "demux-tsout #92":0 []
		-> "dvr-tsout #92":0 []
	pad94: Source
		-> "demux-tsout #93":0 []
		-> "dvr-tsout #93":0 []
	pad95: Source
		-> "demux-tsout #94":0 []
		-> "dvr-tsout #94":0 []
	pad96: Source
		-> "demux-tsout #95":0 []
		-> "dvr-tsout #95":0 []
	pad97: Source
		-> "demux-tsout #96":0 []
		-> "dvr-tsout #96":0 []
	pad98: Source
		-> "demux-tsout #97":0 []
		-> "dvr-tsout #97":0 []
	pad99: Source
		-> "demux-tsout #98":0 []
		-> "dvr-tsout #98":0 []
	pad100: Source
		-> "demux-tsout #99":0 []
		-> "dvr-tsout #99":0 []
	pad101: Source
		-> "demux-tsout #100":0 []
		-> "dvr-tsout #100":0 []
	pad102: Source
		-> "demux-tsout #101":0 []
		-> "dvr-tsout #101":0 []
	pad103: Source
		-> "demux-tsout #102":0 []
		-> "dvr-tsout #102":0 []
	pad104: Source
		-> "demux-tsout #103":0 []
		-> "dvr-tsout #103":0 []
	pad105: Source
		-> "demux-tsout #104":0 []
		-> "dvr-tsout #104":0 []
	pad106: Source
		-> "demux-tsout #105":0 []
		-> "dvr-tsout #105":0 []
	pad107: Source
		-> "demux-tsout #106":0 []
		-> "dvr-tsout #106":0 []
	pad108: Source
		-> "demux-tsout #107":0 []
		-> "dvr-tsout #107":0 []
	pad109: Source
		-> "demux-tsout #108":0 []
		-> "dvr-tsout #108":0 []
	pad110: Source
		-> "demux-tsout #109":0 []
		-> "dvr-tsout #109":0 []
	pad111: Source
		-> "demux-tsout #110":0 []
		-> "dvr-tsout #110":0 []
	pad112: Source
		-> "demux-tsout #111":0 []
		-> "dvr-tsout #111":0 []
	pad113: Source
		-> "demux-tsout #112":0 []
		-> "dvr-tsout #112":0 []
	pad114: Source
		-> "demux-tsout #113":0 []
		-> "dvr-tsout #113":0 []
	pad115: Source
		-> "demux-tsout #114":0 []
		-> "dvr-tsout #114":0 []
	pad116: Source
		-> "demux-tsout #115":0 []
		-> "dvr-tsout #115":0 []
	pad117: Source
		-> "demux-tsout #116":0 []
		-> "dvr-tsout #116":0 []
	pad118: Source
		-> "demux-tsout #117":0 []
		-> "dvr-tsout #117":0 []
	pad119: Source
		-> "demux-tsout #118":0 []
		-> "dvr-tsout #118":0 []
	pad120: Source
		-> "demux-tsout #119":0 []
		-> "dvr-tsout #119":0 []
	pad121: Source
		-> "demux-tsout #120":0 []
		-> "dvr-tsout #120":0 []
	pad122: Source
		-> "demux-tsout #121":0 []
		-> "dvr-tsout #121":0 []
	pad123: Source
		-> "demux-tsout #122":0 []
		-> "dvr-tsout #122":0 []
	pad124: Source
		-> "demux-tsout #123":0 []
		-> "dvr-tsout #123":0 []
	pad125: Source
		-> "demux-tsout #124":0 []
		-> "dvr-tsout #124":0 []
	pad126: Source
		-> "demux-tsout #125":0 []
		-> "dvr-tsout #125":0 []
	pad127: Source
		-> "demux-tsout #126":0 []
		-> "dvr-tsout #126":0 []
	pad128: Source
		-> "demux-tsout #127":0 []
		-> "dvr-tsout #127":0 []
	pad129: Source
		-> "demux-tsout #128":0 []
		-> "dvr-tsout #128":0 []
	pad130: Source
		-> "demux-tsout #129":0 []
		-> "dvr-tsout #129":0 []
	pad131: Source
		-> "demux-tsout #130":0 []
		-> "dvr-tsout #130":0 []
	pad132: Source
		-> "demux-tsout #131":0 []
		-> "dvr-tsout #131":0 []
	pad133: Source
		-> "demux-tsout #132":0 []
		-> "dvr-tsout #132":0 []
	pad134: Source
		-> "demux-tsout #133":0 []
		-> "dvr-tsout #133":0 []
	pad135: Source
		-> "demux-tsout #134":0 []
		-> "dvr-tsout #134":0 []
	pad136: Source
		-> "demux-tsout #135":0 []
		-> "dvr-tsout #135":0 []
	pad137: Source
		-> "demux-tsout #136":0 []
		-> "dvr-tsout #136":0 []
	pad138: Source
		-> "demux-tsout #137":0 []
		-> "dvr-tsout #137":0 []
	pad139: Source
		-> "demux-tsout #138":0 []
		-> "dvr-tsout #138":0 []
	pad140: Source
		-> "demux-tsout #139":0 []
		-> "dvr-tsout #139":0 []
	pad141: Source
		-> "demux-tsout #140":0 []
		-> "dvr-tsout #140":0 []
	pad142: Source
		-> "demux-tsout #141":0 []
		-> "dvr-tsout #141":0 []
	pad143: Source
		-> "demux-tsout #142":0 []
		-> "dvr-tsout #142":0 []
	pad144: Source
		-> "demux-tsout #143":0 []
		-> "dvr-tsout #143":0 []
	pad145: Source
		-> "demux-tsout #144":0 []
		-> "dvr-tsout #144":0 []
	pad146: Source
		-> "demux-tsout #145":0 []
		-> "dvr-tsout #145":0 []
	pad147: Source
		-> "demux-tsout #146":0 []
		-> "dvr-tsout #146":0 []
	pad148: Source
		-> "demux-tsout #147":0 []
		-> "dvr-tsout #147":0 []
	pad149: Source
		-> "demux-tsout #148":0 []
		-> "dvr-tsout #148":0 []
	pad150: Source
		-> "demux-tsout #149":0 []
		-> "dvr-tsout #149":0 []
	pad151: Source
		-> "demux-tsout #150":0 []
		-> "dvr-tsout #150":0 []
	pad152: Source
		-> "demux-tsout #151":0 []
		-> "dvr-tsout #151":0 []
	pad153: Source
		-> "demux-tsout #152":0 []
		-> "dvr-tsout #152":0 []
	pad154: Source
		-> "demux-tsout #153":0 []
		-> "dvr-tsout #153":0 []
	pad155: Source
		-> "demux-tsout #154":0 []
		-> "dvr-tsout #154":0 []
	pad156: Source
		-> "demux-tsout #155":0 []
		-> "dvr-tsout #155":0 []
	pad157: Source
		-> "demux-tsout #156":0 []
		-> "dvr-tsout #156":0 []
	pad158: Source
		-> "demux-tsout #157":0 []
		-> "dvr-tsout #157":0 []
	pad159: Source
		-> "demux-tsout #158":0 []
		-> "dvr-tsout #158":0 []
	pad160: Source
		-> "demux-tsout #159":0 []
		-> "dvr-tsout #159":0 []
	pad161: Source
		-> "demux-tsout #160":0 []
		-> "dvr-tsout #160":0 []
	pad162: Source
		-> "demux-tsout #161":0 []
		-> "dvr-tsout #161":0 []
	pad163: Source
		-> "demux-tsout #162":0 []
		-> "dvr-tsout #162":0 []
	pad164: Source
		-> "demux-tsout #163":0 []
		-> "dvr-tsout #163":0 []
	pad165: Source
		-> "demux-tsout #164":0 []
		-> "dvr-tsout #164":0 []
	pad166: Source
		-> "demux-tsout #165":0 []
		-> "dvr-tsout #165":0 []
	pad167: Source
		-> "demux-tsout #166":0 []
		-> "dvr-tsout #166":0 []
	pad168: Source
		-> "demux-tsout #167":0 []
		-> "dvr-tsout #167":0 []
	pad169: Source
		-> "demux-tsout #168":0 []
		-> "dvr-tsout #168":0 []
	pad170: Source
		-> "demux-tsout #169":0 []
		-> "dvr-tsout #169":0 []
	pad171: Source
		-> "demux-tsout #170":0 []
		-> "dvr-tsout #170":0 []
	pad172: Source
		-> "demux-tsout #171":0 []
		-> "dvr-tsout #171":0 []
	pad173: Source
		-> "demux-tsout #172":0 []
		-> "dvr-tsout #172":0 []
	pad174: Source
		-> "demux-tsout #173":0 []
		-> "dvr-tsout #173":0 []
	pad175: Source
		-> "demux-tsout #174":0 []
		-> "dvr-tsout #174":0 []
	pad176: Source
		-> "demux-tsout #175":0 []
		-> "dvr-tsout #175":0 []
	pad177: Source
		-> "demux-tsout #176":0 []
		-> "dvr-tsout #176":0 []
	pad178: Source
		-> "demux-tsout #177":0 []
		-> "dvr-tsout #177":0 []
	pad179: Source
		-> "demux-tsout #178":0 []
		-> "dvr-tsout #178":0 []
	pad180: Source
		-> "demux-tsout #179":0 []
		-> "dvr-tsout #179":0 []
	pad181: Source
		-> "demux-tsout #180":0 []
		-> "dvr-tsout #180":0 []
	pad182: Source
		-> "demux-tsout #181":0 []
		-> "dvr-tsout #181":0 []
	pad183: Source
		-> "demux-tsout #182":0 []
		-> "dvr-tsout #182":0 []
	pad184: Source
		-> "demux-tsout #183":0 []
		-> "dvr-tsout #183":0 []
	pad185: Source
		-> "demux-tsout #184":0 []
		-> "dvr-tsout #184":0 []
	pad186: Source
		-> "demux-tsout #185":0 []
		-> "dvr-tsout #185":0 []
	pad187: Source
		-> "demux-tsout #186":0 []
		-> "dvr-tsout #186":0 []
	pad188: Source
		-> "demux-tsout #187":0 []
		-> "dvr-tsout #187":0 []
	pad189: Source
		-> "demux-tsout #188":0 []
		-> "dvr-tsout #188":0 []
	pad190: Source
		-> "demux-tsout #189":0 []
		-> "dvr-tsout #189":0 []
	pad191: Source
		-> "demux-tsout #190":0 []
		-> "dvr-tsout #190":0 []
	pad192: Source
		-> "demux-tsout #191":0 []
		-> "dvr-tsout #191":0 []
	pad193: Source
		-> "demux-tsout #192":0 []
		-> "dvr-tsout #192":0 []
	pad194: Source
		-> "demux-tsout #193":0 []
		-> "dvr-tsout #193":0 []
	pad195: Source
		-> "demux-tsout #194":0 []
		-> "dvr-tsout #194":0 []
	pad196: Source
		-> "demux-tsout #195":0 []
		-> "dvr-tsout #195":0 []
	pad197: Source
		-> "demux-tsout #196":0 []
		-> "dvr-tsout #196":0 []
	pad198: Source
		-> "demux-tsout #197":0 []
		-> "dvr-tsout #197":0 []
	pad199: Source
		-> "demux-tsout #198":0 []
		-> "dvr-tsout #198":0 []
	pad200: Source
		-> "demux-tsout #199":0 []
		-> "dvr-tsout #199":0 []
	pad201: Source
		-> "demux-tsout #200":0 []
		-> "dvr-tsout #200":0 []
	pad202: Source
		-> "demux-tsout #201":0 []
		-> "dvr-tsout #201":0 []
	pad203: Source
		-> "demux-tsout #202":0 []
		-> "dvr-tsout #202":0 []
	pad204: Source
		-> "demux-tsout #203":0 []
		-> "dvr-tsout #203":0 []
	pad205: Source
		-> "demux-tsout #204":0 []
		-> "dvr-tsout #204":0 []
	pad206: Source
		-> "demux-tsout #205":0 []
		-> "dvr-tsout #205":0 []
	pad207: Source
		-> "demux-tsout #206":0 []
		-> "dvr-tsout #206":0 []
	pad208: Source
		-> "demux-tsout #207":0 []
		-> "dvr-tsout #207":0 []
	pad209: Source
		-> "demux-tsout #208":0 []
		-> "dvr-tsout #208":0 []
	pad210: Source
		-> "demux-tsout #209":0 []
		-> "dvr-tsout #209":0 []
	pad211: Source
		-> "demux-tsout #210":0 []
		-> "dvr-tsout #210":0 []
	pad212: Source
		-> "demux-tsout #211":0 []
		-> "dvr-tsout #211":0 []
	pad213: Source
		-> "demux-tsout #212":0 []
		-> "dvr-tsout #212":0 []
	pad214: Source
		-> "demux-tsout #213":0 []
		-> "dvr-tsout #213":0 []
	pad215: Source
		-> "demux-tsout #214":0 []
		-> "dvr-tsout #214":0 []
	pad216: Source
		-> "demux-tsout #215":0 []
		-> "dvr-tsout #215":0 []
	pad217: Source
		-> "demux-tsout #216":0 []
		-> "dvr-tsout #216":0 []
	pad218: Source
		-> "demux-tsout #217":0 []
		-> "dvr-tsout #217":0 []
	pad219: Source
		-> "demux-tsout #218":0 []
		-> "dvr-tsout #218":0 []
	pad220: Source
		-> "demux-tsout #219":0 []
		-> "dvr-tsout #219":0 []
	pad221: Source
		-> "demux-tsout #220":0 []
		-> "dvr-tsout #220":0 []
	pad222: Source
		-> "demux-tsout #221":0 []
		-> "dvr-tsout #221":0 []
	pad223: Source
		-> "demux-tsout #222":0 []
		-> "dvr-tsout #222":0 []
	pad224: Source
		-> "demux-tsout #223":0 []
		-> "dvr-tsout #223":0 []
	pad225: Source
		-> "demux-tsout #224":0 []
		-> "dvr-tsout #224":0 []
	pad226: Source
		-> "demux-tsout #225":0 []
		-> "dvr-tsout #225":0 []
	pad227: Source
		-> "demux-tsout #226":0 []
		-> "dvr-tsout #226":0 []
	pad228: Source
		-> "demux-tsout #227":0 []
		-> "dvr-tsout #227":0 []
	pad229: Source
		-> "demux-tsout #228":0 []
		-> "dvr-tsout #228":0 []
	pad230: Source
		-> "demux-tsout #229":0 []
		-> "dvr-tsout #229":0 []
	pad231: Source
		-> "demux-tsout #230":0 []
		-> "dvr-tsout #230":0 []
	pad232: Source
		-> "demux-tsout #231":0 []
		-> "dvr-tsout #231":0 []
	pad233: Source
		-> "demux-tsout #232":0 []
		-> "dvr-tsout #232":0 []
	pad234: Source
		-> "demux-tsout #233":0 []
		-> "dvr-tsout #233":0 []
	pad235: Source
		-> "demux-tsout #234":0 []
		-> "dvr-tsout #234":0 []
	pad236: Source
		-> "demux-tsout #235":0 []
		-> "dvr-tsout #235":0 []
	pad237: Source
		-> "demux-tsout #236":0 []
		-> "dvr-tsout #236":0 []
	pad238: Source
		-> "demux-tsout #237":0 []
		-> "dvr-tsout #237":0 []
	pad239: Source
		-> "demux-tsout #238":0 []
		-> "dvr-tsout #238":0 []
	pad240: Source
		-> "demux-tsout #239":0 []
		-> "dvr-tsout #239":0 []
	pad241: Source
		-> "demux-tsout #240":0 []
		-> "dvr-tsout #240":0 []
	pad242: Source
		-> "demux-tsout #241":0 []
		-> "dvr-tsout #241":0 []
	pad243: Source
		-> "demux-tsout #242":0 []
		-> "dvr-tsout #242":0 []
	pad244: Source
		-> "demux-tsout #243":0 []
		-> "dvr-tsout #243":0 []
	pad245: Source
		-> "demux-tsout #244":0 []
		-> "dvr-tsout #244":0 []
	pad246: Source
		-> "demux-tsout #245":0 []
		-> "dvr-tsout #245":0 []
	pad247: Source
		-> "demux-tsout #246":0 []
		-> "dvr-tsout #246":0 []
	pad248: Source
		-> "demux-tsout #247":0 []
		-> "dvr-tsout #247":0 []
	pad249: Source
		-> "demux-tsout #248":0 []
		-> "dvr-tsout #248":0 []
	pad250: Source
		-> "demux-tsout #249":0 []
		-> "dvr-tsout #249":0 []
	pad251: Source
		-> "demux-tsout #250":0 []
		-> "dvr-tsout #250":0 []
	pad252: Source
		-> "demux-tsout #251":0 []
		-> "dvr-tsout #251":0 []
	pad253: Source
		-> "demux-tsout #252":0 []
		-> "dvr-tsout #252":0 []
	pad254: Source
		-> "demux-tsout #253":0 []
		-> "dvr-tsout #253":0 []
	pad255: Source
		-> "demux-tsout #254":0 []
		-> "dvr-tsout #254":0 []
	pad256: Source
		-> "demux-tsout #255":0 []
		-> "dvr-tsout #255":0 []

- entity 812: dvr-tsout #0 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":1 []

- entity 814: dvr-tsout #1 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":2 []

- entity 816: dvr-tsout #2 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":3 []

- entity 818: dvr-tsout #3 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":4 []

- entity 820: dvr-tsout #4 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":5 []

- entity 822: dvr-tsout #5 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":6 []

- entity 824: dvr-tsout #6 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":7 []

- entity 826: dvr-tsout #7 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":8 []

- entity 828: dvr-tsout #8 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":9 []

- entity 830: dvr-tsout #9 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":10 []

- entity 832: dvr-tsout #10 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":11 []

- entity 834: dvr-tsout #11 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":12 []

- entity 836: dvr-tsout #12 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":13 []

- entity 838: dvr-tsout #13 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":14 []

- entity 840: dvr-tsout #14 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":15 []

- entity 842: dvr-tsout #15 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":16 []

- entity 844: dvr-tsout #16 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":17 []

- entity 846: dvr-tsout #17 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":18 []

- entity 848: dvr-tsout #18 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":19 []

- entity 850: dvr-tsout #19 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":20 []

- entity 852: dvr-tsout #20 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":21 []

- entity 854: dvr-tsout #21 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":22 []

- entity 856: dvr-tsout #22 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":23 []

- entity 858: dvr-tsout #23 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":24 []

- entity 860: dvr-tsout #24 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":25 []

- entity 862: dvr-tsout #25 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":26 []

- entity 864: dvr-tsout #26 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":27 []

- entity 866: dvr-tsout #27 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":28 []

- entity 868: dvr-tsout #28 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":29 []

- entity 870: dvr-tsout #29 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":30 []

- entity 872: dvr-tsout #30 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":31 []

- entity 874: dvr-tsout #31 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":32 []

- entity 876: dvr-tsout #32 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":33 []

- entity 878: dvr-tsout #33 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":34 []

- entity 880: dvr-tsout #34 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":35 []

- entity 882: dvr-tsout #35 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":36 []

- entity 884: dvr-tsout #36 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":37 []

- entity 886: dvr-tsout #37 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":38 []

- entity 888: dvr-tsout #38 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":39 []

- entity 890: dvr-tsout #39 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":40 []

- entity 892: dvr-tsout #40 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":41 []

- entity 894: dvr-tsout #41 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":42 []

- entity 896: dvr-tsout #42 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":43 []

- entity 898: dvr-tsout #43 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":44 []

- entity 900: dvr-tsout #44 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":45 []

- entity 902: dvr-tsout #45 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":46 []

- entity 904: dvr-tsout #46 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":47 []

- entity 906: dvr-tsout #47 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":48 []

- entity 908: dvr-tsout #48 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":49 []

- entity 910: dvr-tsout #49 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":50 []

- entity 912: dvr-tsout #50 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":51 []

- entity 914: dvr-tsout #51 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":52 []

- entity 916: dvr-tsout #52 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":53 []

- entity 918: dvr-tsout #53 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":54 []

- entity 920: dvr-tsout #54 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":55 []

- entity 922: dvr-tsout #55 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":56 []

- entity 924: dvr-tsout #56 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":57 []

- entity 926: dvr-tsout #57 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":58 []

- entity 928: dvr-tsout #58 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":59 []

- entity 930: dvr-tsout #59 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":60 []

- entity 932: dvr-tsout #60 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":61 []

- entity 934: dvr-tsout #61 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":62 []

- entity 936: dvr-tsout #62 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":63 []

- entity 938: dvr-tsout #63 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":64 []

- entity 940: dvr-tsout #64 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":65 []

- entity 942: dvr-tsout #65 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":66 []

- entity 944: dvr-tsout #66 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":67 []

- entity 946: dvr-tsout #67 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":68 []

- entity 948: dvr-tsout #68 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":69 []

- entity 950: dvr-tsout #69 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":70 []

- entity 952: dvr-tsout #70 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":71 []

- entity 954: dvr-tsout #71 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":72 []

- entity 956: dvr-tsout #72 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":73 []

- entity 958: dvr-tsout #73 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":74 []

- entity 960: dvr-tsout #74 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":75 []

- entity 962: dvr-tsout #75 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":76 []

- entity 964: dvr-tsout #76 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":77 []

- entity 966: dvr-tsout #77 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":78 []

- entity 968: dvr-tsout #78 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":79 []

- entity 970: dvr-tsout #79 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":80 []

- entity 972: dvr-tsout #80 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":81 []

- entity 974: dvr-tsout #81 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":82 []

- entity 976: dvr-tsout #82 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":83 []

- entity 978: dvr-tsout #83 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":84 []

- entity 980: dvr-tsout #84 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":85 []

- entity 982: dvr-tsout #85 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":86 []

- entity 984: dvr-tsout #86 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":87 []

- entity 986: dvr-tsout #87 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":88 []

- entity 988: dvr-tsout #88 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":89 []

- entity 990: dvr-tsout #89 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":90 []

- entity 992: dvr-tsout #90 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":91 []

- entity 994: dvr-tsout #91 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":92 []

- entity 996: dvr-tsout #92 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":93 []

- entity 998: dvr-tsout #93 (1 pad, 1 link)
              type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":94 []

- entity 1000: dvr-tsout #94 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":95 []

- entity 1002: dvr-tsout #95 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":96 []

- entity 1004: dvr-tsout #96 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":97 []

- entity 1006: dvr-tsout #97 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":98 []

- entity 1008: dvr-tsout #98 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":99 []

- entity 1010: dvr-tsout #99 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":100 []

- entity 1012: dvr-tsout #100 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":101 []

- entity 1014: dvr-tsout #101 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":102 []

- entity 1016: dvr-tsout #102 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":103 []

- entity 1018: dvr-tsout #103 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":104 []

- entity 1020: dvr-tsout #104 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":105 []

- entity 1022: dvr-tsout #105 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":106 []

- entity 1024: dvr-tsout #106 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":107 []

- entity 1026: dvr-tsout #107 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":108 []

- entity 1028: dvr-tsout #108 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":109 []

- entity 1030: dvr-tsout #109 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":110 []

- entity 1032: dvr-tsout #110 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":111 []

- entity 1034: dvr-tsout #111 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":112 []

- entity 1036: dvr-tsout #112 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":113 []

- entity 1038: dvr-tsout #113 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":114 []

- entity 1040: dvr-tsout #114 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":115 []

- entity 1042: dvr-tsout #115 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":116 []

- entity 1044: dvr-tsout #116 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":117 []

- entity 1046: dvr-tsout #117 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":118 []

- entity 1048: dvr-tsout #118 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":119 []

- entity 1050: dvr-tsout #119 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":120 []

- entity 1052: dvr-tsout #120 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":121 []

- entity 1054: dvr-tsout #121 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":122 []

- entity 1056: dvr-tsout #122 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":123 []

- entity 1058: dvr-tsout #123 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":124 []

- entity 1060: dvr-tsout #124 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":125 []

- entity 1062: dvr-tsout #125 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":126 []

- entity 1064: dvr-tsout #126 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":127 []

- entity 1066: dvr-tsout #127 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":128 []

- entity 1068: dvr-tsout #128 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":129 []

- entity 1070: dvr-tsout #129 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":130 []

- entity 1072: dvr-tsout #130 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":131 []

- entity 1074: dvr-tsout #131 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":132 []

- entity 1076: dvr-tsout #132 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":133 []

- entity 1078: dvr-tsout #133 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":134 []

- entity 1080: dvr-tsout #134 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":135 []

- entity 1082: dvr-tsout #135 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":136 []

- entity 1084: dvr-tsout #136 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":137 []

- entity 1086: dvr-tsout #137 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":138 []

- entity 1088: dvr-tsout #138 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":139 []

- entity 1090: dvr-tsout #139 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":140 []

- entity 1092: dvr-tsout #140 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":141 []

- entity 1094: dvr-tsout #141 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":142 []

- entity 1096: dvr-tsout #142 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":143 []

- entity 1098: dvr-tsout #143 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":144 []

- entity 1100: dvr-tsout #144 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":145 []

- entity 1102: dvr-tsout #145 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":146 []

- entity 1104: dvr-tsout #146 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":147 []

- entity 1106: dvr-tsout #147 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":148 []

- entity 1108: dvr-tsout #148 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":149 []

- entity 1110: dvr-tsout #149 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":150 []

- entity 1112: dvr-tsout #150 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":151 []

- entity 1114: dvr-tsout #151 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":152 []

- entity 1116: dvr-tsout #152 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":153 []

- entity 1118: dvr-tsout #153 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":154 []

- entity 1120: dvr-tsout #154 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":155 []

- entity 1122: dvr-tsout #155 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":156 []

- entity 1124: dvr-tsout #156 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":157 []

- entity 1126: dvr-tsout #157 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":158 []

- entity 1128: dvr-tsout #158 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":159 []

- entity 1130: dvr-tsout #159 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":160 []

- entity 1132: dvr-tsout #160 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":161 []

- entity 1134: dvr-tsout #161 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":162 []

- entity 1136: dvr-tsout #162 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":163 []

- entity 1138: dvr-tsout #163 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":164 []

- entity 1140: dvr-tsout #164 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":165 []

- entity 1142: dvr-tsout #165 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":166 []

- entity 1144: dvr-tsout #166 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":167 []

- entity 1146: dvr-tsout #167 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":168 []

- entity 1148: dvr-tsout #168 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":169 []

- entity 1150: dvr-tsout #169 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":170 []

- entity 1152: dvr-tsout #170 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":171 []

- entity 1154: dvr-tsout #171 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":172 []

- entity 1156: dvr-tsout #172 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":173 []

- entity 1158: dvr-tsout #173 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":174 []

- entity 1160: dvr-tsout #174 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":175 []

- entity 1162: dvr-tsout #175 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":176 []

- entity 1164: dvr-tsout #176 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":177 []

- entity 1166: dvr-tsout #177 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":178 []

- entity 1168: dvr-tsout #178 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":179 []

- entity 1170: dvr-tsout #179 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":180 []

- entity 1172: dvr-tsout #180 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":181 []

- entity 1174: dvr-tsout #181 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":182 []

- entity 1176: dvr-tsout #182 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":183 []

- entity 1178: dvr-tsout #183 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":184 []

- entity 1180: dvr-tsout #184 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":185 []

- entity 1182: dvr-tsout #185 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":186 []

- entity 1184: dvr-tsout #186 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":187 []

- entity 1186: dvr-tsout #187 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":188 []

- entity 1188: dvr-tsout #188 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":189 []

- entity 1190: dvr-tsout #189 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":190 []

- entity 1192: dvr-tsout #190 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":191 []

- entity 1194: dvr-tsout #191 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":192 []

- entity 1196: dvr-tsout #192 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":193 []

- entity 1198: dvr-tsout #193 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":194 []

- entity 1200: dvr-tsout #194 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":195 []

- entity 1202: dvr-tsout #195 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":196 []

- entity 1204: dvr-tsout #196 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":197 []

- entity 1206: dvr-tsout #197 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":198 []

- entity 1208: dvr-tsout #198 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":199 []

- entity 1210: dvr-tsout #199 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":200 []

- entity 1212: dvr-tsout #200 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":201 []

- entity 1214: dvr-tsout #201 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":202 []

- entity 1216: dvr-tsout #202 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":203 []

- entity 1218: dvr-tsout #203 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":204 []

- entity 1220: dvr-tsout #204 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":205 []

- entity 1222: dvr-tsout #205 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":206 []

- entity 1224: dvr-tsout #206 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":207 []

- entity 1226: dvr-tsout #207 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":208 []

- entity 1228: dvr-tsout #208 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":209 []

- entity 1230: dvr-tsout #209 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":210 []

- entity 1232: dvr-tsout #210 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":211 []

- entity 1234: dvr-tsout #211 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":212 []

- entity 1236: dvr-tsout #212 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":213 []

- entity 1238: dvr-tsout #213 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":214 []

- entity 1240: dvr-tsout #214 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":215 []

- entity 1242: dvr-tsout #215 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":216 []

- entity 1244: dvr-tsout #216 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":217 []

- entity 1246: dvr-tsout #217 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":218 []

- entity 1248: dvr-tsout #218 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":219 []

- entity 1250: dvr-tsout #219 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":220 []

- entity 1252: dvr-tsout #220 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":221 []

- entity 1254: dvr-tsout #221 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":222 []

- entity 1256: dvr-tsout #222 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":223 []

- entity 1258: dvr-tsout #223 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":224 []

- entity 1260: dvr-tsout #224 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":225 []

- entity 1262: dvr-tsout #225 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":226 []

- entity 1264: dvr-tsout #226 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":227 []

- entity 1266: dvr-tsout #227 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":228 []

- entity 1268: dvr-tsout #228 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":229 []

- entity 1270: dvr-tsout #229 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":230 []

- entity 1272: dvr-tsout #230 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":231 []

- entity 1274: dvr-tsout #231 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":232 []

- entity 1276: dvr-tsout #232 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":233 []

- entity 1278: dvr-tsout #233 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":234 []

- entity 1280: dvr-tsout #234 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":235 []

- entity 1282: dvr-tsout #235 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":236 []

- entity 1284: dvr-tsout #236 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":237 []

- entity 1286: dvr-tsout #237 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":238 []

- entity 1288: dvr-tsout #238 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":239 []

- entity 1290: dvr-tsout #239 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":240 []

- entity 1292: dvr-tsout #240 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":241 []

- entity 1294: dvr-tsout #241 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":242 []

- entity 1296: dvr-tsout #242 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":243 []

- entity 1298: dvr-tsout #243 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":244 []

- entity 1300: dvr-tsout #244 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":245 []

- entity 1302: dvr-tsout #245 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":246 []

- entity 1304: dvr-tsout #246 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":247 []

- entity 1306: dvr-tsout #247 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":248 []

- entity 1308: dvr-tsout #248 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":249 []

- entity 1310: dvr-tsout #249 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":250 []

- entity 1312: dvr-tsout #250 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":251 []

- entity 1314: dvr-tsout #251 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":252 []

- entity 1316: dvr-tsout #252 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":253 []

- entity 1318: dvr-tsout #253 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":254 []

- entity 1320: dvr-tsout #254 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":255 []

- entity 1322: dvr-tsout #255 (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "dvb-demux":256 []

- entity 2868: USB Mixer (3 pads, 2 links)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "au8522 13-0047":2 [ENABLED]
	pad1: Source
	pad2: Source
		-> "USB Audio":0 [ENABLED]

- entity 2875: USB Audio (1 pad, 1 link)
               type Node subtype Unknown flags 0
	pad0: Sink
		<- "USB Mixer":2 [ENABLED]


[-- Attachment #3: media_graph.dot --]
[-- Type: application/msword-template, Size: 63098 bytes --]

[-- Attachment #4: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 1/4] media: Media Device Allocator API
  2019-01-25 15:38   ` Sakari Ailus
@ 2019-01-26  0:27       ` shuah
  0 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-26  0:27 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, perex, tiwai, hverkuil, linux-media, linux-kernel,
	alsa-devel, shuah

Hi Sakari,

On 1/25/19 8:38 AM, Sakari Ailus wrote:
> Hi Shuah,
> 
> On Thu, Jan 24, 2019 at 01:32:38PM -0700, Shuah Khan wrote:
>> Media Device Allocator API to allows multiple drivers share a media device.
>> This API solves a very common use-case for media devices where one physical
>> device (an USB stick) provides both audio and video. When such media device
>> exposes a standard USB Audio class, a proprietary Video class, two or more
>> independent drivers will share a single physical USB bridge. In such cases,
>> it is necessary to coordinate access to the shared resource.
>>
>> Using this API, drivers can allocate a media device with the shared struct
>> device as the key. Once the media device is allocated by a driver, other
>> drivers can get a reference to it. The media device is released when all
>> the references are released.
> 
> Are there real, non-USB devices that could use the same API?
> 

There might be. I don't have any to test. This patch is restricted
to USB at the moment.

>>
>> Signed-off-by: Shuah Khan <shuah@kernel.org>
>> ---
>>   Documentation/media/kapi/mc-core.rst |  41 ++++++++
>>   drivers/media/Makefile               |   4 +
>>   drivers/media/media-dev-allocator.c  | 144 +++++++++++++++++++++++++++
>>   include/media/media-dev-allocator.h  |  53 ++++++++++
>>   4 files changed, 242 insertions(+)
>>   create mode 100644 drivers/media/media-dev-allocator.c
>>   create mode 100644 include/media/media-dev-allocator.h
>>
>> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
>> index 0bcfeadbc52d..07f2a6a90af2 100644
>> --- a/Documentation/media/kapi/mc-core.rst
>> +++ b/Documentation/media/kapi/mc-core.rst
>> @@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific
>>   helper functions to provide easy access for commonly needed information, and
>>   in the end provide a way to use driver-specific callbacks.
>>   
>> +Media Controller Device Allocator API
>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> +
>> +When the media device belongs to more than one driver, the shared media
>> +device is allocated with the shared struct device as the key for look ups.
>> +
>> +The shared media device should stay in registered state until the last
>> +driver unregisters it. In addition, the media device should be released when
>> +all the references are released. Each driver gets a reference to the media
>> +device during probe, when it allocates the media device. If media device is
>> +already allocated, the allocate API bumps up the refcount and returns the
>> +existing media device. The driver puts the reference back in its disconnect
>> +routine when it calls :c:func:`media_device_delete()`.
>> +
>> +The media device is unregistered and cleaned up from the kref put handler to
>> +ensure that the media device stays in registered state until the last driver
>> +unregisters the media device.
>> +
>> +**Driver Usage**
>> +
>> +Drivers should use the appropriate media-core routines to manage the shared
>> +media device life-time handling the two states:
>> +1. allocate -> register -> delete
>> +2. get reference to already registered device -> delete
>> +
>> +call :c:func:`media_device_delete()` routine to make sure the shared media
>> +device delete is handled correctly.
>> +
>> +**driver probe:**
>> +Call :c:func:`media_device_usb_allocate()` to allocate or get a reference
>> +Call :c:func:`media_device_register()`, if media devnode isn't registered
>> +
>> +**driver disconnect:**
>> +Call :c:func:`media_device_delete()` to free the media_device. Freeing is
>> +handled by the kref put handler.
>> +
>> +API Definitions
>> +^^^^^^^^^^^^^^^
>> +
>>   .. kernel-doc:: include/media/media-device.h
>>   
>>   .. kernel-doc:: include/media/media-devnode.h
>> @@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks.
>>   .. kernel-doc:: include/media/media-entity.h
>>   
>>   .. kernel-doc:: include/media/media-request.h
>> +
>> +.. kernel-doc:: include/media/media-dev-allocator.h
>> diff --git a/drivers/media/Makefile b/drivers/media/Makefile
>> index 985d35ec6b29..1d7653318af6 100644
>> --- a/drivers/media/Makefile
>> +++ b/drivers/media/Makefile
>> @@ -6,6 +6,10 @@
>>   media-objs	:= media-device.o media-devnode.o media-entity.o \
>>   		   media-request.o
>>   
>> +ifeq ($(CONFIG_USB),y)
>> +	media-objs += media-dev-allocator.o
>> +endif
>> +
>>   #
>>   # I2C drivers should come before other drivers, otherwise they'll fail
>>   # when compiled as builtin drivers
>> diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c
>> new file mode 100644
>> index 000000000000..4606456c1e86
>> --- /dev/null
>> +++ b/drivers/media/media-dev-allocator.c
>> @@ -0,0 +1,144 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
> 
> GPL-2.0+
> 

I would like to address this in a follow-on patch instead of
re-doing the series again. Hope that is okay.

>> +/*
>> + * media-dev-allocator.c - Media Controller Device Allocator API
>> + *
>> + * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
>> + *
>> + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + */
>> +
>> +/*
>> + * This file adds a global refcounted Media Controller Device Instance API.
>> + * A system wide global media device list is managed and each media device
>> + * includes a kref count. The last put on the media device releases the media
>> + * device instance.
>> + *
>> + */
>> +
>> +#include <linux/kref.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/usb.h>
>> +
>> +#include <media/media-device.h>
>> +
>> +static LIST_HEAD(media_device_list);
>> +static DEFINE_MUTEX(media_device_lock);
>> +
>> +struct media_device_instance {
>> +	struct media_device mdev;
>> +	struct module *owner;
>> +	struct list_head list;
>> +	struct kref refcount;
>> +};
>> +
>> +static inline struct media_device_instance *
>> +to_media_device_instance(struct media_device *mdev)
>> +{
>> +	return container_of(mdev, struct media_device_instance, mdev);
>> +}
>> +
>> +static void media_device_instance_release(struct kref *kref)
>> +{
>> +	struct media_device_instance *mdi =
>> +		container_of(kref, struct media_device_instance, refcount);
>> +
>> +	dev_dbg(mdi->mdev.dev, "%s: mdev=%p\n", __func__, &mdi->mdev);
>> +
>> +	mutex_lock(&media_device_lock);
>> +
>> +	media_device_unregister(&mdi->mdev);
>> +	media_device_cleanup(&mdi->mdev);
> 
> This is a problem, albeit not really more of a problem than it is in a
> driver.

Okay good to know that it can be addressed in your media device
refcounting series.

The refcounting changes can be made here instead. I'll take this
> into account in the media device refcounting series I'm planning to start
> working on again; would you be perhaps able to help testing with this
> device once I have patches in that shape? I have no access to the hardware.
> 

Absolutely. I will be happy to help you with testing on the same
hardware, I used for this series.

>> +
>> +	list_del(&mdi->list);
>> +	mutex_unlock(&media_device_lock);
>> +
>> +	kfree(mdi);
>> +}
>> +
>> +/* Callers should hold media_device_lock when calling this function */
>> +static struct media_device *__media_device_get(struct device *dev,
>> +						const char *module_name,
>> +						struct module *modp)
>> +{
>> +	struct media_device_instance *mdi;
>> +
>> +	list_for_each_entry(mdi, &media_device_list, list) {
>> +
>> +		if (mdi->mdev.dev != dev)
>> +			continue;
>> +
>> +		kref_get(&mdi->refcount);
>> +
>> +		/* get module reference for the media_device owner */
>> +		if (modp != mdi->owner && !try_module_get(mdi->owner))
>> +			dev_err(dev, "%s: try_module_get() error\n", __func__);
>> +		dev_dbg(dev, "%s: get mdev=%p module_name %s\n",
>> +			__func__, &mdi->mdev, module_name);
>> +		return &mdi->mdev;
>> +	}
>> +
>> +	mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
>> +	if (!mdi)
>> +		return NULL;
>> +
>> +	mdi->owner = modp;
>> +	kref_init(&mdi->refcount);
>> +	list_add_tail(&mdi->list, &media_device_list);
>> +
>> +	dev_dbg(dev, "%s: alloc mdev=%p module_name %s\n", __func__,
>> +		&mdi->mdev, module_name);
>> +	return &mdi->mdev;
>> +}
>> +
>> +#if IS_ENABLED(CONFIG_USB)
> 
> You already compile the file only if CONFIG_USB is enabled. I think you
> could remove this.
> 
>> +struct media_device *media_device_usb_allocate(struct usb_device *udev,
>> +					       const char *module_name)
> 
> I'd like to suggest working based on usb_interface instead of usb_device
> here: that object already exists and you can find out the device based on
> it. It seems all callers of this function already have the usb_interface
> around.
> 

Is there an advantage to using interface instead of the parent device?
Is there a problem doing it this way?


>> +{
>> +	struct media_device *mdev;
>> +	struct module *modptr;
>> +
>> +	mutex_lock(&module_mutex);
>> +	modptr = find_module(module_name);
>> +	mutex_unlock(&module_mutex);
>> +
>> +	mutex_lock(&media_device_lock);
>> +	mdev = __media_device_get(&udev->dev, module_name, modptr);
>> +	if (!mdev) {
>> +		mutex_unlock(&media_device_lock);
>> +		return ERR_PTR(-ENOMEM);
>> +	}
>> +
>> +	/* check if media device is already initialized */
>> +	if (!mdev->dev)
>> +		__media_device_usb_init(mdev, udev, udev->product,
>> +					module_name);
>> +	mutex_unlock(&media_device_lock);
>> +	return mdev;
>> +}
>> +EXPORT_SYMBOL_GPL(media_device_usb_allocate);
>> +#endif
>> +
>> +void media_device_delete(struct media_device *mdev, const char *module_name)
> 
> Same here. The use of the module name seems a bit hackish to me, albeit I
> suppose it'd work, too.
> 

What is hackish about it? I found it very useful to use it in debug and
error messages that are user-friendly.

thanks,
-- Shuah

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 1/4] media: Media Device Allocator API
@ 2019-01-26  0:27       ` shuah
  0 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-26  0:27 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: alsa-devel, linux-kernel, tiwai, hverkuil, mchehab, shuah, linux-media

Hi Sakari,

On 1/25/19 8:38 AM, Sakari Ailus wrote:
> Hi Shuah,
> 
> On Thu, Jan 24, 2019 at 01:32:38PM -0700, Shuah Khan wrote:
>> Media Device Allocator API to allows multiple drivers share a media device.
>> This API solves a very common use-case for media devices where one physical
>> device (an USB stick) provides both audio and video. When such media device
>> exposes a standard USB Audio class, a proprietary Video class, two or more
>> independent drivers will share a single physical USB bridge. In such cases,
>> it is necessary to coordinate access to the shared resource.
>>
>> Using this API, drivers can allocate a media device with the shared struct
>> device as the key. Once the media device is allocated by a driver, other
>> drivers can get a reference to it. The media device is released when all
>> the references are released.
> 
> Are there real, non-USB devices that could use the same API?
> 

There might be. I don't have any to test. This patch is restricted
to USB at the moment.

>>
>> Signed-off-by: Shuah Khan <shuah@kernel.org>
>> ---
>>   Documentation/media/kapi/mc-core.rst |  41 ++++++++
>>   drivers/media/Makefile               |   4 +
>>   drivers/media/media-dev-allocator.c  | 144 +++++++++++++++++++++++++++
>>   include/media/media-dev-allocator.h  |  53 ++++++++++
>>   4 files changed, 242 insertions(+)
>>   create mode 100644 drivers/media/media-dev-allocator.c
>>   create mode 100644 include/media/media-dev-allocator.h
>>
>> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
>> index 0bcfeadbc52d..07f2a6a90af2 100644
>> --- a/Documentation/media/kapi/mc-core.rst
>> +++ b/Documentation/media/kapi/mc-core.rst
>> @@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific
>>   helper functions to provide easy access for commonly needed information, and
>>   in the end provide a way to use driver-specific callbacks.
>>   
>> +Media Controller Device Allocator API
>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> +
>> +When the media device belongs to more than one driver, the shared media
>> +device is allocated with the shared struct device as the key for look ups.
>> +
>> +The shared media device should stay in registered state until the last
>> +driver unregisters it. In addition, the media device should be released when
>> +all the references are released. Each driver gets a reference to the media
>> +device during probe, when it allocates the media device. If media device is
>> +already allocated, the allocate API bumps up the refcount and returns the
>> +existing media device. The driver puts the reference back in its disconnect
>> +routine when it calls :c:func:`media_device_delete()`.
>> +
>> +The media device is unregistered and cleaned up from the kref put handler to
>> +ensure that the media device stays in registered state until the last driver
>> +unregisters the media device.
>> +
>> +**Driver Usage**
>> +
>> +Drivers should use the appropriate media-core routines to manage the shared
>> +media device life-time handling the two states:
>> +1. allocate -> register -> delete
>> +2. get reference to already registered device -> delete
>> +
>> +call :c:func:`media_device_delete()` routine to make sure the shared media
>> +device delete is handled correctly.
>> +
>> +**driver probe:**
>> +Call :c:func:`media_device_usb_allocate()` to allocate or get a reference
>> +Call :c:func:`media_device_register()`, if media devnode isn't registered
>> +
>> +**driver disconnect:**
>> +Call :c:func:`media_device_delete()` to free the media_device. Freeing is
>> +handled by the kref put handler.
>> +
>> +API Definitions
>> +^^^^^^^^^^^^^^^
>> +
>>   .. kernel-doc:: include/media/media-device.h
>>   
>>   .. kernel-doc:: include/media/media-devnode.h
>> @@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks.
>>   .. kernel-doc:: include/media/media-entity.h
>>   
>>   .. kernel-doc:: include/media/media-request.h
>> +
>> +.. kernel-doc:: include/media/media-dev-allocator.h
>> diff --git a/drivers/media/Makefile b/drivers/media/Makefile
>> index 985d35ec6b29..1d7653318af6 100644
>> --- a/drivers/media/Makefile
>> +++ b/drivers/media/Makefile
>> @@ -6,6 +6,10 @@
>>   media-objs	:= media-device.o media-devnode.o media-entity.o \
>>   		   media-request.o
>>   
>> +ifeq ($(CONFIG_USB),y)
>> +	media-objs += media-dev-allocator.o
>> +endif
>> +
>>   #
>>   # I2C drivers should come before other drivers, otherwise they'll fail
>>   # when compiled as builtin drivers
>> diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c
>> new file mode 100644
>> index 000000000000..4606456c1e86
>> --- /dev/null
>> +++ b/drivers/media/media-dev-allocator.c
>> @@ -0,0 +1,144 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
> 
> GPL-2.0+
> 

I would like to address this in a follow-on patch instead of
re-doing the series again. Hope that is okay.

>> +/*
>> + * media-dev-allocator.c - Media Controller Device Allocator API
>> + *
>> + * Copyright (c) 2018 Shuah Khan <shuah@kernel.org>
>> + *
>> + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + */
>> +
>> +/*
>> + * This file adds a global refcounted Media Controller Device Instance API.
>> + * A system wide global media device list is managed and each media device
>> + * includes a kref count. The last put on the media device releases the media
>> + * device instance.
>> + *
>> + */
>> +
>> +#include <linux/kref.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/usb.h>
>> +
>> +#include <media/media-device.h>
>> +
>> +static LIST_HEAD(media_device_list);
>> +static DEFINE_MUTEX(media_device_lock);
>> +
>> +struct media_device_instance {
>> +	struct media_device mdev;
>> +	struct module *owner;
>> +	struct list_head list;
>> +	struct kref refcount;
>> +};
>> +
>> +static inline struct media_device_instance *
>> +to_media_device_instance(struct media_device *mdev)
>> +{
>> +	return container_of(mdev, struct media_device_instance, mdev);
>> +}
>> +
>> +static void media_device_instance_release(struct kref *kref)
>> +{
>> +	struct media_device_instance *mdi =
>> +		container_of(kref, struct media_device_instance, refcount);
>> +
>> +	dev_dbg(mdi->mdev.dev, "%s: mdev=%p\n", __func__, &mdi->mdev);
>> +
>> +	mutex_lock(&media_device_lock);
>> +
>> +	media_device_unregister(&mdi->mdev);
>> +	media_device_cleanup(&mdi->mdev);
> 
> This is a problem, albeit not really more of a problem than it is in a
> driver.

Okay good to know that it can be addressed in your media device
refcounting series.

The refcounting changes can be made here instead. I'll take this
> into account in the media device refcounting series I'm planning to start
> working on again; would you be perhaps able to help testing with this
> device once I have patches in that shape? I have no access to the hardware.
> 

Absolutely. I will be happy to help you with testing on the same
hardware, I used for this series.

>> +
>> +	list_del(&mdi->list);
>> +	mutex_unlock(&media_device_lock);
>> +
>> +	kfree(mdi);
>> +}
>> +
>> +/* Callers should hold media_device_lock when calling this function */
>> +static struct media_device *__media_device_get(struct device *dev,
>> +						const char *module_name,
>> +						struct module *modp)
>> +{
>> +	struct media_device_instance *mdi;
>> +
>> +	list_for_each_entry(mdi, &media_device_list, list) {
>> +
>> +		if (mdi->mdev.dev != dev)
>> +			continue;
>> +
>> +		kref_get(&mdi->refcount);
>> +
>> +		/* get module reference for the media_device owner */
>> +		if (modp != mdi->owner && !try_module_get(mdi->owner))
>> +			dev_err(dev, "%s: try_module_get() error\n", __func__);
>> +		dev_dbg(dev, "%s: get mdev=%p module_name %s\n",
>> +			__func__, &mdi->mdev, module_name);
>> +		return &mdi->mdev;
>> +	}
>> +
>> +	mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
>> +	if (!mdi)
>> +		return NULL;
>> +
>> +	mdi->owner = modp;
>> +	kref_init(&mdi->refcount);
>> +	list_add_tail(&mdi->list, &media_device_list);
>> +
>> +	dev_dbg(dev, "%s: alloc mdev=%p module_name %s\n", __func__,
>> +		&mdi->mdev, module_name);
>> +	return &mdi->mdev;
>> +}
>> +
>> +#if IS_ENABLED(CONFIG_USB)
> 
> You already compile the file only if CONFIG_USB is enabled. I think you
> could remove this.
> 
>> +struct media_device *media_device_usb_allocate(struct usb_device *udev,
>> +					       const char *module_name)
> 
> I'd like to suggest working based on usb_interface instead of usb_device
> here: that object already exists and you can find out the device based on
> it. It seems all callers of this function already have the usb_interface
> around.
> 

Is there an advantage to using interface instead of the parent device?
Is there a problem doing it this way?


>> +{
>> +	struct media_device *mdev;
>> +	struct module *modptr;
>> +
>> +	mutex_lock(&module_mutex);
>> +	modptr = find_module(module_name);
>> +	mutex_unlock(&module_mutex);
>> +
>> +	mutex_lock(&media_device_lock);
>> +	mdev = __media_device_get(&udev->dev, module_name, modptr);
>> +	if (!mdev) {
>> +		mutex_unlock(&media_device_lock);
>> +		return ERR_PTR(-ENOMEM);
>> +	}
>> +
>> +	/* check if media device is already initialized */
>> +	if (!mdev->dev)
>> +		__media_device_usb_init(mdev, udev, udev->product,
>> +					module_name);
>> +	mutex_unlock(&media_device_lock);
>> +	return mdev;
>> +}
>> +EXPORT_SYMBOL_GPL(media_device_usb_allocate);
>> +#endif
>> +
>> +void media_device_delete(struct media_device *mdev, const char *module_name)
> 
> Same here. The use of the module name seems a bit hackish to me, albeit I
> suppose it'd work, too.
> 

What is hackish about it? I found it very useful to use it in debug and
error messages that are user-friendly.

thanks,
-- Shuah

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
                   ` (4 preceding siblings ...)
  2019-01-25 15:28   ` Sakari Ailus
@ 2019-01-28 12:03 ` Hans Verkuil
  2019-01-28 23:48   ` shuah
  5 siblings, 1 reply; 23+ messages in thread
From: Hans Verkuil @ 2019-01-28 12:03 UTC (permalink / raw)
  To: Shuah Khan, mchehab, perex, tiwai; +Cc: linux-media, linux-kernel, alsa-devel

Hi Shuah,

On 1/24/19 9:32 PM, Shuah Khan wrote:
> Media Device Allocator API to allows multiple drivers share a media device.
> This API solves a very common use-case for media devices where one physical
> device (an USB stick) provides both audio and video. When such media device
> exposes a standard USB Audio class, a proprietary Video class, two or more
> independent drivers will share a single physical USB bridge. In such cases,
> it is necessary to coordinate access to the shared resource.
> 
> Using this API, drivers can allocate a media device with the shared struct
> device as the key. Once the media device is allocated by a driver, other
> drivers can get a reference to it. The media device is released when all
> the references are released.
> 
> - This patch series is tested on 5.0-rc3 and addresses comments on
>   v9 series from Hans Verkuil.
> - v9 was tested on 4.20-rc6.
> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>   arecord. When analog is streaming, digital and audio user-space
>   applications detect that the tuner is busy and exit. When digital
>   is streaming, analog and audio applications detect that the tuner is
>   busy and exit. When arecord is owns the tuner, digital and analog
>   detect that the tuner is busy and exit.

I've been doing some testing with my au0828, and I am confused about one
thing, probably because it has been too long ago since I last looked into
this in detail:

Why can't I change the tuner frequency if arecord (and only arecord) is
streaming audio? If arecord is streaming, then it is recording the audio
from the analog TV tuner, right? So changing the analog TV frequency
should be fine.

I understand why you can't switch to DVB mode, but analog TV should be OK.
Or am I missing something?

Regards,

	Hans

> - Tested media device allocator API with bind/unbind testing on
>   snd-usb-audio and au0828 drivers to make sure /dev/mediaX is released
>   only when the last driver is unbound.
> - Addressed review comments from Hans on the RFC v8 (rebased on 4.19)
> - Updated change log to describe the use-case more clearly.
> - No changes to 0001,0002 code since the v7 referenced below.
> - 0003 is a new patch to enable ALSA defines that have been
>   disabled for kernel between 4.9 and 4.19.
> - Minor merge conflict resolution in 0004.
> - Added SPDX to new files.
> 
> Changes since v9:
> - Patch 1: Fix mutex assert warning from find_module() calls. This
>   code was written before the change to find_module() that requires
>   callers to hold module_mutex. I missed this during my testing on
>   4.20-rc6. Hans Verkuil reported the problem.
> - Patch 4: sound/usb: Initializes all the entities it can before
>   registering the device based on comments from Hans Verkuil
> - Carried Reviewed-by tag from Takashi Iwai for the sound from v9.
> - No changes to Patches 2 and 3.
> 
> References:
> https://lkml.org/lkml/2018/11/2/169
> https://www.mail-archive.com/linux-media@vger.kernel.org/msg105854.html
> 
> Shuah Khan (4):
>   media: Media Device Allocator API
>   media: change au0828 to use Media Device Allocator API
>   media: media.h: Enable ALSA MEDIA_INTF_T* interface types
>   sound/usb: Use Media Controller API to share media resources
> 
>  Documentation/media/kapi/mc-core.rst   |  41 ++++
>  drivers/media/Makefile                 |   4 +
>  drivers/media/media-dev-allocator.c    | 144 +++++++++++
>  drivers/media/usb/au0828/au0828-core.c |  12 +-
>  drivers/media/usb/au0828/au0828.h      |   1 +
>  include/media/media-dev-allocator.h    |  53 ++++
>  include/uapi/linux/media.h             |  25 +-
>  sound/usb/Kconfig                      |   4 +
>  sound/usb/Makefile                     |   2 +
>  sound/usb/card.c                       |  14 ++
>  sound/usb/card.h                       |   3 +
>  sound/usb/media.c                      | 327 +++++++++++++++++++++++++
>  sound/usb/media.h                      |  74 ++++++
>  sound/usb/mixer.h                      |   3 +
>  sound/usb/pcm.c                        |  29 ++-
>  sound/usb/quirks-table.h               |   1 +
>  sound/usb/stream.c                     |   2 +
>  sound/usb/usbaudio.h                   |   6 +
>  18 files changed, 723 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/media/media-dev-allocator.c
>  create mode 100644 include/media/media-dev-allocator.h
>  create mode 100644 sound/usb/media.c
>  create mode 100644 sound/usb/media.h
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-28 12:03 ` Hans Verkuil
@ 2019-01-28 23:48   ` shuah
  2019-01-29  9:43     ` Hans Verkuil
  0 siblings, 1 reply; 23+ messages in thread
From: shuah @ 2019-01-28 23:48 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, perex, tiwai
  Cc: linux-media, linux-kernel, alsa-devel, shuah

Hi Hans,

On 1/28/19 5:03 AM, Hans Verkuil wrote:
> Hi Shuah,
> 
> On 1/24/19 9:32 PM, Shuah Khan wrote:
>> Media Device Allocator API to allows multiple drivers share a media device.
>> This API solves a very common use-case for media devices where one physical
>> device (an USB stick) provides both audio and video. When such media device
>> exposes a standard USB Audio class, a proprietary Video class, two or more
>> independent drivers will share a single physical USB bridge. In such cases,
>> it is necessary to coordinate access to the shared resource.
>>
>> Using this API, drivers can allocate a media device with the shared struct
>> device as the key. Once the media device is allocated by a driver, other
>> drivers can get a reference to it. The media device is released when all
>> the references are released.
>>
>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>    v9 series from Hans Verkuil.
>> - v9 was tested on 4.20-rc6.
>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>    arecord. When analog is streaming, digital and audio user-space
>>    applications detect that the tuner is busy and exit. When digital
>>    is streaming, analog and audio applications detect that the tuner is
>>    busy and exit. When arecord is owns the tuner, digital and analog
>>    detect that the tuner is busy and exit.
> 
> I've been doing some testing with my au0828, and I am confused about one
> thing, probably because it has been too long ago since I last looked into
> this in detail:
> 

Great.

> Why can't I change the tuner frequency if arecord (and only arecord) is
> streaming audio? If arecord is streaming, then it is recording the audio
> from the analog TV tuner, right? So changing the analog TV frequency
> should be fine.
> 

Changing analog TV frequency would be s_frequency. The way it works is
any s_* calls would require holding the pipeline. In Analog TV case, it
would mean holding both audio and video pipelines for any changes
including TV.

As I recall, we discussed this design and the decision was to make all
s_* calls interfaces to hold the tuner. A special exception is g_tuner
in case of au0828. au0828 initializes the tuner from s_* interfaces and
its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
arecord audio stream.

Query (q_*) works just fine without holding the pipeline. I limited the
analog holds to just the ones that are required. The current set is
required to avoid audio stream disruptions.

I made sure v4l-ctl --all works when the pipeline is locked by any one
of the 3 (audio, video, DVB).

Hope this helps.

thanks,
-- Shuah



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-28 23:48   ` shuah
@ 2019-01-29  9:43     ` Hans Verkuil
  2019-01-30  1:50         ` shuah
  0 siblings, 1 reply; 23+ messages in thread
From: Hans Verkuil @ 2019-01-29  9:43 UTC (permalink / raw)
  To: shuah, mchehab, perex, tiwai; +Cc: linux-media, linux-kernel, alsa-devel

On 1/29/19 12:48 AM, shuah wrote:
> Hi Hans,
> 
> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>> Hi Shuah,
>>
>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>> Media Device Allocator API to allows multiple drivers share a media device.
>>> This API solves a very common use-case for media devices where one physical
>>> device (an USB stick) provides both audio and video. When such media device
>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>> independent drivers will share a single physical USB bridge. In such cases,
>>> it is necessary to coordinate access to the shared resource.
>>>
>>> Using this API, drivers can allocate a media device with the shared struct
>>> device as the key. Once the media device is allocated by a driver, other
>>> drivers can get a reference to it. The media device is released when all
>>> the references are released.
>>>
>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>    v9 series from Hans Verkuil.
>>> - v9 was tested on 4.20-rc6.
>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>    arecord. When analog is streaming, digital and audio user-space
>>>    applications detect that the tuner is busy and exit. When digital
>>>    is streaming, analog and audio applications detect that the tuner is
>>>    busy and exit. When arecord is owns the tuner, digital and analog
>>>    detect that the tuner is busy and exit.
>>
>> I've been doing some testing with my au0828, and I am confused about one
>> thing, probably because it has been too long ago since I last looked into
>> this in detail:
>>
> 
> Great.
> 
>> Why can't I change the tuner frequency if arecord (and only arecord) is
>> streaming audio? If arecord is streaming, then it is recording the audio
>> from the analog TV tuner, right? So changing the analog TV frequency
>> should be fine.
>>
> 
> Changing analog TV frequency would be s_frequency. The way it works is
> any s_* calls would require holding the pipeline. In Analog TV case, it
> would mean holding both audio and video pipelines for any changes
> including TV.
> 
> As I recall, we discussed this design and the decision was to make all
> s_* calls interfaces to hold the tuner. A special exception is g_tuner
> in case of au0828. au0828 initializes the tuner from s_* interfaces and
> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
> arecord audio stream.
> 
> Query (q_*) works just fine without holding the pipeline. I limited the
> analog holds to just the ones that are required. The current set is
> required to avoid audio stream disruptions.

So I am not sure about that ('avoid audio stream disruptions'): if I
stream video AND use arecord, then I can just set the frequency while
streaming. Doesn't that interrupt audio as well? And are you sure changing
the tuner frequency actually disrupts audio? And if audio is disrupted,
are we talking about a glitch or is audio permanently disrupted?

That's basically the inconsistent behavior I noticed: just running arecord
will prevent me from changing the frequency, but if I run arecord and stream
video, then it is suddenly OK to change the frequency.

BTW, I think there was also inconsistent behavior in the order of streaming
audio and video: if I stream video first, then I can stream audio afterwards.
But if I stream audio first, then (if I remember correctly) I can't start
video streaming.

Regards,

	Hans

> 
> I made sure v4l-ctl --all works when the pipeline is locked by any one
> of the 3 (audio, video, DVB).
> 
> Hope this helps.
> 
> thanks,
> -- Shuah
> 
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-29  9:43     ` Hans Verkuil
@ 2019-01-30  1:50         ` shuah
  0 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-30  1:50 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, perex, tiwai
  Cc: linux-media, linux-kernel, alsa-devel, shuah

On 1/29/19 2:43 AM, Hans Verkuil wrote:
> On 1/29/19 12:48 AM, shuah wrote:
>> Hi Hans,
>>
>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>> Hi Shuah,
>>>
>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>> This API solves a very common use-case for media devices where one physical
>>>> device (an USB stick) provides both audio and video. When such media device
>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>> it is necessary to coordinate access to the shared resource.
>>>>
>>>> Using this API, drivers can allocate a media device with the shared struct
>>>> device as the key. Once the media device is allocated by a driver, other
>>>> drivers can get a reference to it. The media device is released when all
>>>> the references are released.
>>>>
>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>     v9 series from Hans Verkuil.
>>>> - v9 was tested on 4.20-rc6.
>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>     arecord. When analog is streaming, digital and audio user-space
>>>>     applications detect that the tuner is busy and exit. When digital
>>>>     is streaming, analog and audio applications detect that the tuner is
>>>>     busy and exit. When arecord is owns the tuner, digital and analog
>>>>     detect that the tuner is busy and exit.
>>>
>>> I've been doing some testing with my au0828, and I am confused about one
>>> thing, probably because it has been too long ago since I last looked into
>>> this in detail:
>>>
>>
>> Great.
>>
>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>> streaming audio? If arecord is streaming, then it is recording the audio
>>> from the analog TV tuner, right? So changing the analog TV frequency
>>> should be fine.
>>>
>>
>> Changing analog TV frequency would be s_frequency. The way it works is
>> any s_* calls would require holding the pipeline. In Analog TV case, it
>> would mean holding both audio and video pipelines for any changes
>> including TV.
>>
>> As I recall, we discussed this design and the decision was to make all
>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>> arecord audio stream.
>>
>> Query (q_*) works just fine without holding the pipeline. I limited the
>> analog holds to just the ones that are required. The current set is
>> required to avoid audio stream disruptions.
> 
> So I am not sure about that ('avoid audio stream disruptions'): if I
> stream video AND use arecord, then I can just set the frequency while
> streaming. Doesn't that interrupt audio as well? And are you sure changing
> the tuner frequency actually disrupts audio? And if audio is disrupted,
> are we talking about a glitch or is audio permanently disrupted?

I think it is a glitch. I will run some tests and let you know.
> 
> That's basically the inconsistent behavior I noticed: just running arecord
> will prevent me from changing the frequency, but if I run arecord and stream
> video, then it is suddenly OK to change the frequency.

How are you changing frequency? I want to duplicate what you are doing.

> 
> BTW, I think there was also inconsistent behavior in the order of streaming
> audio and video: if I stream video first, then I can stream audio afterwards.
> But if I stream audio first, then (if I remember correctly) I can't start
> video streaming.
> 

I will run some tests tomorrow and see what I find. Which video apps are
you running for these tests?

thanks,
-- Shuah

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
@ 2019-01-30  1:50         ` shuah
  0 siblings, 0 replies; 23+ messages in thread
From: shuah @ 2019-01-30  1:50 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, perex, tiwai
  Cc: alsa-devel, shuah, linux-kernel, linux-media

On 1/29/19 2:43 AM, Hans Verkuil wrote:
> On 1/29/19 12:48 AM, shuah wrote:
>> Hi Hans,
>>
>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>> Hi Shuah,
>>>
>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>> This API solves a very common use-case for media devices where one physical
>>>> device (an USB stick) provides both audio and video. When such media device
>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>> it is necessary to coordinate access to the shared resource.
>>>>
>>>> Using this API, drivers can allocate a media device with the shared struct
>>>> device as the key. Once the media device is allocated by a driver, other
>>>> drivers can get a reference to it. The media device is released when all
>>>> the references are released.
>>>>
>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>     v9 series from Hans Verkuil.
>>>> - v9 was tested on 4.20-rc6.
>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>     arecord. When analog is streaming, digital and audio user-space
>>>>     applications detect that the tuner is busy and exit. When digital
>>>>     is streaming, analog and audio applications detect that the tuner is
>>>>     busy and exit. When arecord is owns the tuner, digital and analog
>>>>     detect that the tuner is busy and exit.
>>>
>>> I've been doing some testing with my au0828, and I am confused about one
>>> thing, probably because it has been too long ago since I last looked into
>>> this in detail:
>>>
>>
>> Great.
>>
>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>> streaming audio? If arecord is streaming, then it is recording the audio
>>> from the analog TV tuner, right? So changing the analog TV frequency
>>> should be fine.
>>>
>>
>> Changing analog TV frequency would be s_frequency. The way it works is
>> any s_* calls would require holding the pipeline. In Analog TV case, it
>> would mean holding both audio and video pipelines for any changes
>> including TV.
>>
>> As I recall, we discussed this design and the decision was to make all
>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>> arecord audio stream.
>>
>> Query (q_*) works just fine without holding the pipeline. I limited the
>> analog holds to just the ones that are required. The current set is
>> required to avoid audio stream disruptions.
> 
> So I am not sure about that ('avoid audio stream disruptions'): if I
> stream video AND use arecord, then I can just set the frequency while
> streaming. Doesn't that interrupt audio as well? And are you sure changing
> the tuner frequency actually disrupts audio? And if audio is disrupted,
> are we talking about a glitch or is audio permanently disrupted?

I think it is a glitch. I will run some tests and let you know.
> 
> That's basically the inconsistent behavior I noticed: just running arecord
> will prevent me from changing the frequency, but if I run arecord and stream
> video, then it is suddenly OK to change the frequency.

How are you changing frequency? I want to duplicate what you are doing.

> 
> BTW, I think there was also inconsistent behavior in the order of streaming
> audio and video: if I stream video first, then I can stream audio afterwards.
> But if I stream audio first, then (if I remember correctly) I can't start
> video streaming.
> 

I will run some tests tomorrow and see what I find. Which video apps are
you running for these tests?

thanks,
-- Shuah

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-30  1:50         ` shuah
@ 2019-01-30  7:42           ` Hans Verkuil
  -1 siblings, 0 replies; 23+ messages in thread
From: Hans Verkuil @ 2019-01-30  7:42 UTC (permalink / raw)
  To: shuah, mchehab, perex, tiwai; +Cc: linux-media, linux-kernel, alsa-devel

On 1/30/19 2:50 AM, shuah wrote:
> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>> On 1/29/19 12:48 AM, shuah wrote:
>>> Hi Hans,
>>>
>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>> Hi Shuah,
>>>>
>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>> This API solves a very common use-case for media devices where one physical
>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>> it is necessary to coordinate access to the shared resource.
>>>>>
>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>> drivers can get a reference to it. The media device is released when all
>>>>> the references are released.
>>>>>
>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>     v9 series from Hans Verkuil.
>>>>> - v9 was tested on 4.20-rc6.
>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>     arecord. When analog is streaming, digital and audio user-space
>>>>>     applications detect that the tuner is busy and exit. When digital
>>>>>     is streaming, analog and audio applications detect that the tuner is
>>>>>     busy and exit. When arecord is owns the tuner, digital and analog
>>>>>     detect that the tuner is busy and exit.
>>>>
>>>> I've been doing some testing with my au0828, and I am confused about one
>>>> thing, probably because it has been too long ago since I last looked into
>>>> this in detail:
>>>>
>>>
>>> Great.
>>>
>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>> should be fine.
>>>>
>>>
>>> Changing analog TV frequency would be s_frequency. The way it works is
>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>> would mean holding both audio and video pipelines for any changes
>>> including TV.
>>>
>>> As I recall, we discussed this design and the decision was to make all
>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>> arecord audio stream.
>>>
>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>> analog holds to just the ones that are required. The current set is
>>> required to avoid audio stream disruptions.
>>
>> So I am not sure about that ('avoid audio stream disruptions'): if I
>> stream video AND use arecord, then I can just set the frequency while
>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>> are we talking about a glitch or is audio permanently disrupted?
> 
> I think it is a glitch. I will run some tests and let you know.
>>
>> That's basically the inconsistent behavior I noticed: just running arecord
>> will prevent me from changing the frequency, but if I run arecord and stream
>> video, then it is suddenly OK to change the frequency.
> 
> How are you changing frequency? I want to duplicate what you are doing.

v4l2-ctl -f <freq>

> 
>>
>> BTW, I think there was also inconsistent behavior in the order of streaming
>> audio and video: if I stream video first, then I can stream audio afterwards.
>> But if I stream audio first, then (if I remember correctly) I can't start
>> video streaming.
>>
> 
> I will run some tests tomorrow and see what I find. Which video apps are
> you running for these tests?

v4l2-ctl or qv4l2.

Regards,

	Hans

> 
> thanks,
> -- Shuah
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
@ 2019-01-30  7:42           ` Hans Verkuil
  0 siblings, 0 replies; 23+ messages in thread
From: Hans Verkuil @ 2019-01-30  7:42 UTC (permalink / raw)
  To: shuah, mchehab, perex, tiwai; +Cc: alsa-devel, linux-kernel, linux-media

On 1/30/19 2:50 AM, shuah wrote:
> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>> On 1/29/19 12:48 AM, shuah wrote:
>>> Hi Hans,
>>>
>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>> Hi Shuah,
>>>>
>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>> This API solves a very common use-case for media devices where one physical
>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>> it is necessary to coordinate access to the shared resource.
>>>>>
>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>> drivers can get a reference to it. The media device is released when all
>>>>> the references are released.
>>>>>
>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>     v9 series from Hans Verkuil.
>>>>> - v9 was tested on 4.20-rc6.
>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>     arecord. When analog is streaming, digital and audio user-space
>>>>>     applications detect that the tuner is busy and exit. When digital
>>>>>     is streaming, analog and audio applications detect that the tuner is
>>>>>     busy and exit. When arecord is owns the tuner, digital and analog
>>>>>     detect that the tuner is busy and exit.
>>>>
>>>> I've been doing some testing with my au0828, and I am confused about one
>>>> thing, probably because it has been too long ago since I last looked into
>>>> this in detail:
>>>>
>>>
>>> Great.
>>>
>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>> should be fine.
>>>>
>>>
>>> Changing analog TV frequency would be s_frequency. The way it works is
>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>> would mean holding both audio and video pipelines for any changes
>>> including TV.
>>>
>>> As I recall, we discussed this design and the decision was to make all
>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>> arecord audio stream.
>>>
>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>> analog holds to just the ones that are required. The current set is
>>> required to avoid audio stream disruptions.
>>
>> So I am not sure about that ('avoid audio stream disruptions'): if I
>> stream video AND use arecord, then I can just set the frequency while
>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>> are we talking about a glitch or is audio permanently disrupted?
> 
> I think it is a glitch. I will run some tests and let you know.
>>
>> That's basically the inconsistent behavior I noticed: just running arecord
>> will prevent me from changing the frequency, but if I run arecord and stream
>> video, then it is suddenly OK to change the frequency.
> 
> How are you changing frequency? I want to duplicate what you are doing.

v4l2-ctl -f <freq>

> 
>>
>> BTW, I think there was also inconsistent behavior in the order of streaming
>> audio and video: if I stream video first, then I can stream audio afterwards.
>> But if I stream audio first, then (if I remember correctly) I can't start
>> video streaming.
>>
> 
> I will run some tests tomorrow and see what I find. Which video apps are
> you running for these tests?

v4l2-ctl or qv4l2.

Regards,

	Hans

> 
> thanks,
> -- Shuah
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-01-30  7:42           ` Hans Verkuil
  (?)
@ 2019-02-01  0:46           ` shuah
  2019-02-01  9:21             ` Hans Verkuil
  -1 siblings, 1 reply; 23+ messages in thread
From: shuah @ 2019-02-01  0:46 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, perex, tiwai
  Cc: linux-media, linux-kernel, alsa-devel, shuah

Hi Hans,

On 1/30/19 12:42 AM, Hans Verkuil wrote:
> On 1/30/19 2:50 AM, shuah wrote:
>> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>>> On 1/29/19 12:48 AM, shuah wrote:
>>>> Hi Hans,
>>>>
>>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>>> Hi Shuah,
>>>>>
>>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>>> This API solves a very common use-case for media devices where one physical
>>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>>> it is necessary to coordinate access to the shared resource.
>>>>>>
>>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>>> drivers can get a reference to it. The media device is released when all
>>>>>> the references are released.
>>>>>>
>>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>>      v9 series from Hans Verkuil.
>>>>>> - v9 was tested on 4.20-rc6.
>>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>>      arecord. When analog is streaming, digital and audio user-space
>>>>>>      applications detect that the tuner is busy and exit. When digital
>>>>>>      is streaming, analog and audio applications detect that the tuner is
>>>>>>      busy and exit. When arecord is owns the tuner, digital and analog
>>>>>>      detect that the tuner is busy and exit.
>>>>>
>>>>> I've been doing some testing with my au0828, and I am confused about one
>>>>> thing, probably because it has been too long ago since I last looked into
>>>>> this in detail:
>>>>>
>>>>
>>>> Great.
>>>>
>>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>>> should be fine.
>>>>>
>>>>
>>>> Changing analog TV frequency would be s_frequency. The way it works is
>>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>>> would mean holding both audio and video pipelines for any changes
>>>> including TV.
>>>>
>>>> As I recall, we discussed this design and the decision was to make all
>>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>>> arecord audio stream.
>>>>
>>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>>> analog holds to just the ones that are required. The current set is
>>>> required to avoid audio stream disruptions.
>>>
>>> So I am not sure about that ('avoid audio stream disruptions'): if I
>>> stream video AND use arecord, then I can just set the frequency while
>>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>>> are we talking about a glitch or is audio permanently disrupted?
>>
>> I think it is a glitch. I will run some tests and let you know.
>>>
>>> That's basically the inconsistent behavior I noticed: just running arecord
>>> will prevent me from changing the frequency, but if I run arecord and stream
>>> video, then it is suddenly OK to change the frequency.
>>
>> How are you changing frequency? I want to duplicate what you are doing.
> 
> v4l2-ctl -f <freq>

I am not seeing the inconsistent behavior. Here are my results.

1. Started acecord and while it is running:

arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo

2. Ran v4l2-ctl -f as follows:

v4l2-ctl -f 700
VIDIOC_G_TUNER: failed: Device or resource busy
VIDIOC_S_FREQUENCY: failed: Device or resource busy

Based on the current implementation, it failed with resource
busy as expected.

3. Started v4l2-ctl as follows:

  v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
VIDIOC_STREAMON: failed: Device or resource busy
shuah@deneb:/mnt/data/lkml/v4l-utils/utils/v4l2-ctl$ v4l2-ctl -f 700
VIDIOC_G_TUNER: failed: Device or resource busy
VIDIOC_S_FREQUENCY: failed: Device or resource busy

Based on the current implementation, it failed with resource
busy as expected.

4. After stopping arecord:

v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
<<<<<<<<<<<<< 11.88 fps
<<<<<<<<<<<<<<< 13.36 fps
<<<<<<<<<<<<<<< 14.00 fps
<<<<<<<<<<<<<<<< 14.35 fps
<<<<<<<<<<<<<<< 14.57 fps
<<<<<<<<<<<<<<<< 14.71 fps
<<<<<<<<<


Worked as expected.


5. After stopping above video streaming:

arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo


Worked as expected.

> 
>>
>>>
>>> BTW, I think there was also inconsistent behavior in the order of streaming
>>> audio and video: if I stream video first, then I can stream audio afterwards.
>>> But if I stream audio first, then (if I remember correctly) I can't start
>>> video streaming.
>>>

Okay this is what I saw:

While v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0

I could start arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav

I ran strace on v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
and I didn't see AUDIO holds. The only think of here is that

v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0

doesn't open audio device. I didn't see this when tested with other
video apps, (tvtine, xawtv, vlc). When video is streaming, I see
arecord failing with device busy.

As far I can see, exclusion logic is working correctly. s_freq does
fail now based on the current logic.

btw I tested all of this on 5.0-rc4

thanks,
-- Shuah

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-02-01  0:46           ` shuah
@ 2019-02-01  9:21             ` Hans Verkuil
  2019-02-05 18:10               ` shuah
  0 siblings, 1 reply; 23+ messages in thread
From: Hans Verkuil @ 2019-02-01  9:21 UTC (permalink / raw)
  To: shuah, mchehab, perex, tiwai; +Cc: linux-media, linux-kernel, alsa-devel

On 2/1/19 1:46 AM, shuah wrote:
> Hi Hans,
> 
> On 1/30/19 12:42 AM, Hans Verkuil wrote:
>> On 1/30/19 2:50 AM, shuah wrote:
>>> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>>>> On 1/29/19 12:48 AM, shuah wrote:
>>>>> Hi Hans,
>>>>>
>>>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>>>> Hi Shuah,
>>>>>>
>>>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>>>> This API solves a very common use-case for media devices where one physical
>>>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>>>> it is necessary to coordinate access to the shared resource.
>>>>>>>
>>>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>>>> drivers can get a reference to it. The media device is released when all
>>>>>>> the references are released.
>>>>>>>
>>>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>>>      v9 series from Hans Verkuil.
>>>>>>> - v9 was tested on 4.20-rc6.
>>>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>>>      arecord. When analog is streaming, digital and audio user-space
>>>>>>>      applications detect that the tuner is busy and exit. When digital
>>>>>>>      is streaming, analog and audio applications detect that the tuner is
>>>>>>>      busy and exit. When arecord is owns the tuner, digital and analog
>>>>>>>      detect that the tuner is busy and exit.
>>>>>>
>>>>>> I've been doing some testing with my au0828, and I am confused about one
>>>>>> thing, probably because it has been too long ago since I last looked into
>>>>>> this in detail:
>>>>>>
>>>>>
>>>>> Great.
>>>>>
>>>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>>>> should be fine.
>>>>>>
>>>>>
>>>>> Changing analog TV frequency would be s_frequency. The way it works is
>>>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>>>> would mean holding both audio and video pipelines for any changes
>>>>> including TV.
>>>>>
>>>>> As I recall, we discussed this design and the decision was to make all
>>>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>>>> arecord audio stream.
>>>>>
>>>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>>>> analog holds to just the ones that are required. The current set is
>>>>> required to avoid audio stream disruptions.
>>>>
>>>> So I am not sure about that ('avoid audio stream disruptions'): if I
>>>> stream video AND use arecord, then I can just set the frequency while
>>>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>>>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>>>> are we talking about a glitch or is audio permanently disrupted?
>>>
>>> I think it is a glitch. I will run some tests and let you know.
>>>>
>>>> That's basically the inconsistent behavior I noticed: just running arecord
>>>> will prevent me from changing the frequency, but if I run arecord and stream
>>>> video, then it is suddenly OK to change the frequency.
>>>
>>> How are you changing frequency? I want to duplicate what you are doing.
>>
>> v4l2-ctl -f <freq>
> 
> I am not seeing the inconsistent behavior. Here are my results.
> 
> 1. Started acecord and while it is running:
> 
> arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
> Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo
> 
> 2. Ran v4l2-ctl -f as follows:
> 
> v4l2-ctl -f 700
> VIDIOC_G_TUNER: failed: Device or resource busy
> VIDIOC_S_FREQUENCY: failed: Device or resource busy
> 
> Based on the current implementation, it failed with resource
> busy as expected.
> 
> 3. Started v4l2-ctl as follows:
> 
>  v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
> VIDIOC_STREAMON: failed: Device or resource busy

Why is this? You have one analog tuner and it delivers independent audio
and video streams. I should be able to start/stop audio and video independently.

And as mentioned above, if I use v4l2-ctl for video streaming, then start arecord,
then that works fine. And I can change the tuner frequency while both are streaming.

But doing this the other way around (first start arecord, then v4l2-ctl) then that
doesn't work.

It makes no sense.

Note that v4l2-ctl does not open audio, it solely deals with video. qv4l2 will
open both audio and video, but for testing audio and video independently you
need to use arecord/v4l2-ctl.

In any case, my understanding of how this should work is that both arecord and
v4l2-ctl should attempt to lock the analog tuner resource, but they can share it.

If DVB is using the tuner, then both arecord and v4l2-ctl should fail with -EBUSY.
Same if either of arecord/v4l2-ctl is running, then DVB should fail with -EBUSY.

BTW, I won't be able to test anything myself until Feb 9th since I'm abroad and
don't have access to my au0828.

Regards,

	Hans

> shuah@deneb:/mnt/data/lkml/v4l-utils/utils/v4l2-ctl$ v4l2-ctl -f 700
> VIDIOC_G_TUNER: failed: Device or resource busy
> VIDIOC_S_FREQUENCY: failed: Device or resource busy
> 
> Based on the current implementation, it failed with resource
> busy as expected.
> 
> 4. After stopping arecord:
> 
> v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
> <<<<<<<<<<<<< 11.88 fps
> <<<<<<<<<<<<<<< 13.36 fps
> <<<<<<<<<<<<<<< 14.00 fps
> <<<<<<<<<<<<<<<< 14.35 fps
> <<<<<<<<<<<<<<< 14.57 fps
> <<<<<<<<<<<<<<<< 14.71 fps
> <<<<<<<<<
> 
> 
> Worked as expected.
> 
> 
> 5. After stopping above video streaming:
> 
> arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
> Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo
> 
> 
> Worked as expected.
> 
>>
>>>
>>>>
>>>> BTW, I think there was also inconsistent behavior in the order of streaming
>>>> audio and video: if I stream video first, then I can stream audio afterwards.
>>>> But if I stream audio first, then (if I remember correctly) I can't start
>>>> video streaming.
>>>>
> 
> Okay this is what I saw:
> 
> While v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
> 
> I could start arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
> 
> I ran strace on v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
> and I didn't see AUDIO holds. The only think of here is that
> 
> v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
> 
> doesn't open audio device. I didn't see this when tested with other
> video apps, (tvtine, xawtv, vlc). When video is streaming, I see
> arecord failing with device busy.
> 
> As far I can see, exclusion logic is working correctly. s_freq does
> fail now based on the current logic.
> 
> btw I tested all of this on 5.0-rc4
> 
> thanks,
> -- Shuah


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-02-01  9:21             ` Hans Verkuil
@ 2019-02-05 18:10               ` shuah
  2019-02-06  7:36                 ` Hans Verkuil
  0 siblings, 1 reply; 23+ messages in thread
From: shuah @ 2019-02-05 18:10 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, perex, tiwai
  Cc: linux-media, linux-kernel, alsa-devel, shuah

On 2/1/19 2:21 AM, Hans Verkuil wrote:
> On 2/1/19 1:46 AM, shuah wrote:
>> Hi Hans,
>>
>> On 1/30/19 12:42 AM, Hans Verkuil wrote:
>>> On 1/30/19 2:50 AM, shuah wrote:
>>>> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>>>>> On 1/29/19 12:48 AM, shuah wrote:
>>>>>> Hi Hans,
>>>>>>
>>>>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>>>>> Hi Shuah,
>>>>>>>
>>>>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>>>>> This API solves a very common use-case for media devices where one physical
>>>>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>>>>> it is necessary to coordinate access to the shared resource.
>>>>>>>>
>>>>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>>>>> drivers can get a reference to it. The media device is released when all
>>>>>>>> the references are released.
>>>>>>>>
>>>>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>>>>       v9 series from Hans Verkuil.
>>>>>>>> - v9 was tested on 4.20-rc6.
>>>>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>>>>       arecord. When analog is streaming, digital and audio user-space
>>>>>>>>       applications detect that the tuner is busy and exit. When digital
>>>>>>>>       is streaming, analog and audio applications detect that the tuner is
>>>>>>>>       busy and exit. When arecord is owns the tuner, digital and analog
>>>>>>>>       detect that the tuner is busy and exit.
>>>>>>>
>>>>>>> I've been doing some testing with my au0828, and I am confused about one
>>>>>>> thing, probably because it has been too long ago since I last looked into
>>>>>>> this in detail:
>>>>>>>
>>>>>>
>>>>>> Great.
>>>>>>
>>>>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>>>>> should be fine.
>>>>>>>
>>>>>>
>>>>>> Changing analog TV frequency would be s_frequency. The way it works is
>>>>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>>>>> would mean holding both audio and video pipelines for any changes
>>>>>> including TV.
>>>>>>
>>>>>> As I recall, we discussed this design and the decision was to make all
>>>>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>>>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>>>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>>>>> arecord audio stream.
>>>>>>
>>>>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>>>>> analog holds to just the ones that are required. The current set is
>>>>>> required to avoid audio stream disruptions.
>>>>>
>>>>> So I am not sure about that ('avoid audio stream disruptions'): if I
>>>>> stream video AND use arecord, then I can just set the frequency while
>>>>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>>>>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>>>>> are we talking about a glitch or is audio permanently disrupted?
>>>>
>>>> I think it is a glitch. I will run some tests and let you know.
>>>>>
>>>>> That's basically the inconsistent behavior I noticed: just running arecord
>>>>> will prevent me from changing the frequency, but if I run arecord and stream
>>>>> video, then it is suddenly OK to change the frequency.
>>>>
>>>> How are you changing frequency? I want to duplicate what you are doing.
>>>
>>> v4l2-ctl -f <freq>
>>
>> I am not seeing the inconsistent behavior. Here are my results.
>>
>> 1. Started acecord and while it is running:
>>
>> arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
>> Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo
>>
>> 2. Ran v4l2-ctl -f as follows:
>>
>> v4l2-ctl -f 700
>> VIDIOC_G_TUNER: failed: Device or resource busy
>> VIDIOC_S_FREQUENCY: failed: Device or resource busy
>>
>> Based on the current implementation, it failed with resource
>> busy as expected.
>>
>> 3. Started v4l2-ctl as follows:
>>
>>   v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
>> VIDIOC_STREAMON: failed: Device or resource busy
> 
> Why is this? You have one analog tuner and it delivers independent audio
> and video streams. I should be able to start/stop audio and video independently.
> 
> And as mentioned above, if I use v4l2-ctl for video streaming, then start arecord,
> then that works fine. And I can change the tuner frequency while both are streaming.
> 
> But doing this the other way around (first start arecord, then v4l2-ctl) then that
> doesn't work.
> 
> It makes no sense.
> 
> Note that v4l2-ctl does not open audio, it solely deals with video. qv4l2 will
> open both audio and video, but for testing audio and video independently you
> need to use arecord/v4l2-ctl.
> 
> In any case, my understanding of how this should work is that both arecord and
> v4l2-ctl should attempt to lock the analog tuner resource, but they can share it.
> 
> If DVB is using the tuner, then both arecord and v4l2-ctl should fail with -EBUSY.
> Same if either of arecord/v4l2-ctl is running, then DVB should fail with -EBUSY.
> 
> BTW, I won't be able to test anything myself until Feb 9th since I'm abroad and
> don't have access to my au0828.
> 

I am also on a business trip at the moment and won't have access to my
au0828 until Feb 8th.

I think I understand your concern and the change to get the desired 
behavior of allowing tuner to be shared by arecord and v4l2-ctl is
going to in the code that is already in the mainline which is the
au0828_enable_source().

If you would like to wait to pull this series for the problem to be 
fixed, I can send that change in. It will be another patch added to
the series.

Or if you pull this and I can send fix on top. Let me know your preference.

thanks,
-- Shuah


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v10 0/4] Media Device Allocator API
  2019-02-05 18:10               ` shuah
@ 2019-02-06  7:36                 ` Hans Verkuil
  0 siblings, 0 replies; 23+ messages in thread
From: Hans Verkuil @ 2019-02-06  7:36 UTC (permalink / raw)
  To: shuah, mchehab, perex, tiwai; +Cc: linux-media, linux-kernel, alsa-devel

On 2/5/19 7:10 PM, shuah wrote:
> On 2/1/19 2:21 AM, Hans Verkuil wrote:
>> On 2/1/19 1:46 AM, shuah wrote:
>>> Hi Hans,
>>>
>>> On 1/30/19 12:42 AM, Hans Verkuil wrote:
>>>> On 1/30/19 2:50 AM, shuah wrote:
>>>>> On 1/29/19 2:43 AM, Hans Verkuil wrote:
>>>>>> On 1/29/19 12:48 AM, shuah wrote:
>>>>>>> Hi Hans,
>>>>>>>
>>>>>>> On 1/28/19 5:03 AM, Hans Verkuil wrote:
>>>>>>>> Hi Shuah,
>>>>>>>>
>>>>>>>> On 1/24/19 9:32 PM, Shuah Khan wrote:
>>>>>>>>> Media Device Allocator API to allows multiple drivers share a media device.
>>>>>>>>> This API solves a very common use-case for media devices where one physical
>>>>>>>>> device (an USB stick) provides both audio and video. When such media device
>>>>>>>>> exposes a standard USB Audio class, a proprietary Video class, two or more
>>>>>>>>> independent drivers will share a single physical USB bridge. In such cases,
>>>>>>>>> it is necessary to coordinate access to the shared resource.
>>>>>>>>>
>>>>>>>>> Using this API, drivers can allocate a media device with the shared struct
>>>>>>>>> device as the key. Once the media device is allocated by a driver, other
>>>>>>>>> drivers can get a reference to it. The media device is released when all
>>>>>>>>> the references are released.
>>>>>>>>>
>>>>>>>>> - This patch series is tested on 5.0-rc3 and addresses comments on
>>>>>>>>>       v9 series from Hans Verkuil.
>>>>>>>>> - v9 was tested on 4.20-rc6.
>>>>>>>>> - Tested sharing resources with kaffeine, vlc, xawtv, tvtime, and
>>>>>>>>>       arecord. When analog is streaming, digital and audio user-space
>>>>>>>>>       applications detect that the tuner is busy and exit. When digital
>>>>>>>>>       is streaming, analog and audio applications detect that the tuner is
>>>>>>>>>       busy and exit. When arecord is owns the tuner, digital and analog
>>>>>>>>>       detect that the tuner is busy and exit.
>>>>>>>>
>>>>>>>> I've been doing some testing with my au0828, and I am confused about one
>>>>>>>> thing, probably because it has been too long ago since I last looked into
>>>>>>>> this in detail:
>>>>>>>>
>>>>>>>
>>>>>>> Great.
>>>>>>>
>>>>>>>> Why can't I change the tuner frequency if arecord (and only arecord) is
>>>>>>>> streaming audio? If arecord is streaming, then it is recording the audio
>>>>>>>> from the analog TV tuner, right? So changing the analog TV frequency
>>>>>>>> should be fine.
>>>>>>>>
>>>>>>>
>>>>>>> Changing analog TV frequency would be s_frequency. The way it works is
>>>>>>> any s_* calls would require holding the pipeline. In Analog TV case, it
>>>>>>> would mean holding both audio and video pipelines for any changes
>>>>>>> including TV.
>>>>>>>
>>>>>>> As I recall, we discussed this design and the decision was to make all
>>>>>>> s_* calls interfaces to hold the tuner. A special exception is g_tuner
>>>>>>> in case of au0828. au0828 initializes the tuner from s_* interfaces and
>>>>>>> its g_tuner interfaces. Allowing s_frequency to proceed will disrupt the
>>>>>>> arecord audio stream.
>>>>>>>
>>>>>>> Query (q_*) works just fine without holding the pipeline. I limited the
>>>>>>> analog holds to just the ones that are required. The current set is
>>>>>>> required to avoid audio stream disruptions.
>>>>>>
>>>>>> So I am not sure about that ('avoid audio stream disruptions'): if I
>>>>>> stream video AND use arecord, then I can just set the frequency while
>>>>>> streaming. Doesn't that interrupt audio as well? And are you sure changing
>>>>>> the tuner frequency actually disrupts audio? And if audio is disrupted,
>>>>>> are we talking about a glitch or is audio permanently disrupted?
>>>>>
>>>>> I think it is a glitch. I will run some tests and let you know.
>>>>>>
>>>>>> That's basically the inconsistent behavior I noticed: just running arecord
>>>>>> will prevent me from changing the frequency, but if I run arecord and stream
>>>>>> video, then it is suddenly OK to change the frequency.
>>>>>
>>>>> How are you changing frequency? I want to duplicate what you are doing.
>>>>
>>>> v4l2-ctl -f <freq>
>>>
>>> I am not seeing the inconsistent behavior. Here are my results.
>>>
>>> 1. Started acecord and while it is running:
>>>
>>> arecord -M -D plughw:2,0 -c2  -f S16_LE -t wav foo.wav
>>> Recording WAVE 'foo.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo
>>>
>>> 2. Ran v4l2-ctl -f as follows:
>>>
>>> v4l2-ctl -f 700
>>> VIDIOC_G_TUNER: failed: Device or resource busy
>>> VIDIOC_S_FREQUENCY: failed: Device or resource busy
>>>
>>> Based on the current implementation, it failed with resource
>>> busy as expected.
>>>
>>> 3. Started v4l2-ctl as follows:
>>>
>>>   v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video0
>>> VIDIOC_STREAMON: failed: Device or resource busy
>>
>> Why is this? You have one analog tuner and it delivers independent audio
>> and video streams. I should be able to start/stop audio and video independently.
>>
>> And as mentioned above, if I use v4l2-ctl for video streaming, then start arecord,
>> then that works fine. And I can change the tuner frequency while both are streaming.
>>
>> But doing this the other way around (first start arecord, then v4l2-ctl) then that
>> doesn't work.
>>
>> It makes no sense.
>>
>> Note that v4l2-ctl does not open audio, it solely deals with video. qv4l2 will
>> open both audio and video, but for testing audio and video independently you
>> need to use arecord/v4l2-ctl.
>>
>> In any case, my understanding of how this should work is that both arecord and
>> v4l2-ctl should attempt to lock the analog tuner resource, but they can share it.
>>
>> If DVB is using the tuner, then both arecord and v4l2-ctl should fail with -EBUSY.
>> Same if either of arecord/v4l2-ctl is running, then DVB should fail with -EBUSY.
>>
>> BTW, I won't be able to test anything myself until Feb 9th since I'm abroad and
>> don't have access to my au0828.
>>
> 
> I am also on a business trip at the moment and won't have access to my
> au0828 until Feb 8th.
> 
> I think I understand your concern and the change to get the desired behavior of allowing tuner to be shared by arecord and v4l2-ctl is
> going to in the code that is already in the mainline which is the
> au0828_enable_source().
> 
> If you would like to wait to pull this series for the problem to be fixed, I can send that change in. It will be another patch added to
> the series.
> 
> Or if you pull this and I can send fix on top. Let me know your preference.

I prefer to wait until I can test with the additional patch if that's OK?

Regards,

	Hans

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2019-02-06  7:36 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-24 20:32 [PATCH v10 0/4] Media Device Allocator API Shuah Khan
2019-01-24 20:32 ` [PATCH v10 1/4] media: " Shuah Khan
2019-01-25 15:38   ` Sakari Ailus
2019-01-26  0:27     ` shuah
2019-01-26  0:27       ` shuah
2019-01-24 20:32 ` [PATCH v10 2/4] media: change au0828 to use " Shuah Khan
2019-01-24 20:32 ` [PATCH v10 3/4] media: media.h: Enable ALSA MEDIA_INTF_T* interface types Shuah Khan
2019-01-24 20:32 ` [PATCH v10 4/4] sound/usb: Use Media Controller API to share media resources Shuah Khan
2019-01-25 15:28 ` [PATCH v10 0/4] Media Device Allocator API Sakari Ailus
2019-01-25 15:28   ` Sakari Ailus
2019-01-26  0:19   ` shuah
2019-01-26  0:19     ` shuah
2019-01-28 12:03 ` Hans Verkuil
2019-01-28 23:48   ` shuah
2019-01-29  9:43     ` Hans Verkuil
2019-01-30  1:50       ` shuah
2019-01-30  1:50         ` shuah
2019-01-30  7:42         ` Hans Verkuil
2019-01-30  7:42           ` Hans Verkuil
2019-02-01  0:46           ` shuah
2019-02-01  9:21             ` Hans Verkuil
2019-02-05 18:10               ` shuah
2019-02-06  7:36                 ` Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.