Skip to content

WebGear_RTC API References

WebGear_RTC API usage examples can be found here âž¶

WebGear_RTC API parameters are explained here âž¶

WebGear_RTC

WebGear_RTC is similar to WeGear API in many aspects but utilizes WebRTC technology under the hood instead of Motion JPEG, which makes it suitable for building powerful video-streaming solutions for all modern browsers as well as native clients available on all major platforms.

WebGear_RTC is implemented with the help of aiortc library which is built on top of asynchronous I/O framework for Web Real-Time Communication (WebRTC) and Object Real-Time Communication (ORTC) and supports many features like SDP generation/parsing, Interactive Connectivity Establishment with half-trickle and mDNS support, DTLS key and certificate generation, DTLS handshake, etc.

WebGear_RTC can handle multiple consumers seamlessly and provides native support for ICE (Interactive Connectivity Establishment) protocol, STUN (Session Traversal Utilities for NAT), and TURN (Traversal Using Relays around NAT) servers that help us to easily establish direct media connection with the remote peers for uninterrupted data flow. It also allows us to define our custom Server as a source to transform frames easily before sending them across the network(see this doc example).

WebGear_RTC API works in conjunction with Starlette ASGI application and can also flexibly interact with Starlette's ecosystem of shared middleware, mountable applications, Response classes, Routing tables, Static Files, Templating engine(with Jinja2), etc.

Additionally, WebGear_RTC API also provides internal wrapper around VideoGear, which itself provides internal access to both CamGear and PiGear APIs.

Source code in vidgear/gears/asyncio/webgear_rtc.py
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
class WebGear_RTC:
    """
    WebGear_RTC is similar to WeGear API in many aspects but utilizes WebRTC technology under the hood instead of Motion JPEG, which
    makes it suitable for building powerful video-streaming solutions for all modern browsers as well as native clients available on
    all major platforms.

    WebGear_RTC is implemented with the help of aiortc library which is built on top of asynchronous I/O framework for Web Real-Time
    Communication (WebRTC) and Object Real-Time Communication (ORTC) and supports many features like SDP generation/parsing, Interactive
    Connectivity Establishment with half-trickle and mDNS support, DTLS key and certificate generation, DTLS handshake, etc.

    WebGear_RTC can handle multiple consumers seamlessly and provides native support for ICE (Interactive Connectivity Establishment)
    protocol, STUN (Session Traversal Utilities for NAT), and TURN (Traversal Using Relays around NAT) servers that help us to easily
    establish direct media connection with the remote peers for uninterrupted data flow. It also allows us to define our custom Server
    as a source to transform frames easily before sending them across the network(see this doc example).

    WebGear_RTC API works in conjunction with Starlette ASGI application and can also flexibly interact with Starlette's ecosystem of
    shared middleware, mountable applications, Response classes, Routing tables, Static Files, Templating engine(with Jinja2), etc.

    Additionally, WebGear_RTC API also provides internal wrapper around VideoGear, which itself provides internal access to both
    CamGear and PiGear APIs.
    """

    def __init__(
        self,
        # VideoGear parameters
        api: Backend = Backend.CAMGEAR,
        stabilize: bool = False,
        # PiGear parameters
        camera_num: int = 0,
        resolution: tuple[int, int] = (640, 480),
        framerate: int | float = 25,
        # CamGear/FFGear parameters
        source: Any = None,
        stream_mode: bool = False,
        backend: int = 0,
        # FFGear parameters
        source_demuxer: str | None = None,
        frame_format: str = "bgr24",
        custom_ffmpeg: str = "",
        # common parameters
        colorspace: str | None = None,
        logging: bool = False,
        time_delay: int = 0,
        # deprecated
        enablePiCamera: bool | None = None,
        **options: dict
    ):
        """
        This constructor method initializes the object state and attributes of the WebGear_RTC class.

        Parameters:
            api (Backend): selects the capture backend. Accepted values are `Backend.CAMGEAR` _(default)_,
                `Backend.PIGEAR`, and `Backend.FFGEAR`. Raises `TypeError` if an invalid value is given.
            stabilize (bool): enable access to Stabilizer Class for stabilizing frames.
            camera_num (int): [PiGear only] selects the camera module index. Must be `>= 0`.
            resolution (tuple): [PiGear only] sets `(width, height)` of the source. Default: `(640, 480)`.
            framerate (int/float): [PiGear only] sets the framerate of the source. Default: `25`.
            source (Any): [CamGear/FFGear] defines the source for the input stream (device index,
                filepath, network URL, or image-sequence glob). Default: `None`.
            stream_mode (bool): [CamGear/FFGear] enables Stream-Mode for `yt_dlp`-backed streaming URLs.
            backend (int): [CamGear only] selects the OpenCV VideoCapture backend (e.g. `cv2.CAP_DSHOW`).
            source_demuxer (str): [FFGear only] specifies the FFmpeg demuxer for the source
                (e.g. `"v4l2"`, `"dshow"`, `"avfoundation"`). Default: `None` (auto-detect).
            frame_format (str): [FFGear only] specifies the pixel layout for decoded frames
                (any FFmpeg-supported pix_fmt, e.g. `"bgr24"`, `"gray"`, `"yuv420p"`). Default: `"bgr24"`.
            custom_ffmpeg (str): [FFGear only] path to a custom FFmpeg executable. Default: `""` (use PATH).
            colorspace (str): [CamGear/PiGear only] selects the colorspace of the input stream.
            logging (bool): enables/disables logging. Default: `False`.
            time_delay (int): [CamGear/PiGear only] time delay (in seconds) before reading frames.
            enablePiCamera (bool): **DEPRECATED** — use `api=Backend.PIGEAR` instead. Will be removed
                in a future release.
            options (dict): additional tweak parameters forwarded to the selected backend gear
                and/or WebGear_RTC and the Stabilizer class.
        """
        # enable logging if specified
        self.__logging = logging if isinstance(logging, bool) else False

        # print current version
        logcurr_vidgear_ver(logging=self.__logging)

        # handle deprecated `enablePiCamera`
        if enablePiCamera is not None:
            warnings.warn(
                "`enablePiCamera` is deprecated in WebGear_RTC; use `api=Backend.PIGEAR` instead.",
                DeprecationWarning,
                stacklevel=2,
            )
            api = Backend.PIGEAR if enablePiCamera else Backend.CAMGEAR

        # raise error(s) for critical Class imports
        import_dependency_safe("starlette" if starlette is None else "")
        import_dependency_safe("aiortc" if aiortc is None else "")

        # initialize global params
        custom_data_location = ""  # path to save data-files to custom location
        data_path = ""  # path to WebGear_RTC data-files
        overwrite_default = False
        self.__relay = None  # act as broadcaster

        # reformat dictionary
        options = {str(k).strip(): v for k, v in options.items()}

        # assign values to global variables if specified and valid
        if options:
            if "custom_data_location" in options:
                value = options["custom_data_location"]
                if isinstance(value, str):
                    assert os.access(
                        value, os.W_OK
                    ), "[WebGear_RTC:ERROR] :: Permission Denied!, cannot write WebGear_RTC data-files to '{}' directory!".format(
                        value
                    )
                    assert os.path.isdir(
                        os.path.abspath(value)
                    ), "[WebGear_RTC:ERROR] :: `custom_data_location` value must be the path to a directory and not to a file!"
                    custom_data_location = os.path.abspath(value)
                else:
                    logger.warning("Skipped invalid `custom_data_location` value!")
                del options["custom_data_location"]  # clean

            if "overwrite_default_files" in options:
                value = options["overwrite_default_files"]
                if isinstance(value, bool):
                    overwrite_default = value
                else:
                    logger.warning("Skipped invalid `overwrite_default_files` value!")
                del options["overwrite_default_files"]  # clean

            if "enable_live_broadcast" in options:
                value = options["enable_live_broadcast"]
                if isinstance(value, bool):
                    if value:
                        self.__relay = MediaRelay()
                        options["enable_infinite_frames"] = (
                            True  # enforce infinite frames
                        )
                        logger.critical(
                            "Enabled live broadcasting for Peer connection(s)."
                        )
                    else:
                        pass
                else:
                    logger.warning("Skipped invalid `enable_live_broadcast` value!")
                del options["enable_live_broadcast"]  # clean

        # check if custom certificates path is specified
        if custom_data_location:
            data_path = generate_webdata(
                custom_data_location,
                c_name="webgear_rtc",
                overwrite_default=overwrite_default,
                logging=logging,
            )
        else:
            # otherwise generate suitable path
            data_path = generate_webdata(
                os.path.join(expanduser("~"), ".vidgear"),
                c_name="webgear_rtc",
                overwrite_default=overwrite_default,
                logging=logging,
            )

        # log it
        self.__logging and logger.debug(
            "`{}` is the default location for saving WebGear_RTC data-files.".format(
                data_path
            )
        )

        # define Jinja2 templates handler
        self.__templates = Jinja2Templates(directory="{}/templates".format(data_path))

        # define custom exception handlers
        self.__exception_handlers = {404: self.__not_found, 500: self.__server_error}
        # define routing tables
        self.routes = [
            Route("/", endpoint=self.__homepage),
            Route("/offer", self.__offer, methods=["GET", "POST"]),
            Mount(
                "/static",
                app=StaticFiles(directory="{}/static".format(data_path)),
                name="static",
            ),
        ]

        # define middleware support
        self.middleware = []

        # Handle RTC video server
        if "custom_stream" in options or source is not None:
            # Handle video source
            self.__default_rtc_server = RTC_VideoServer(
                api=api,
                stabilize=stabilize,
                source=source,
                camera_num=camera_num,
                stream_mode=stream_mode,
                backend=backend,
                source_demuxer=source_demuxer,
                frame_format=frame_format,
                custom_ffmpeg=custom_ffmpeg,
                colorspace=colorspace,
                resolution=resolution,
                framerate=framerate,
                logging=logging,
                time_delay=time_delay,
                **options
            )
            # add exclusive reset connection node
            self.routes.append(
                Route("/close_connection", self.__reset_connections, methods=["POST"])
            )
        else:
            raise ValueError(
                "[WebGear_RTC:ERROR] :: Source cannot be NoneType without Custom Stream(`custom_stream`) defined!"
            )

        # copying original routing tables for further validation
        self.__rt_org_copy = self.routes[:]
        # collects peer RTC connections
        self.__pcs = set()

    def __call__(self) -> Starlette:
        """
        Implements a custom Callable method for WebGear_RTC application.
        """
        # validate routing tables
        assert self.routes is not None, "Routing tables are NoneType!"
        if not isinstance(self.routes, list) or not all(
            x in self.routes for x in self.__rt_org_copy
        ):
            raise RuntimeError("[WebGear_RTC:ERROR] :: Routing tables are not valid!")

        # validate middlewares
        assert self.middleware is not None, "Middlewares are NoneType!"
        if self.middleware and (
            not isinstance(self.middleware, list)
            or not all(isinstance(x, Middleware) for x in self.middleware)
        ):
            raise RuntimeError("[WebGear_RTC:ERROR] :: Middlewares are not valid!")

        # return Starlette application
        self.__logging and logger.debug("Running Starlette application.")
        return Starlette(
            debug=(bool(self.__logging)),
            routes=self.routes,
            middleware=self.middleware,
            exception_handlers=self.__exception_handlers,
            lifespan=self.__lifespan,
        )

    async def __offer(self, request):
        """
        Generates JSON Response with a WebRTC Peer Connection of Video Server.
        """
        # get offer from params
        params = await request.json()
        offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])

        # initiate stream
        if self.__default_rtc_server is not None and not (
            self.__default_rtc_server.is_launched
        ):
            self.__logging and logger.debug("Initiating Video Streaming.")
            self.__default_rtc_server.launch()

        # setup RTC peer connection - interface represents a WebRTC connection
        # between the local computer and a remote peer.
        pc = RTCPeerConnection()
        self.__pcs.add(pc)
        self.__logging and logger.info("Created WebRTC Peer Connection.")

        # track ICE connection state changes
        @pc.on("iceconnectionstatechange")
        async def on_iceconnectionstatechange():
            if pc.iceConnectionState == "failed":
                logger.error("ICE connection state failed.")
                # check if Live Broadcasting is enabled
                if self.__relay is None:
                    # if not, close connection.
                    await pc.close()
                    self.__pcs.discard(pc)
            else:
                logger.debug("ICE connection state is {}".format(pc.iceConnectionState))

        # Change the remote description associated with the connection.
        await pc.setRemoteDescription(offer)
        # retrieve list of RTCRtpTransceiver objects that are currently attached to the connection
        for t in pc.getTransceivers():
            # Increments performance significantly, IDK why this works as H265 codec is not even supported :D
            capabilities = RTCRtpSender.getCapabilities("video")
            preferences = list(filter(lambda x: x.name == "H265", capabilities.codecs))
            t.setCodecPreferences(preferences)
            # add video server to peer track
            if t.kind == "video":
                pc.addTrack(
                    self.__relay.subscribe(self.__default_rtc_server)
                    if self.__relay is not None
                    else self.__default_rtc_server
                )

        # Create an SDP answer to an offer received from a remote peer
        answer = await pc.createAnswer()

        # Change the local description for the answer
        await pc.setLocalDescription(answer)

        # return Starlette json response
        return JSONResponse(
            {"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}
        )

    async def __homepage(self, request):
        """
        Return an HTML index page.
        """
        return self.__templates.TemplateResponse(request, "index.html")

    async def __not_found(self, request, exc):
        """
        Return an HTML 404 page.
        """
        return self.__templates.TemplateResponse(request, "404.html", status_code=404)

    async def __server_error(self, request, exc):
        """
        Return an HTML 500 page.
        """
        return self.__templates.TemplateResponse(request, "500.html", status_code=500)

    async def __reset_connections(self, request):
        """
        Resets all connections and recreates VideoServer timestamps
        """
        # get additional parameter
        parameter = await request.json()
        # check if Live Broadcasting is enabled
        if (
            self.__relay is None
            and self.__default_rtc_server is not None
            and (self.__default_rtc_server.is_running)
        ):
            logger.critical("Resetting Server")
            # close old peer connections
            if parameter != 0:  # disable if specified explicitly
                coros = [
                    pc.close() for pc in self.__pcs if pc.iceConnectionState != "closed"
                ]
                await asyncio.gather(*coros)
                self.__pcs.clear()
            await self.__default_rtc_server.reset()
            return PlainTextResponse("OK")
        else:
            # if does, then do nothing
            return PlainTextResponse("DISABLED")

    @contextlib.asynccontextmanager
    async def __lifespan(self, context):
        try:
            yield
        finally:
            # close Video Server
            self.shutdown()
            # collects peer RTC connections
            coros = [
                pc.close() for pc in self.__pcs if pc.iceConnectionState != "closed"
            ]
            await asyncio.gather(*coros)
            self.__pcs.clear()

    def shutdown(self) -> None:
        """
        Gracefully shutdown video-server
        """
        if self.__default_rtc_server is not None:
            self.__logging and logger.debug("Closing Video Server.")
            self.__default_rtc_server.terminate()
            self.__default_rtc_server = None
        # terminate internal server aswell.
        self.__default_rtc_server = None

__call__()

Implements a custom Callable method for WebGear_RTC application.

Source code in vidgear/gears/asyncio/webgear_rtc.py
def __call__(self) -> Starlette:
    """
    Implements a custom Callable method for WebGear_RTC application.
    """
    # validate routing tables
    assert self.routes is not None, "Routing tables are NoneType!"
    if not isinstance(self.routes, list) or not all(
        x in self.routes for x in self.__rt_org_copy
    ):
        raise RuntimeError("[WebGear_RTC:ERROR] :: Routing tables are not valid!")

    # validate middlewares
    assert self.middleware is not None, "Middlewares are NoneType!"
    if self.middleware and (
        not isinstance(self.middleware, list)
        or not all(isinstance(x, Middleware) for x in self.middleware)
    ):
        raise RuntimeError("[WebGear_RTC:ERROR] :: Middlewares are not valid!")

    # return Starlette application
    self.__logging and logger.debug("Running Starlette application.")
    return Starlette(
        debug=(bool(self.__logging)),
        routes=self.routes,
        middleware=self.middleware,
        exception_handlers=self.__exception_handlers,
        lifespan=self.__lifespan,
    )

__init__(api=Backend.CAMGEAR, stabilize=False, camera_num=0, resolution=(640, 480), framerate=25, source=None, stream_mode=False, backend=0, source_demuxer=None, frame_format='bgr24', custom_ffmpeg='', colorspace=None, logging=False, time_delay=0, enablePiCamera=None, **options)

This constructor method initializes the object state and attributes of the WebGear_RTC class.

Parameters:

Name Type Description Default
api Backend

selects the capture backend. Accepted values are Backend.CAMGEAR (default), Backend.PIGEAR, and Backend.FFGEAR. Raises TypeError if an invalid value is given.

CAMGEAR
stabilize bool

enable access to Stabilizer Class for stabilizing frames.

False
camera_num int

[PiGear only] selects the camera module index. Must be >= 0.

0
resolution tuple

[PiGear only] sets (width, height) of the source. Default: (640, 480).

(640, 480)
framerate int / float

[PiGear only] sets the framerate of the source. Default: 25.

25
source Any

[CamGear/FFGear] defines the source for the input stream (device index, filepath, network URL, or image-sequence glob). Default: None.

None
stream_mode bool

[CamGear/FFGear] enables Stream-Mode for yt_dlp-backed streaming URLs.

False
backend int

[CamGear only] selects the OpenCV VideoCapture backend (e.g. cv2.CAP_DSHOW).

0
source_demuxer str

[FFGear only] specifies the FFmpeg demuxer for the source (e.g. "v4l2", "dshow", "avfoundation"). Default: None (auto-detect).

None
frame_format str

[FFGear only] specifies the pixel layout for decoded frames (any FFmpeg-supported pix_fmt, e.g. "bgr24", "gray", "yuv420p"). Default: "bgr24".

'bgr24'
custom_ffmpeg str

[FFGear only] path to a custom FFmpeg executable. Default: "" (use PATH).

''
colorspace str

[CamGear/PiGear only] selects the colorspace of the input stream.

None
logging bool

enables/disables logging. Default: False.

False
time_delay int

[CamGear/PiGear only] time delay (in seconds) before reading frames.

0
enablePiCamera bool

DEPRECATED — use api=Backend.PIGEAR instead. Will be removed in a future release.

None
options dict

additional tweak parameters forwarded to the selected backend gear and/or WebGear_RTC and the Stabilizer class.

{}
Source code in vidgear/gears/asyncio/webgear_rtc.py
def __init__(
    self,
    # VideoGear parameters
    api: Backend = Backend.CAMGEAR,
    stabilize: bool = False,
    # PiGear parameters
    camera_num: int = 0,
    resolution: tuple[int, int] = (640, 480),
    framerate: int | float = 25,
    # CamGear/FFGear parameters
    source: Any = None,
    stream_mode: bool = False,
    backend: int = 0,
    # FFGear parameters
    source_demuxer: str | None = None,
    frame_format: str = "bgr24",
    custom_ffmpeg: str = "",
    # common parameters
    colorspace: str | None = None,
    logging: bool = False,
    time_delay: int = 0,
    # deprecated
    enablePiCamera: bool | None = None,
    **options: dict
):
    """
    This constructor method initializes the object state and attributes of the WebGear_RTC class.

    Parameters:
        api (Backend): selects the capture backend. Accepted values are `Backend.CAMGEAR` _(default)_,
            `Backend.PIGEAR`, and `Backend.FFGEAR`. Raises `TypeError` if an invalid value is given.
        stabilize (bool): enable access to Stabilizer Class for stabilizing frames.
        camera_num (int): [PiGear only] selects the camera module index. Must be `>= 0`.
        resolution (tuple): [PiGear only] sets `(width, height)` of the source. Default: `(640, 480)`.
        framerate (int/float): [PiGear only] sets the framerate of the source. Default: `25`.
        source (Any): [CamGear/FFGear] defines the source for the input stream (device index,
            filepath, network URL, or image-sequence glob). Default: `None`.
        stream_mode (bool): [CamGear/FFGear] enables Stream-Mode for `yt_dlp`-backed streaming URLs.
        backend (int): [CamGear only] selects the OpenCV VideoCapture backend (e.g. `cv2.CAP_DSHOW`).
        source_demuxer (str): [FFGear only] specifies the FFmpeg demuxer for the source
            (e.g. `"v4l2"`, `"dshow"`, `"avfoundation"`). Default: `None` (auto-detect).
        frame_format (str): [FFGear only] specifies the pixel layout for decoded frames
            (any FFmpeg-supported pix_fmt, e.g. `"bgr24"`, `"gray"`, `"yuv420p"`). Default: `"bgr24"`.
        custom_ffmpeg (str): [FFGear only] path to a custom FFmpeg executable. Default: `""` (use PATH).
        colorspace (str): [CamGear/PiGear only] selects the colorspace of the input stream.
        logging (bool): enables/disables logging. Default: `False`.
        time_delay (int): [CamGear/PiGear only] time delay (in seconds) before reading frames.
        enablePiCamera (bool): **DEPRECATED** — use `api=Backend.PIGEAR` instead. Will be removed
            in a future release.
        options (dict): additional tweak parameters forwarded to the selected backend gear
            and/or WebGear_RTC and the Stabilizer class.
    """
    # enable logging if specified
    self.__logging = logging if isinstance(logging, bool) else False

    # print current version
    logcurr_vidgear_ver(logging=self.__logging)

    # handle deprecated `enablePiCamera`
    if enablePiCamera is not None:
        warnings.warn(
            "`enablePiCamera` is deprecated in WebGear_RTC; use `api=Backend.PIGEAR` instead.",
            DeprecationWarning,
            stacklevel=2,
        )
        api = Backend.PIGEAR if enablePiCamera else Backend.CAMGEAR

    # raise error(s) for critical Class imports
    import_dependency_safe("starlette" if starlette is None else "")
    import_dependency_safe("aiortc" if aiortc is None else "")

    # initialize global params
    custom_data_location = ""  # path to save data-files to custom location
    data_path = ""  # path to WebGear_RTC data-files
    overwrite_default = False
    self.__relay = None  # act as broadcaster

    # reformat dictionary
    options = {str(k).strip(): v for k, v in options.items()}

    # assign values to global variables if specified and valid
    if options:
        if "custom_data_location" in options:
            value = options["custom_data_location"]
            if isinstance(value, str):
                assert os.access(
                    value, os.W_OK
                ), "[WebGear_RTC:ERROR] :: Permission Denied!, cannot write WebGear_RTC data-files to '{}' directory!".format(
                    value
                )
                assert os.path.isdir(
                    os.path.abspath(value)
                ), "[WebGear_RTC:ERROR] :: `custom_data_location` value must be the path to a directory and not to a file!"
                custom_data_location = os.path.abspath(value)
            else:
                logger.warning("Skipped invalid `custom_data_location` value!")
            del options["custom_data_location"]  # clean

        if "overwrite_default_files" in options:
            value = options["overwrite_default_files"]
            if isinstance(value, bool):
                overwrite_default = value
            else:
                logger.warning("Skipped invalid `overwrite_default_files` value!")
            del options["overwrite_default_files"]  # clean

        if "enable_live_broadcast" in options:
            value = options["enable_live_broadcast"]
            if isinstance(value, bool):
                if value:
                    self.__relay = MediaRelay()
                    options["enable_infinite_frames"] = (
                        True  # enforce infinite frames
                    )
                    logger.critical(
                        "Enabled live broadcasting for Peer connection(s)."
                    )
                else:
                    pass
            else:
                logger.warning("Skipped invalid `enable_live_broadcast` value!")
            del options["enable_live_broadcast"]  # clean

    # check if custom certificates path is specified
    if custom_data_location:
        data_path = generate_webdata(
            custom_data_location,
            c_name="webgear_rtc",
            overwrite_default=overwrite_default,
            logging=logging,
        )
    else:
        # otherwise generate suitable path
        data_path = generate_webdata(
            os.path.join(expanduser("~"), ".vidgear"),
            c_name="webgear_rtc",
            overwrite_default=overwrite_default,
            logging=logging,
        )

    # log it
    self.__logging and logger.debug(
        "`{}` is the default location for saving WebGear_RTC data-files.".format(
            data_path
        )
    )

    # define Jinja2 templates handler
    self.__templates = Jinja2Templates(directory="{}/templates".format(data_path))

    # define custom exception handlers
    self.__exception_handlers = {404: self.__not_found, 500: self.__server_error}
    # define routing tables
    self.routes = [
        Route("/", endpoint=self.__homepage),
        Route("/offer", self.__offer, methods=["GET", "POST"]),
        Mount(
            "/static",
            app=StaticFiles(directory="{}/static".format(data_path)),
            name="static",
        ),
    ]

    # define middleware support
    self.middleware = []

    # Handle RTC video server
    if "custom_stream" in options or source is not None:
        # Handle video source
        self.__default_rtc_server = RTC_VideoServer(
            api=api,
            stabilize=stabilize,
            source=source,
            camera_num=camera_num,
            stream_mode=stream_mode,
            backend=backend,
            source_demuxer=source_demuxer,
            frame_format=frame_format,
            custom_ffmpeg=custom_ffmpeg,
            colorspace=colorspace,
            resolution=resolution,
            framerate=framerate,
            logging=logging,
            time_delay=time_delay,
            **options
        )
        # add exclusive reset connection node
        self.routes.append(
            Route("/close_connection", self.__reset_connections, methods=["POST"])
        )
    else:
        raise ValueError(
            "[WebGear_RTC:ERROR] :: Source cannot be NoneType without Custom Stream(`custom_stream`) defined!"
        )

    # copying original routing tables for further validation
    self.__rt_org_copy = self.routes[:]
    # collects peer RTC connections
    self.__pcs = set()

shutdown()

Gracefully shutdown video-server

Source code in vidgear/gears/asyncio/webgear_rtc.py
def shutdown(self) -> None:
    """
    Gracefully shutdown video-server
    """
    if self.__default_rtc_server is not None:
        self.__logging and logger.debug("Closing Video Server.")
        self.__default_rtc_server.terminate()
        self.__default_rtc_server = None
    # terminate internal server aswell.
    self.__default_rtc_server = None