Add example of using with Janus video-room

Resolves #268
This commit is contained in:
Sean DuBois
2018-12-08 16:44:47 -08:00
committed by Michiel De Backker
parent 04d691ef96
commit 12fd9b41e4
16 changed files with 161 additions and 206 deletions

View File

@@ -5,8 +5,8 @@ import (
"time"
"github.com/pions/webrtc"
"github.com/pions/webrtc/examples/gstreamer-receive/gst"
"github.com/pions/webrtc/examples/util"
"github.com/pions/webrtc/examples/util/gstreamer-sink"
"github.com/pions/webrtc/pkg/ice"
"github.com/pions/webrtc/pkg/rtcp"
)

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/pions/webrtc"
"github.com/pions/webrtc/examples/gstreamer-send/gst"
"github.com/pions/webrtc/examples/util"
"github.com/pions/webrtc/examples/util/gstreamer-src"
"github.com/pions/webrtc/pkg/ice"
)

View File

@@ -1,88 +0,0 @@
#include "gst.h"
#include <gst/app/gstappsrc.h>
typedef struct SampleHandlerUserData {
int pipelineId;
} SampleHandlerUserData;
GMainLoop *gstreamer_send_main_loop = NULL;
void gstreamer_send_start_mainloop(void) {
gstreamer_send_main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(gstreamer_send_main_loop);
}
static gboolean gstreamer_send_bus_call(GstBus *bus, GstMessage *msg, gpointer data) {
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_EOS:
g_print("End of stream\n");
exit(1);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error(msg, &error, &debug);
g_free(debug);
g_printerr("Error: %s\n", error->message);
g_error_free(error);
exit(1);
break;
}
default:
break;
}
return TRUE;
}
GstFlowReturn gstreamer_send_new_sample_handler(GstElement *object, gpointer user_data) {
GstSample *sample = NULL;
GstBuffer *buffer = NULL;
gpointer copy = NULL;
gsize copy_size = 0;
SampleHandlerUserData *s = (SampleHandlerUserData *)user_data;
g_signal_emit_by_name (object, "pull-sample", &sample);
if (sample) {
buffer = gst_sample_get_buffer(sample);
if (buffer) {
gst_buffer_extract_dup(buffer, 0, gst_buffer_get_size(buffer), &copy, &copy_size);
goHandlePipelineBuffer(copy, copy_size, GST_BUFFER_DURATION(buffer), s->pipelineId);
}
gst_sample_unref (sample);
}
return GST_FLOW_OK;
}
GstElement *gstreamer_send_create_pipeline(char *pipeline) {
gst_init(NULL, NULL);
GError *error = NULL;
return gst_parse_launch(pipeline, &error);
}
void gstreamer_send_start_pipeline(GstElement *pipeline, int pipelineId) {
SampleHandlerUserData *s = calloc(1, sizeof(SampleHandlerUserData));
s->pipelineId = pipelineId;
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
guint bus_watch_id = gst_bus_add_watch(bus, gstreamer_send_bus_call, NULL);
gst_object_unref(bus);
GstElement *appsink = gst_bin_get_by_name(GST_BIN(pipeline), "appsink");
g_object_set(appsink, "emit-signals", TRUE, NULL);
g_signal_connect(appsink, "new-sample", G_CALLBACK(gstreamer_send_new_sample_handler), s);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
}
void gstreamer_send_stop_pipeline(GstElement *pipeline) {
gst_element_set_state(pipeline, GST_STATE_NULL);
}

View File

@@ -1,99 +0,0 @@
package gst
/*
#cgo pkg-config: gstreamer-1.0 gstreamer-app-1.0
#include "gst.h"
*/
import "C"
import (
"fmt"
"sync"
"unsafe"
"github.com/pions/webrtc"
"github.com/pions/webrtc/pkg/media"
)
func init() {
go C.gstreamer_send_start_mainloop()
}
// Pipeline is a wrapper for a GStreamer Pipeline
type Pipeline struct {
Pipeline *C.GstElement
in chan<- media.RTCSample
id int
codecName string
}
var pipelines = make(map[int]*Pipeline)
var pipelinesLock sync.Mutex
// CreatePipeline creates a GStreamer Pipeline
func CreatePipeline(codecName string, in chan<- media.RTCSample) *Pipeline {
pipelineStr := "appsink name=appsink"
switch codecName {
case webrtc.VP8:
pipelineStr = "videotestsrc ! vp8enc ! " + pipelineStr
case webrtc.VP9:
pipelineStr = "videotestsrc ! vp9enc ! " + pipelineStr
case webrtc.H264:
pipelineStr = "videotestsrc ! video/x-raw,format=I420 ! x264enc bframes=0 speed-preset=veryfast key-int-max=60 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr
case webrtc.Opus:
pipelineStr = "audiotestsrc ! opusenc ! " + pipelineStr
default:
panic("Unhandled codec " + codecName)
}
pipelineStrUnsafe := C.CString(pipelineStr)
defer C.free(unsafe.Pointer(pipelineStrUnsafe))
pipelinesLock.Lock()
defer pipelinesLock.Unlock()
pipeline := &Pipeline{
Pipeline: C.gstreamer_send_create_pipeline(pipelineStrUnsafe),
in: in,
id: len(pipelines),
codecName: codecName,
}
pipelines[pipeline.id] = pipeline
return pipeline
}
// Start starts the GStreamer Pipeline
func (p *Pipeline) Start() {
C.gstreamer_send_start_pipeline(p.Pipeline, C.int(p.id))
}
// Stop stops the GStreamer Pipeline
func (p *Pipeline) Stop() {
C.gstreamer_send_stop_pipeline(p.Pipeline)
}
const (
videoClockRate = 90000
audioClockRate = 48000
)
//export goHandlePipelineBuffer
func goHandlePipelineBuffer(buffer unsafe.Pointer, bufferLen C.int, duration C.int, pipelineID C.int) {
pipelinesLock.Lock()
defer pipelinesLock.Unlock()
if pipeline, ok := pipelines[int(pipelineID)]; ok {
var samples uint32
if pipeline.codecName == webrtc.Opus {
samples = uint32(audioClockRate * (float32(duration) / 1000000000))
} else {
samples = uint32(videoClockRate * (float32(duration) / 1000000000))
}
pipeline.in <- media.RTCSample{Data: C.GoBytes(buffer, bufferLen), Samples: samples}
} else {
fmt.Printf("discarding buffer, no pipeline with id %d", int(pipelineID))
}
C.free(buffer)
}

View File

@@ -1,16 +0,0 @@
#ifndef GST_H
#define GST_H
#include <glib.h>
#include <gst/gst.h>
#include <stdint.h>
#include <stdlib.h>
extern void goHandlePipelineBuffer(void *buffer, int bufferLen, int samples, int pipelineId);
GstElement *gstreamer_send_create_pipeline(char *pipeline);
void gstreamer_send_start_pipeline(GstElement *pipeline, int pipelineId);
void gstreamer_send_stop_pipeline(GstElement *pipeline);
void gstreamer_send_start_mainloop(void);
#endif

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/pions/webrtc"
"github.com/pions/webrtc/examples/gstreamer-send/gst"
"github.com/pions/webrtc/examples/util"
"github.com/pions/webrtc/examples/util/gstreamer-src"
"github.com/pions/webrtc/pkg/ice"
)

View File

@@ -19,3 +19,13 @@ Got VP8 track, saving to disk as output.ivf
```
You will see output.ivf in the current folder.
## video-room
This example demonstrates how to stream to a Janus video-room using pion-WebRTC
### Running
run `main.go` in `github.com/pions/webrtc/examples/janus-gateway/video-room`
If this worked you should see a test video in video-room `1234`
This is the default demo-room that exists in the sample configs, and can quickly be accessed via the Janus demos.

View File

@@ -0,0 +1,9 @@
module github.com/pions/webrtc/examples/janus-gateway/streaming
replace github.com/pions/webrtc => ../../../
require (
github.com/gorilla/websocket v1.4.0 // indirect
github.com/notedit/janus-go v0.0.0-20180821162543-a152adf0cb7b
github.com/pions/webrtc v1.1.1
)

View File

@@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/notedit/janus-go v0.0.0-20180821162543-a152adf0cb7b h1:GT1/zfKpQHX4Cz7F1QUE/tjE/OP0KM5aYaFiKVRgvkk=
github.com/notedit/janus-go v0.0.0-20180821162543-a152adf0cb7b/go.mod h1:BN/Txse3qz8tZOmCm2OfajB2wHVujWmX3o9nVdsI6gE=
github.com/pions/pkg v0.0.0-20181115215726-b60cd756f712 h1:ciXO7F7PusyAzW/EZJt01bETgfTxP/BIGoWQ15pBP54=
github.com/pions/pkg v0.0.0-20181115215726-b60cd756f712/go.mod h1:r9wKZs+Xxv2acLspex4CHQiIhFjGK1zGP+nUm/8klXA=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k=
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
gotest.tools v2.2.0+incompatible h1:y0IMTfclpMdsdIbr6uwmJn5/WZ7vFuObxDMdrylFM3A=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

View File

@@ -0,0 +1,119 @@
package main
import (
"fmt"
"log"
janus "github.com/notedit/janus-go"
"github.com/pions/webrtc"
"github.com/pions/webrtc/examples/util"
"github.com/pions/webrtc/examples/util/gstreamer-src"
"github.com/pions/webrtc/pkg/ice"
)
func watchHandle(handle *janus.Handle) {
// wait for event
for {
msg := <-handle.Events
switch msg := msg.(type) {
case *janus.SlowLinkMsg:
log.Println("SlowLinkMsg type ", handle.Id)
case *janus.MediaMsg:
log.Println("MediaEvent type", msg.Type, " receiving ", msg.Receiving)
case *janus.WebRTCUpMsg:
log.Println("WebRTCUp type ", handle.Id)
case *janus.HangupMsg:
log.Println("HangupEvent type ", handle.Id)
case *janus.EventMsg:
log.Printf("EventMsg %+v", msg.Plugindata.Data)
}
}
}
func main() {
// Everything below is the pion-WebRTC API! Thanks for using it ❤️.
// Setup the codecs you want to use.
// We'll use the default ones but you can also define your own
webrtc.RegisterDefaultCodecs()
// Prepare the configuration
config := webrtc.RTCConfiguration{
IceServers: []webrtc.RTCIceServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
}
// Create a new RTCPeerConnection
peerConnection, err := webrtc.New(config)
util.Check(err)
peerConnection.OnICEConnectionStateChange(func(connectionState ice.ConnectionState) {
fmt.Printf("Connection State has changed %s \n", connectionState.String())
})
// Create a audio track
opusTrack, err := peerConnection.NewRTCSampleTrack(webrtc.DefaultPayloadTypeOpus, "audio", "pion1")
util.Check(err)
_, err = peerConnection.AddTrack(opusTrack)
util.Check(err)
// Create a video track
vp8Track, err := peerConnection.NewRTCSampleTrack(webrtc.DefaultPayloadTypeVP8, "video", "pion2")
util.Check(err)
_, err = peerConnection.AddTrack(vp8Track)
util.Check(err)
offer, err := peerConnection.CreateOffer(nil)
util.Check(err)
gateway, err := janus.Connect("ws://localhost:8188/janus")
util.Check(err)
session, err := gateway.Create()
util.Check(err)
handle, err := session.Attach("janus.plugin.videoroom")
util.Check(err)
go watchHandle(handle)
_, err = handle.Message(map[string]interface{}{
"request": "join",
"ptype": "publisher",
"room": 1234,
"id": 1,
}, nil)
util.Check(err)
msg, err := handle.Message(map[string]interface{}{
"request": "publish",
"audio": true,
"video": true,
"data": false,
}, map[string]interface{}{
"type": "offer",
"sdp": offer.Sdp,
"trickle": false,
})
util.Check(err)
if msg.Jsep != nil {
err = peerConnection.SetRemoteDescription(webrtc.RTCSessionDescription{
Type: webrtc.RTCSdpTypeAnswer,
Sdp: msg.Jsep["sdp"].(string),
})
util.Check(err)
// Start pushing buffers on these tracks
gst.CreatePipeline(webrtc.Opus, opusTrack.Samples).Start()
gst.CreatePipeline(webrtc.VP8, vp8Track.Samples).Start()
}
select {}
}