Table of Contents

Embedded Server

The ServerPage1 demonstrates an RTSP streaming server running within the MAUI application. It captures video and audio from local devices, encodes them as H.264 and AAC, and serves the stream to any RTSP client on the network.

Overview

The ServerPage1 performs the following:

  1. Enumerates video and audio capture devices
  2. Creates an RtspServer listening on a configurable port
  3. Captures from camera and microphone, encoding as H.264 video and AAC audio
  4. Combines capture sources into an AggregatedNetworkSource
  5. Accepts client connections and distributes media samples to all connected clients
  6. Rejects incoming publisher connections (output-only server)

Creating the RTSP Server

var pars = new VAST.RTSP.RtspServerParameters();
pars.RtspEndPoints.Add(new IPEndPoint(IPAddress.Any, this.rtspPort));

this.server = new VAST.RTSP.RtspServer(10, pars);
this.server.Disconnected += Server_Disconnected;
this.server.PublisherConnected += Server_PublisherConnected;
this.server.ClientConnected += Server_ClientConnected;

VAST.RTSP.RtspGlobal.ForceRtpTransport = VAST.RTP.RtpTransportType.TcpInterleaved;
this.server.Start();

The server listens on all network interfaces (IPAddress.Any) on port 10554. RTP transport is forced to TCP interleaved mode, which delivers media over the same TCP connection as the RTSP control channel — this provides reliable delivery through NAT and firewalls without requiring separate UDP ports.

After starting the server, the page displays the connection URI:

rtsp://{localIp}:10554/stream

The local IPv4 address is auto-detected by iterating network interfaces at startup.

Creating Capture Sources

Capture sources are created the same way as in Simple Capture, with H.264 video and AAC audio encoding configured via SetDesiredOutputType:

this.activeVideoCaptureSource = VAST.Media.SourceFactory.CreateVideoCapture(
    this.videoDevice.DeviceId, this.videoCaptureMode);
this.activeVideoCaptureSource.Rotation = this.videoRotation;
this.activeVideoCaptureSource.AddRef();

this.activeAudioCaptureSource = VAST.Media.SourceFactory.CreateAudioCapture(
    this.audioDevice.DeviceId, this.audioCaptureMode);
this.activeAudioCaptureSource.AddRef();

Video encoding parameters (resolution, bitrate, profile, level, keyframe interval) and audio encoding parameters (sample rate, channels, bitrate) are configurable through the UI.

The encoding framework options are the same as in the Simple Capture page.

Aggregated Source

The capture sources are combined into an AggregatedNetworkSource that acts as the publishing point for the server:

this.serverSource = new VAST.Network.AggregatedNetworkSource();
this.serverSource.AddRef();

if (this.activeVideoCaptureSource != null) this.serverSource.AddSource(this.activeVideoCaptureSource);
if (this.activeAudioCaptureSource != null) this.serverSource.AddSource(this.activeAudioCaptureSource);

this.serverSource.NewStream += Publisher_NewStream;
this.serverSource.NewSample += Publisher_NewSample;
this.serverSource.StateChanged += Publisher_StateChanged;
this.serverSource.Open();

The aggregated source fires NewStream events to report media types (used when new clients connect) and NewSample events to deliver each captured media sample. When the source reaches the Opened state, Start() is called to begin capture.

Client Connections

When a client connects to the RTSP server, the ClientConnected handler validates the publishing path, accepts the client, and adds all available media streams:

private void Server_ClientConnected(object sender, VAST.Network.INetworkSink client)
{
    lock (this)
    {
        if (client.PublishingPath != this.publishName)
        {
            return;
        }

        client.Accept = true;

        int index = 0;
        foreach (VAST.Common.MediaType mt in this.mediaStreams)
        {
            client.AddStream(index++, mt);
        }

        this.connectedClients.Add(client.EndPoint, client);
    }
}

Each incoming media sample is distributed to all connected clients:

private void Publisher_NewSample(object sender, VAST.Media.NewSampleEventArgs e)
{
    lock (this)
    {
        foreach (VAST.Media.IMediaSink client in this.connectedClients.Values)
        {
            client.PushMedia(e.Sample.StreamIndex, e.Sample);
        }
    }
}

When a client disconnects, the Disconnected handler removes it from the tracking dictionary.

All incoming publisher connections are rejected (publisher.Accept = false) — this server only streams out captured media, it does not accept incoming streams.

Device Orientation

On mobile devices, the camera rotation is adjusted when the device orientation changes. The page monitors orientation via OnSizeAllocated and restarts capture with the updated rotation.

Send Log

The page includes a Send Log button that uploads the application log file to VASTreaming support for diagnostics:

await VAST.Common.License.SendLog("MAUI server #1 issue");

SendLog sends the current log file to the support server. A valid license key must be configured for this feature to work.

See Also