[libcamera-devel,v3,3/9] libcamera: media_device: Handle ancillary links in populateLinks()
diff mbox series

Message ID 20211207224512.753979-4-djrscally@gmail.com
State Superseded
Headers show
Series
  • Enumerate CameraLens by following sensor's ancillary links
Related show

Commit Message

Daniel Scally Dec. 7, 2021, 10:45 p.m. UTC
The populateLinks() function can't currently handle ancillary links
which causes an error to be thrown in process() when the MediaObject
cannot be cast to a MediaPad.

Add explicit handling for the different link types, creating either
pad-2-pad links or else storing the pointer to the ancillary device
MediaEntity in the ancillaryEntities_ member of the primary.

Signed-off-by: Daniel Scally <djrscally@gmail.com>
---
Changes in v3:

	- Split out the new macro
	- Fixed some style errors and comments
	- Added a default case

 src/libcamera/media_device.cpp | 55 ++++++++++++++++++++++++----------
 1 file changed, 39 insertions(+), 16 deletions(-)

Comments

Laurent Pinchart Dec. 8, 2021, 8:26 a.m. UTC | #1
Hi Dan,

Thank you for the patch.

On Tue, Dec 07, 2021 at 10:45:06PM +0000, Daniel Scally wrote:
> The populateLinks() function can't currently handle ancillary links
> which causes an error to be thrown in process() when the MediaObject
> cannot be cast to a MediaPad.
> 
> Add explicit handling for the different link types, creating either
> pad-2-pad links or else storing the pointer to the ancillary device
> MediaEntity in the ancillaryEntities_ member of the primary.
> 
> Signed-off-by: Daniel Scally <djrscally@gmail.com>
> ---
> Changes in v3:
> 
> 	- Split out the new macro
> 	- Fixed some style errors and comments
> 	- Added a default case
> 
>  src/libcamera/media_device.cpp | 55 ++++++++++++++++++++++++----------
>  1 file changed, 39 insertions(+), 16 deletions(-)

I'm afraid this patch now conflicts, could you please rebase it ?

> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
> index 4df0a27f..fb332445 100644
> --- a/src/libcamera/media_device.cpp
> +++ b/src/libcamera/media_device.cpp
> @@ -693,45 +693,68 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
>  {
>  	struct media_v2_link *mediaLinks = reinterpret_cast<struct media_v2_link *>
>  					   (topology.ptr_links);
> +	MediaEntity *ancillary;
> +	MediaEntity *primary;
> +	MediaLink *link;
>  
>  	for (unsigned int i = 0; i < topology.num_links; ++i) {
>  		/*
> -		 * Skip links between entities and interfaces: we only care
> -		 * about pad-2-pad links here.
> +		 * Skip links between entities and interfaces: interfaces are
> +		 * not created as MediaObjects at this time, so the source and
> +		 * sink pointers would never be found.
>  		 */
>  		if ((mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
>  		    MEDIA_LNK_FL_INTERFACE_LINK)
>  			continue;
>  
> -		/* Store references to source and sink pads in the link. */
> +		/* Look up the source and sink objects. */
>  		unsigned int source_id = mediaLinks[i].source_id;
> -		MediaPad *source = dynamic_cast<MediaPad *>
> -				   (object(source_id));
> +		MediaObject *source = object(source_id);
>  		if (!source) {
>  			LOG(MediaDevice, Error)
> -				<< "Failed to find pad with id: "
> +				<< "Failed to find MediaObject with id: "
>  				<< source_id;
>  			return false;
>  		}
>  
>  		unsigned int sink_id = mediaLinks[i].sink_id;
> -		MediaPad *sink = dynamic_cast<MediaPad *>
> -				 (object(sink_id));
> +		MediaObject *sink = object(sink_id);
>  		if (!sink) {
>  			LOG(MediaDevice, Error)
> -				<< "Failed to find pad with id: "
> +				<< "Failed to find MediaObject with id: "
>  				<< sink_id;
>  			return false;
>  		}
>  
> -		MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
> -		if (!addObject(link)) {
> -			delete link;
> -			return false;
> -		}
> +		switch (mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) {
> +		case MEDIA_LNK_FL_DATA_LINK:
> +			link = new MediaLink(&mediaLinks[i],
> +					     dynamic_cast<MediaPad *>(source),
> +					     dynamic_cast<MediaPad *>(sink));

We'll crash if the source or sink isn't a pad (dynamic_cast will return
nullptr in that case). This shouldn't happen unless the kernel reports
an incorrect topology, but it would still be nice to protect against
that. How about the following (untested) ?

		case MEDIA_LNK_FL_DATA_LINK: {
			MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
			if (!sourcePad) {
				LOG(MediaDevice, Error)
					<< "Source MediaObject " << source_id
					<< " is not a pad";
				return false;
			}

			MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
			if (!sinkPad) {
				LOG(MediaDevice, Error)
					<< "Sink MediaObject " << sink_id
					<< " is not a pad";
				return false;
			}

			MediaLink *link = new MediaLink(&mediaLinks[i],
							sourcePad, sinkPad);
			if (!addObject(link)) {
				delete link;
				return false;
			}

			link->source()->addLink(link);
			link->sink()->addLink(link);

			break;
		}

		case MEDIA_LNK_FL_ANCILLARY_LINK: {
			MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
			if (!primary) {
				LOG(MediaDevice, Error)
					<< "Source MediaObject " << source_id
					<< " is not an entity";
				return false;
			}

			MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
			if (!ancillary) {
				LOG(MediaDevice, Error)
					<< "Sink MediaObject " << sink_id
					<< " is not an entity";
				return false;
			}

			primary->addAncillaryEntity(ancillary);
			break;
		}

Or is it overkill ?

> +			if (!addObject(link)) {
> +				delete link;
> +				return false;
> +			}
> +
> +			link->source()->addLink(link);
> +			link->sink()->addLink(link);
> +
> +			break;
> +
> +		case MEDIA_LNK_FL_ANCILLARY_LINK:
> +			primary = dynamic_cast<MediaEntity *>(source);
> +			ancillary = dynamic_cast<MediaEntity *>(sink);
>  
> -		source->addLink(link);
> -		sink->addLink(link);
> +			primary->addAncillaryEntity(ancillary);
> +
> +			break;
> +
> +		default:
> +			LOG(MediaDevice, Warning)
> +				<< "Unknown media link type";
> +
> +			break;
> +		}
>  	}
>  
>  	return true;
Daniel Scally Dec. 8, 2021, 10:10 p.m. UTC | #2
Hi Laurent

On 08/12/2021 08:26, Laurent Pinchart wrote:
> Hi Dan,
> 
> Thank you for the patch.
> 
> On Tue, Dec 07, 2021 at 10:45:06PM +0000, Daniel Scally wrote:
>> The populateLinks() function can't currently handle ancillary links
>> which causes an error to be thrown in process() when the MediaObject
>> cannot be cast to a MediaPad.
>>
>> Add explicit handling for the different link types, creating either
>> pad-2-pad links or else storing the pointer to the ancillary device
>> MediaEntity in the ancillaryEntities_ member of the primary.
>>
>> Signed-off-by: Daniel Scally <djrscally@gmail.com>
>> ---
>> Changes in v3:
>>
>> 	- Split out the new macro
>> 	- Fixed some style errors and comments
>> 	- Added a default case
>>
>>  src/libcamera/media_device.cpp | 55 ++++++++++++++++++++++++----------
>>  1 file changed, 39 insertions(+), 16 deletions(-)
> 
> I'm afraid this patch now conflicts, could you please rebase it ?
> 
>> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
>> index 4df0a27f..fb332445 100644
>> --- a/src/libcamera/media_device.cpp
>> +++ b/src/libcamera/media_device.cpp
>> @@ -693,45 +693,68 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
>>  {
>>  	struct media_v2_link *mediaLinks = reinterpret_cast<struct media_v2_link *>
>>  					   (topology.ptr_links);
>> +	MediaEntity *ancillary;
>> +	MediaEntity *primary;
>> +	MediaLink *link;
>>  
>>  	for (unsigned int i = 0; i < topology.num_links; ++i) {
>>  		/*
>> -		 * Skip links between entities and interfaces: we only care
>> -		 * about pad-2-pad links here.
>> +		 * Skip links between entities and interfaces: interfaces are
>> +		 * not created as MediaObjects at this time, so the source and
>> +		 * sink pointers would never be found.
>>  		 */
>>  		if ((mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
>>  		    MEDIA_LNK_FL_INTERFACE_LINK)
>>  			continue;
>>  
>> -		/* Store references to source and sink pads in the link. */
>> +		/* Look up the source and sink objects. */
>>  		unsigned int source_id = mediaLinks[i].source_id;
>> -		MediaPad *source = dynamic_cast<MediaPad *>
>> -				   (object(source_id));
>> +		MediaObject *source = object(source_id);
>>  		if (!source) {
>>  			LOG(MediaDevice, Error)
>> -				<< "Failed to find pad with id: "
>> +				<< "Failed to find MediaObject with id: "
>>  				<< source_id;
>>  			return false;
>>  		}
>>  
>>  		unsigned int sink_id = mediaLinks[i].sink_id;
>> -		MediaPad *sink = dynamic_cast<MediaPad *>
>> -				 (object(sink_id));
>> +		MediaObject *sink = object(sink_id);
>>  		if (!sink) {
>>  			LOG(MediaDevice, Error)
>> -				<< "Failed to find pad with id: "
>> +				<< "Failed to find MediaObject with id: "
>>  				<< sink_id;
>>  			return false;
>>  		}
>>  
>> -		MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
>> -		if (!addObject(link)) {
>> -			delete link;
>> -			return false;
>> -		}
>> +		switch (mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) {
>> +		case MEDIA_LNK_FL_DATA_LINK:
>> +			link = new MediaLink(&mediaLinks[i],
>> +					     dynamic_cast<MediaPad *>(source),
>> +					     dynamic_cast<MediaPad *>(sink));
> 
> We'll crash if the source or sink isn't a pad (dynamic_cast will return
> nullptr in that case). This shouldn't happen unless the kernel reports
> an incorrect topology, but it would still be nice to protect against
> that. How about the following (untested) ?
> 
> 		case MEDIA_LNK_FL_DATA_LINK: {
> 			MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
> 			if (!sourcePad) {
> 				LOG(MediaDevice, Error)
> 					<< "Source MediaObject " << source_id
> 					<< " is not a pad";
> 				return false;
> 			}
> 
> 			MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
> 			if (!sinkPad) {
> 				LOG(MediaDevice, Error)
> 					<< "Sink MediaObject " << sink_id
> 					<< " is not a pad";
> 				return false;
> 			}
> 
> 			MediaLink *link = new MediaLink(&mediaLinks[i],
> 							sourcePad, sinkPad);
> 			if (!addObject(link)) {
> 				delete link;
> 				return false;
> 			}
> 
> 			link->source()->addLink(link);
> 			link->sink()->addLink(link);
> 
> 			break;
> 		}
> 
> 		case MEDIA_LNK_FL_ANCILLARY_LINK: {
> 			MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
> 			if (!primary) {
> 				LOG(MediaDevice, Error)
> 					<< "Source MediaObject " << source_id
> 					<< " is not an entity";
> 				return false;
> 			}
> 
> 			MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
> 			if (!ancillary) {
> 				LOG(MediaDevice, Error)
> 					<< "Sink MediaObject " << sink_id
> 					<< " is not an entity";
> 				return false;
> 			}
> 
> 			primary->addAncillaryEntity(ancillary);
> 			break;
> 		}
> 
> Or is it overkill ?

I lean towards overkill to be honest; since creating data links on the
kernel side is through media_create_pad_link(), which explicitly sets
the source and sink to pads. So someone would have to invent a new
function to add the link in a way that would be broken.

Happy to do it though if you prefer.

>> +			if (!addObject(link)) {
>> +				delete link;
>> +				return false;
>> +			}
>> +
>> +			link->source()->addLink(link);
>> +			link->sink()->addLink(link);
>> +
>> +			break;
>> +
>> +		case MEDIA_LNK_FL_ANCILLARY_LINK:
>> +			primary = dynamic_cast<MediaEntity *>(source);
>> +			ancillary = dynamic_cast<MediaEntity *>(sink);
>>  
>> -		source->addLink(link);
>> -		sink->addLink(link);
>> +			primary->addAncillaryEntity(ancillary);
>> +
>> +			break;
>> +
>> +		default:
>> +			LOG(MediaDevice, Warning)
>> +				<< "Unknown media link type";
>> +
>> +			break;
>> +		}
>>  	}
>>  
>>  	return true;
>
Laurent Pinchart Dec. 10, 2021, 12:59 a.m. UTC | #3
Hi Dan,

On Wed, Dec 08, 2021 at 10:10:08PM +0000, Daniel Scally wrote:
> On 08/12/2021 08:26, Laurent Pinchart wrote:
> > On Tue, Dec 07, 2021 at 10:45:06PM +0000, Daniel Scally wrote:
> >> The populateLinks() function can't currently handle ancillary links
> >> which causes an error to be thrown in process() when the MediaObject
> >> cannot be cast to a MediaPad.
> >>
> >> Add explicit handling for the different link types, creating either
> >> pad-2-pad links or else storing the pointer to the ancillary device
> >> MediaEntity in the ancillaryEntities_ member of the primary.
> >>
> >> Signed-off-by: Daniel Scally <djrscally@gmail.com>
> >> ---
> >> Changes in v3:
> >>
> >> 	- Split out the new macro
> >> 	- Fixed some style errors and comments
> >> 	- Added a default case
> >>
> >>  src/libcamera/media_device.cpp | 55 ++++++++++++++++++++++++----------
> >>  1 file changed, 39 insertions(+), 16 deletions(-)
> > 
> > I'm afraid this patch now conflicts, could you please rebase it ?
> > 
> >> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
> >> index 4df0a27f..fb332445 100644
> >> --- a/src/libcamera/media_device.cpp
> >> +++ b/src/libcamera/media_device.cpp
> >> @@ -693,45 +693,68 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
> >>  {
> >>  	struct media_v2_link *mediaLinks = reinterpret_cast<struct media_v2_link *>
> >>  					   (topology.ptr_links);
> >> +	MediaEntity *ancillary;
> >> +	MediaEntity *primary;
> >> +	MediaLink *link;
> >>  
> >>  	for (unsigned int i = 0; i < topology.num_links; ++i) {
> >>  		/*
> >> -		 * Skip links between entities and interfaces: we only care
> >> -		 * about pad-2-pad links here.
> >> +		 * Skip links between entities and interfaces: interfaces are
> >> +		 * not created as MediaObjects at this time, so the source and
> >> +		 * sink pointers would never be found.
> >>  		 */
> >>  		if ((mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
> >>  		    MEDIA_LNK_FL_INTERFACE_LINK)
> >>  			continue;
> >>  
> >> -		/* Store references to source and sink pads in the link. */
> >> +		/* Look up the source and sink objects. */
> >>  		unsigned int source_id = mediaLinks[i].source_id;
> >> -		MediaPad *source = dynamic_cast<MediaPad *>
> >> -				   (object(source_id));
> >> +		MediaObject *source = object(source_id);
> >>  		if (!source) {
> >>  			LOG(MediaDevice, Error)
> >> -				<< "Failed to find pad with id: "
> >> +				<< "Failed to find MediaObject with id: "
> >>  				<< source_id;
> >>  			return false;
> >>  		}
> >>  
> >>  		unsigned int sink_id = mediaLinks[i].sink_id;
> >> -		MediaPad *sink = dynamic_cast<MediaPad *>
> >> -				 (object(sink_id));
> >> +		MediaObject *sink = object(sink_id);
> >>  		if (!sink) {
> >>  			LOG(MediaDevice, Error)
> >> -				<< "Failed to find pad with id: "
> >> +				<< "Failed to find MediaObject with id: "
> >>  				<< sink_id;
> >>  			return false;
> >>  		}
> >>  
> >> -		MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
> >> -		if (!addObject(link)) {
> >> -			delete link;
> >> -			return false;
> >> -		}
> >> +		switch (mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) {
> >> +		case MEDIA_LNK_FL_DATA_LINK:
> >> +			link = new MediaLink(&mediaLinks[i],
> >> +					     dynamic_cast<MediaPad *>(source),
> >> +					     dynamic_cast<MediaPad *>(sink));
> > 
> > We'll crash if the source or sink isn't a pad (dynamic_cast will return
> > nullptr in that case). This shouldn't happen unless the kernel reports
> > an incorrect topology, but it would still be nice to protect against
> > that. How about the following (untested) ?
> > 
> > 		case MEDIA_LNK_FL_DATA_LINK: {
> > 			MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
> > 			if (!sourcePad) {
> > 				LOG(MediaDevice, Error)
> > 					<< "Source MediaObject " << source_id
> > 					<< " is not a pad";
> > 				return false;
> > 			}
> > 
> > 			MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
> > 			if (!sinkPad) {
> > 				LOG(MediaDevice, Error)
> > 					<< "Sink MediaObject " << sink_id
> > 					<< " is not a pad";
> > 				return false;
> > 			}
> > 
> > 			MediaLink *link = new MediaLink(&mediaLinks[i],
> > 							sourcePad, sinkPad);
> > 			if (!addObject(link)) {
> > 				delete link;
> > 				return false;
> > 			}
> > 
> > 			link->source()->addLink(link);
> > 			link->sink()->addLink(link);
> > 
> > 			break;
> > 		}
> > 
> > 		case MEDIA_LNK_FL_ANCILLARY_LINK: {
> > 			MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
> > 			if (!primary) {
> > 				LOG(MediaDevice, Error)
> > 					<< "Source MediaObject " << source_id
> > 					<< " is not an entity";
> > 				return false;
> > 			}
> > 
> > 			MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
> > 			if (!ancillary) {
> > 				LOG(MediaDevice, Error)
> > 					<< "Sink MediaObject " << sink_id
> > 					<< " is not an entity";
> > 				return false;
> > 			}
> > 
> > 			primary->addAncillaryEntity(ancillary);
> > 			break;
> > 		}
> > 
> > Or is it overkill ?
> 
> I lean towards overkill to be honest; since creating data links on the
> kernel side is through media_create_pad_link(), which explicitly sets
> the source and sink to pads. So someone would have to invent a new
> function to add the link in a way that would be broken.
> 
> Happy to do it though if you prefer.

I agree that having detailed messages is overkill, but I'd like to at
least avoid crashing in case something goes wrong (during kernel
development for instance). Maybe the following ?

 		case MEDIA_LNK_FL_DATA_LINK: {
 			MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
 			MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
 			if (!sourcePad || !sinkPad) {
 				LOG(MediaDevice, Error)
 					<< "Source or sink is not a pad";
 				return false;
 			}
 
 			MediaLink *link = new MediaLink(&mediaLinks[i],
 							sourcePad, sinkPad);
 			if (!addObject(link)) {
 				delete link;
 				return false;
 			}
 
 			link->source()->addLink(link);
 			link->sink()->addLink(link);
 
 			break;
 		}
 
 		case MEDIA_LNK_FL_ANCILLARY_LINK: {
 			MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
 			MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
 			if (!primary || !ancillary) {
 				LOG(MediaDevice, Error)
 					<< "Source or sink is not an entity";
 				return false;
 			}
 
 			primary->addAncillaryEntity(ancillary);
 			break;
 		}

> >> +			if (!addObject(link)) {
> >> +				delete link;
> >> +				return false;
> >> +			}
> >> +
> >> +			link->source()->addLink(link);
> >> +			link->sink()->addLink(link);
> >> +
> >> +			break;
> >> +
> >> +		case MEDIA_LNK_FL_ANCILLARY_LINK:
> >> +			primary = dynamic_cast<MediaEntity *>(source);
> >> +			ancillary = dynamic_cast<MediaEntity *>(sink);
> >>  
> >> -		source->addLink(link);
> >> -		sink->addLink(link);
> >> +			primary->addAncillaryEntity(ancillary);
> >> +
> >> +			break;
> >> +
> >> +		default:
> >> +			LOG(MediaDevice, Warning)
> >> +				<< "Unknown media link type";
> >> +
> >> +			break;
> >> +		}
> >>  	}
> >>  
> >>  	return true;

Patch
diff mbox series

diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
index 4df0a27f..fb332445 100644
--- a/src/libcamera/media_device.cpp
+++ b/src/libcamera/media_device.cpp
@@ -693,45 +693,68 @@  bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
 {
 	struct media_v2_link *mediaLinks = reinterpret_cast<struct media_v2_link *>
 					   (topology.ptr_links);
+	MediaEntity *ancillary;
+	MediaEntity *primary;
+	MediaLink *link;
 
 	for (unsigned int i = 0; i < topology.num_links; ++i) {
 		/*
-		 * Skip links between entities and interfaces: we only care
-		 * about pad-2-pad links here.
+		 * Skip links between entities and interfaces: interfaces are
+		 * not created as MediaObjects at this time, so the source and
+		 * sink pointers would never be found.
 		 */
 		if ((mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
 		    MEDIA_LNK_FL_INTERFACE_LINK)
 			continue;
 
-		/* Store references to source and sink pads in the link. */
+		/* Look up the source and sink objects. */
 		unsigned int source_id = mediaLinks[i].source_id;
-		MediaPad *source = dynamic_cast<MediaPad *>
-				   (object(source_id));
+		MediaObject *source = object(source_id);
 		if (!source) {
 			LOG(MediaDevice, Error)
-				<< "Failed to find pad with id: "
+				<< "Failed to find MediaObject with id: "
 				<< source_id;
 			return false;
 		}
 
 		unsigned int sink_id = mediaLinks[i].sink_id;
-		MediaPad *sink = dynamic_cast<MediaPad *>
-				 (object(sink_id));
+		MediaObject *sink = object(sink_id);
 		if (!sink) {
 			LOG(MediaDevice, Error)
-				<< "Failed to find pad with id: "
+				<< "Failed to find MediaObject with id: "
 				<< sink_id;
 			return false;
 		}
 
-		MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
-		if (!addObject(link)) {
-			delete link;
-			return false;
-		}
+		switch (mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) {
+		case MEDIA_LNK_FL_DATA_LINK:
+			link = new MediaLink(&mediaLinks[i],
+					     dynamic_cast<MediaPad *>(source),
+					     dynamic_cast<MediaPad *>(sink));
+			if (!addObject(link)) {
+				delete link;
+				return false;
+			}
+
+			link->source()->addLink(link);
+			link->sink()->addLink(link);
+
+			break;
+
+		case MEDIA_LNK_FL_ANCILLARY_LINK:
+			primary = dynamic_cast<MediaEntity *>(source);
+			ancillary = dynamic_cast<MediaEntity *>(sink);
 
-		source->addLink(link);
-		sink->addLink(link);
+			primary->addAncillaryEntity(ancillary);
+
+			break;
+
+		default:
+			LOG(MediaDevice, Warning)
+				<< "Unknown media link type";
+
+			break;
+		}
 	}
 
 	return true;