Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add base64 encode for self-signed certificate and key pem data #82

Merged
merged 1 commit into from
Apr 20, 2023

Conversation

CodeDing
Copy link
Contributor

Establish a test environment for stunnerd locally. Follow the steps below.

Prerequisite

  • golang1.20.3

Installation

  1. Download the mediatx from the repository https://github.com/aler9/mediamtx.git as the streaming server.
  • cd

  • git clone https://github.com/aler9/mediamtx.git

  • cd mediamtx

  • make binaries

  • modify the config option in the mediamtx.yml
    webrtcICEServers: [turn:user1:passwd1::3478?transport=dtls]

  • ./mediatx

Note
Replace the host-ip field with your own host's ip.

  1. Download a binary tool called as ffmpeg which is used to publish a video stream to mediatx.
    For example, on macOS, run the command like below
  • brew install ffmpeg
  1. Download a video material http://vjs.zencdn.net/v/oceans.mp4.
  1. Publish the above video to the mediatx.
  • ffmpeg -re -stream_loop -1 -i test.mp4 -c:v libx264 -an -b:v 500k -bufsize 500k -preset ultrafast -rtsp_transport tcp -f rtsp rtsp://127.0.0.1:8554/mystream
  1. Download the stunnerd source from the repository.
  • cd stunner
  • go build -o stunnerd cmd/stunnerd/main.go
  • ./stunnerd --log=all:TRACE turn://user1:passwd1@:3478?transport=dtls

Note
Replace the host-ip with your own host's ip.

Before modifying the code, the stunnerd's log looks like:

15:35:24.141869 listener.go:57: stunner-listener-default-listener TRACE: NewListener: "default-listener":{DTLS://127.0.0.1:3478<32768-65535>,public=-:-,cert/key=<SECRET>/<SECRET>,routes=[allow-any]}
15:35:24.141876 listener.go:121: stunner-listener-default-listener TRACE: Reconcile: "default-listener":{DTLS://127.0.0.1:3478<32768-65535>,public=-:-,cert/key=<SECRET>/<SECRET>,routes=[allow-any]}
15:35:24.141898 reconcile.go:100: listener-manager ERROR: could not create new object: invalid TLS certificate: base64-decode error: illegal base64 data at input byte 0
15:35:24.141904 reconcile.go:131: stunner ERROR: could not reconcile listener config: invalid TLS certificate: base64-decode error: illegal base64 data at input byte 0
15:35:24.141911 reconcile.go:196: stunner INFO: rolling back to previous configuration: {version="v1alpha1",admin:{},auth:{},listeners=[],clusters=[]}
15:35:24.141918 main.go:163: stunnerd TRACE: reconciliation ready
15:35:24.141945 main.go:168: stunnerd ERROR: could not reconcile new configuration: plaintext: empty username or password, rolling back to last running config

After adding the base64 encode feature to the self-signed certificate and key pem data, the stunner's log looks like:

15:40:03.130721 handlers.go:66: stunner TRACE: NewPermissionHandler
15:40:03.130729 server.go:109: stunner DEBUG: setting up DTLS/UDP listener at 127.0.0.1:3478
15:40:03.131509 handlers.go:17: stunner TRACE: NewAuthHandler
15:40:03.131585 server.go:161: stunner INFO: listener default-listener: TURN server running
15:40:03.131595 reconcile.go:177: stunner INFO: reconciliation ready: new objects: 4, changed objects: 0, deleted objects: 0, started objects: 1, restarted objects: 0
15:40:03.131603 reconcile.go:181: stunner INFO: status: READY, realm: stunner.l7mp.io, authentication: plaintext, listeners: default-listener: [dtls://127.0.0.1:3478<32768:65535>], active allocations: 0
15:40:03.131609 main.go:163: stunnerd TRACE: reconciliation ready
  1. Browse the video with the following index.html.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style>
html, body {
	margin: 0;
	padding: 0;
	height: 100%;
	overflow: hidden;
}
#video {
	width: 100%;
	height: 100%;
	background: black;
}
</style>
</head>
<body>
<h1> WebRTC Host </h1>

<video id="video" muted controls autoplay playsinline></video>

<script>

const restartPause = 2000;

class Receiver {
	constructor() {
		this.terminated = false;
		this.ws = null;
		this.pc = null;
		this.restartTimeout = null;
		this.start();
	}

	start() {
		console.log("connecting");

        //this.ws = new WebSocket(window.location.href.replace(/^http/, "ws") + 'ws');

        this.ws = new WebSocket("ws://10.159.10.28:8889/mystream/ws");


        this.ws.onerror = () => {
            console.log("ws error");
            if (this.ws === null) {
                return;
            }
            this.ws.close();
            this.ws = null;
        };

        this.ws.onclose = () => {
            console.log("ws closed");
            this.ws = null;
            this.scheduleRestart();
        };

        this.ws.onmessage = (msg) => this.onIceServers(msg);
	}

    onIceServers(msg) {
        if (this.ws === null) {
            return;
        }

        const iceConfig = JSON.parse(msg.data);
        console.log(iceConfig)

        this.pc = new RTCPeerConnection({
            iceServers: iceConfig,
            iceTransportPolicy: 'relay'
        });

        this.ws.onmessage = (msg) => this.onRemoteDescription(msg);
        this.pc.onicecandidate = (evt) => this.onIceCandidate(evt);

        this.pc.oniceconnectionstatechange = () => {
            if (this.pc === null) {
                return;
            }

            console.log("peer connection state:", this.pc.iceConnectionState);

            switch (this.pc.iceConnectionState) {
            case "disconnected":
                this.scheduleRestart();
            }
        };

        this.pc.ontrack = (evt) => {
            console.log("new track " + evt.track.kind);
            document.getElementById("video").srcObject = evt.streams[0];
        };

        const direction = "sendrecv";
        this.pc.addTransceiver("video", { direction });
        this.pc.addTransceiver("audio", { direction });

        this.pc.createOffer()
            .then((desc) => {
                if (this.pc === null || this.ws === null) {
                    return;
                }

                this.pc.setLocalDescription(desc);

                console.log("sending offer");
                this.ws.send(JSON.stringify(desc));
            });
    }

	onRemoteDescription(msg) {
		if (this.pc === null || this.ws === null) {
			return;
		}

		this.pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(msg.data)));
		this.ws.onmessage = (msg) => this.onRemoteCandidate(msg);
	}

    onIceCandidate(evt) {
        if (this.ws === null) {
            return;
        }

        if (evt.candidate !== null) {
            if (evt.candidate.candidate !== "") {
                this.ws.send(JSON.stringify(evt.candidate));
            }
        }
    }

	onRemoteCandidate(msg) {
		if (this.pc === null) {
			return;
		}

		this.pc.addIceCandidate(JSON.parse(msg.data));
	}

    scheduleRestart() {
        if (this.terminated) {
            return;
        }

        if (this.ws !== null) {
            this.ws.close();
            this.ws = null;
        }

        if (this.pc !== null) {
            this.pc.close();
            this.pc = null;
        }

        this.restartTimeout = window.setTimeout(() => {
            this.restartTimeout = null;
            this.start();
        }, restartPause);
    }
}

window.addEventListener('DOMContentLoaded', () => new Receiver());

</script>

</body>
</html>

@rg0now rg0now merged commit 75d1251 into l7mp:main Apr 20, 2023
@rg0now
Copy link
Member

rg0now commented Apr 20, 2023

Thanks, applied! Welcome onboard.

By the way, I really like the detailed analysis, this is almost like a tutorial for setting up STUNner with MediaMTX. With a tiny extra work we could easily make this into a new STUNner tutorial, I would be happy to support you in this. You can find examples here. It can be a standalone deployment or something in Kubernetes, it does not matter: what matters is the way you configure the clients to talk to STUNner by setting webrtcICEServers in mediamtx.yml. Wdyt?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants