mirror of
https://github.com/pion/webrtc.git
synced 2025-10-27 01:00:35 +08:00
committed by
Michiel De Backker
parent
04d691ef96
commit
12fd9b41e4
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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), ©, ©_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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
9
examples/janus-gateway/video-room/go.mod
Normal file
9
examples/janus-gateway/video-room/go.mod
Normal 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
|
||||
)
|
||||
20
examples/janus-gateway/video-room/go.sum
Normal file
20
examples/janus-gateway/video-room/go.sum
Normal 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=
|
||||
119
examples/janus-gateway/video-room/main.go
Normal file
119
examples/janus-gateway/video-room/main.go
Normal 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 {}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user