1.3.10. Peer Streaming

Overview

Peer streaming is feature of the SDK that allows two SDK applications to directly share media streams without using Proximie’s infrastructure, e.g. over a LAN without needing internet access.

Without the support of Proximie services, there are a number of limitations to using peer streaming:

  1. The session itself is implied by the peers connecting, rather than being arranged using Proximie services.

  2. Only the two local peers are participants; peer streaming does not use any remote services.

  3. Traffic is encrypted between peers, but there is no authentication/authorization of the peers themselves, other than both peers needing to agree on an encryption key/passphrase.

Concepts

Peer session

The peer session is the vehicle that connects two peers together. Each peer is defined by: the details of where it can be found (namely, its host name or IP address), and a set of named “channels” that they may transmit media with. In addition to the peers themselves, the session has an encryption key/passphrase that is used to encode outgoing and decode incoming peer feeds.

The application instantiates a peer session using the configuration and declaring which of the two peer roles it is assuming.

Peer feeds

Feeds are created by the application in association with the peer session. An outgoing peer feed must use a channel from the local peer’s details, and an incoming feed must use a channel from the remote peer’s details.

When a peer shares a feed, it does so by listening on a port defined for the channel it is sharing on. The other peer receives that feed by contacting the host of the peer sharing the feed, on the port defined for the channel. The receiving peer local port is dynamically assigned.

Creating a peer session

The PeerSession class defines a peer session. It is created by calling its factory function create(). To create the peer session, the application needs to provide three key pieces of information:

  1. The encryption key to use for the session.

  2. The local (i.e. outgoing) peer details.

  3. The remote (i.e. incoming) peer details.

Both local and remote peer details use the same data structure: PeerSession::PeerDetails.

    // Details for the peer application with the patient
    PeerSession::PeerDetails patientPeer;
    patientPeer.label = "Patient";
    patientPeer.host.hostname = "patient-peer";
    patientPeer.channels["room-cam"] = {"Patient: Room", VIDEO_PORT_ROOM_CAM};
    patientPeer.channels["room-mic"] = {"Patient: Mic", AUDIO_PORT_ROOM_MIC};
    // Details for the peer application with operating console
    PeerSession::PeerDetails consolePeer;
    consolePeer.label = "Console";
    consolePeer.host.hostname = "console-peer";
    consolePeer.channels["web-cam"] = {"Console: Webcam", VIDEO_PORT_CONSOLE_CAM};
    consolePeer.channels["local-mic"] = {"Console: Mic", AUDIO_PORT_CONSOLE_MIC};

Note that this is merely illustrative of the possible data values; in a real application, the configuration of the peers would likely be read from a configuration file or other source, rather than being hard-coded as in this example.

In the above example, the two peers are called “Patient” and “Console”. The patient peer can be found on the host resolved from patient-peer, which declares two channels (room-cam and room-mic) and the ports assigned to each.

Once the peers are obtained, the application can create the peer session using the usual ProximieContext (see ProximieContext) and a PeerSession::PeerSessionSettings structure that defines the peers and the encryption key to use.

    PeerSession::PeerSessionSettings peerSettings(patientPeer,      // Local peer
                                                  consolePeer,      // Remote peer
                                                  ENCRYPTION_KEY);  // Encryption key
    auto peerSessionCreated = PeerSession::create(pxcontext, peerSettings);
    if (!peerSessionCreated) {
        // Handle error...
    }
    auto peerSession = peerSessionCreated.value();

Note that the first peer is the local (outgoing) peer, and the second is the remote (incoming) peer.

Important

The encryption key/passphrase needs to be a specific format, this being:

  1. Between 10 and 79 characters in length, inclusive

If the key is not valid, the peer session creation will fail with an error.

Keen observers may have noticed that we do not need to specify the host for the local peer, as this is always outgoing from the host of the application. However, by making the peer details data structures identical, applications can share the configuration data (e.g. configuration data file) and decide which peer role to use at runtime with the same data.

Creating an outgoing peer feed

Outgoing feeds must only use channels that are defined for the peer that was chosen as the local role in the peer session. Starting a local peer feed is similar to the process when creating feeds for Proximie remote sessions (see the section: Media Server Session).

    using namespace Proximie::PxMedia::Literals;

    // Properties for the video feed
    PxMedia::PeerLocalVideoFeed::FeedProperties localVideoProps;
    localVideoProps.label = "local-webcam";
    localVideoProps.channel = "room-cam";  // Needs to match a local channel key
    // Video feed input source
    PxMedia::VideoInputFeedV4Linux2 localVideo;
    localVideo.deviceProperties().device("/dev/video0");
    localVideo.videoCapabilities().frameRate(30);
    // Encoder configuration
    PxMedia::X264EncoderFeedComponent encoderProperties;
    encoderProperties.bitrate(2000_kbps);
    // Create the feed
    auto localVideoCreated = PxMedia::PeerLocalVideoFeed::create(peerSession, localVideoProps,
                                                                 localVideo, &encoderProperties);
    if (!localVideoCreated) {
        // Handle error...
    }
    auto localVideoFeed = localVideoCreated.value();
    auto localVideoStarted = localVideoFeed->startFeed();
    if (!localVideoStarted) {
        // Handle error...
    }

    // Properties for the audio feed
    PxMedia::PeerLocalAudioFeed::FeedProperties localAudioProps;
    localAudioProps.label = "local-mic";
    localAudioProps.channel = "room-mic";  // Needs to match a local channel key
    // Audio feed input source
    PxMedia::AudioInputFeedAuto localAudio;
    // Create the audio feed
    auto localAudioCreated =
        PxMedia::PeerLocalAudioFeed::create(peerSession, localAudioProps, localAudio);
    if (!localAudioCreated) {
        // Handle error...
    }
    auto localAudioFeed = localAudioCreated.value();
    auto localAudioStarted = localAudioFeed->startFeed();
    if (!localAudioStarted) {
        // Handle error...
    }

Creating an incoming peer feed

Incoming feeds must only use channels that are defined for the peer that was chosen as the remote role in the peer session. Again, the process should be quite familiar.

    // Properties for the video feed
    PxMedia::PeerRemoteVideoFeed::FeedProperties remoteVideoProps;
    remoteVideoProps.label = "remote-cam";
    remoteVideoProps.channel = "web-cam";  // Needs to match a remote channel key
    // Output locally
    PxMedia::VideoOutputFeedAuto videoOut;
    // Create the feed
    auto remoteVideoCreated =
        PxMedia::PeerRemoteVideoFeed::create(peerSession, remoteVideoProps, videoOut);
    if (!remoteVideoCreated) {
        // Handle error...
    }
    auto remoteVideoFeed = remoteVideoCreated.value();
    auto remoteVideoStarted = remoteVideoFeed->startFeed();
    if (!remoteVideoStarted) {
        // Handle error...
    }

    // Properties for the audio feed
    PxMedia::PeerRemoteAudioFeed::FeedProperties remoteAudioProps;
    remoteAudioProps.label = "remote-audio";
    remoteAudioProps.channel = "room-mic";  // Needs to match a remote channel key
    // Output locally
    PxMedia::AudioOutputFeedAuto audioOut;
    // Create the feed
    auto remoteAudioCreated =
        PxMedia::PeerRemoteAudioFeed::create(peerSession, remoteAudioProps, audioOut);
    if (!remoteAudioCreated) {
        // Handle error...
    }
    auto remoteAudioFeed = remoteAudioCreated.value();
    auto remoteAudioStarted = remoteAudioFeed->startFeed();
    if (!remoteAudioStarted) {
        // Handle error...
    }

Stopping Feeds

Stopping a peer feed is a simple matter of calling the stopFeed() method.

    auto stopped = peerFeed->stopFeed();
    if (!stopped) {
        // Handle error...
    }