// Print information regarding a stream
        static void PrintStreamInfo(DiscovererStreamInfo info, int depth)
        {
            var caps = info.Caps;

            string desc = null;

            if (caps != null)
            {
                if (caps.IsFixed)
                {
                    desc = Gst.PbUtils.Global.PbUtilsGetCodecDescription(caps);
                }
                else
                {
                    desc = caps.ToString();
                }
            }

            Console.WriteLine("{0}{1}: {2}", new string (' ', 2 * depth), info.StreamTypeNick, (desc != null ? desc : ""));

            var tags = info.Tags;

            if (tags != null)
            {
                Console.WriteLine("{0}Tags:", new string (' ', 2 * (depth + 1)));
                tags.Foreach((TagForeachFunc) delegate(TagList list, string tag) {
                    PrintTagForeach(list, tag, depth + 2);
                });
            }
        }
        /// <summary>
        /// Print information regarding a stream and its substreams, if any
        /// </summary>
        static void PrintTopology(DiscovererStreamInfo info, int depth)
        {
            if (info == null)
            {
                return;
            }
            PrintStreamInfo(info, depth);
            DiscovererStreamInfo next = info.Next;

            if (next != null)
            {
                PrintTopology(next, depth + 1);
                next.Dispose();
            }
            else if (info is DiscovererContainerInfo)
            {
                var streams = ((DiscovererContainerInfo)info).Streams;
                foreach (var stream in streams)
                {
                    PrintTopology(stream, depth + 1);
                }
            }
        }
        /// <summary>
        /// This function is called every time the discoverer has information regarding one of the URIs we provided.
        /// </summary>
        static void OnDiscoveredCb(object o, DiscoveredArgs args)
        {
            var discoverer = o as Discoverer;
            var info       = args.Info;
            var uri        = info.Uri;
            var result     = info.Result;

            switch (result)
            {
            case DiscovererResult.UriInvalid:
                $"Invalid uri {uri}".PrintErr();
                break;

            case DiscovererResult.Error:
                var err = new GLib.GException(args.Error);
                $"Discoverer error {err.Message}".PrintErr();
                break;

            case DiscovererResult.Timeout:
                Console.WriteLine("Timeout");
                break;

            case DiscovererResult.Busy:
                Console.WriteLine("Busy");
                break;

            case DiscovererResult.MissingPlugins:
                var s = info.Misc;
                if (s != null)
                {
                    Console.WriteLine($"Missing plugins {s}");
                }
                break;

            case DiscovererResult.Ok:
                Console.WriteLine($"Discovered {uri}");
                break;
            }
            if (result != DiscovererResult.Ok)
            {
                "This URI cannot be played".PrintErr();
                return;
            }

            // If we got no error, show the retrieved information
            var duration = new TimeSpan((long)info.Duration);

            Console.WriteLine($"Duration {duration}");

            var tags = info.Tags;

            if (tags != null)
            {
                Console.WriteLine("Tags: ");
                tags.Foreach(PrintTagForeach);
            }

            Console.WriteLine("Seekable: {0}", info.Seekable ? "yes" : "no");
            DiscovererStreamInfo sinfo = info.StreamInfo;

            if (sinfo == null)
            {
                return;
            }
            Console.WriteLine("Stream information: ");
            PrintTopology(sinfo, 1);
            Console.WriteLine();
        }