mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-31 03:26:27 +08:00
Merge pull request #113 from go-gst/webrtc_support
initial Webrtc(-bin) support
This commit is contained in:
2
go.mod
2
go.mod
@@ -4,6 +4,6 @@ go 1.22
|
||||
|
||||
require github.com/mattn/go-pointer v0.0.1
|
||||
|
||||
require github.com/go-gst/go-glib v1.1.0
|
||||
require github.com/go-gst/go-glib v1.2.0
|
||||
|
||||
require golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1,5 +1,7 @@
|
||||
github.com/go-gst/go-glib v1.1.0 h1:XTGhwk2BWYjW/UZ08y7ojf3iPPRiYtXL0W6vJkXNKFc=
|
||||
github.com/go-gst/go-glib v1.1.0/go.mod h1:JybIYeoHNwCkHGaBf1fHNIaM4sQTrJPkPLsi7dmPNOU=
|
||||
github.com/go-gst/go-glib v1.2.0 h1:IEi5Og63V8YHBprCFiLsesRKSKWuxY0nYOMgbm7P2NI=
|
||||
github.com/go-gst/go-glib v1.2.0/go.mod h1:JybIYeoHNwCkHGaBf1fHNIaM4sQTrJPkPLsi7dmPNOU=
|
||||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||
|
||||
@@ -198,5 +198,11 @@ func marshalPromise(p unsafe.Pointer) (interface{}, error) {
|
||||
done: nil, // cannot be awaited if received from FFI
|
||||
}
|
||||
|
||||
prom.Ref()
|
||||
|
||||
runtime.SetFinalizer(prom, func(p *Promise) {
|
||||
p.Unref()
|
||||
})
|
||||
|
||||
return prom, nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:noinline
|
||||
@@ -35,9 +33,7 @@ func awaitGC() {
|
||||
}
|
||||
|
||||
func TestPromise(t *testing.T) {
|
||||
initOnce.Do(func() {
|
||||
Init(nil)
|
||||
})
|
||||
|
||||
prom := NewPromise()
|
||||
cprom := prom.Instance()
|
||||
@@ -87,12 +83,8 @@ func TestPromise(t *testing.T) {
|
||||
awaitGC()
|
||||
}
|
||||
|
||||
var initOnce sync.Once
|
||||
|
||||
func TestPromiseMarshal(t *testing.T) {
|
||||
initOnce.Do(func() {
|
||||
Init(nil)
|
||||
})
|
||||
|
||||
prom := NewPromise()
|
||||
|
||||
@@ -102,7 +94,7 @@ func TestPromiseMarshal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
receivedPromI, err := marshalPromise(unsafe.Pointer(gv.GValue))
|
||||
receivedPromI, err := gv.GoValue()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
2
gst/gstsdp/doc.go
Normal file
2
gst/gstsdp/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// gstsdp contains bindings for the gstreamer sdp library. See also https://gstreamer.freedesktop.org/documentation/sdp/index.html
|
||||
package gstsdp
|
||||
6
gst/gstsdp/gst.go.h
Normal file
6
gst/gstsdp/gst.go.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __GST_WEBRTC_GO_H__
|
||||
#define __GST_WEBRTC_GO_H__
|
||||
|
||||
#include <gst/sdp/sdp.h>
|
||||
|
||||
#endif
|
||||
94
gst/gstsdp/message.go
Normal file
94
gst/gstsdp/message.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package gstsdp
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type SDPResult C.GstSDPResult
|
||||
|
||||
const (
|
||||
SDPResultOk SDPResult = C.GST_SDP_OK
|
||||
SDPEinval SDPResult = C.GST_SDP_EINVAL
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
ptr *C.GstSDPMessage
|
||||
}
|
||||
|
||||
func wrapSDPMessageAndFinalize(sdp *C.GstSDPMessage) *Message {
|
||||
msg := &Message{
|
||||
ptr: sdp,
|
||||
}
|
||||
|
||||
// this requires that we copy the SDP message before passing it to any transfer-ownership function
|
||||
runtime.SetFinalizer(msg, func(msg *Message) {
|
||||
msg.Free()
|
||||
})
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
// NewMessageFromUnsafe creates a new SDP message from a pointer and does not finalize it
|
||||
func NewMessageFromUnsafe(ptr unsafe.Pointer) *Message {
|
||||
return &Message{
|
||||
ptr: (*C.GstSDPMessage)(ptr),
|
||||
}
|
||||
}
|
||||
|
||||
var ErrSDPInvalid = errors.New("invalid SDP")
|
||||
|
||||
func ParseSDPMessage(sdp string) (*Message, error) {
|
||||
cstr := C.CString(sdp)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
var msg *C.GstSDPMessage
|
||||
|
||||
res := SDPResult(C.gst_sdp_message_new_from_text(cstr, &msg))
|
||||
|
||||
if res != SDPResultOk || msg == nil {
|
||||
return nil, ErrSDPInvalid
|
||||
}
|
||||
|
||||
return wrapSDPMessageAndFinalize(msg), nil
|
||||
}
|
||||
|
||||
func (msg *Message) String() string {
|
||||
cstr := C.gst_sdp_message_as_text(msg.ptr)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
return C.GoString(cstr)
|
||||
}
|
||||
|
||||
// UnownedCopy creates a new copy of the SDP message that will not be finalized
|
||||
//
|
||||
// this is needed to pass the message back to C where C takes ownership of the message
|
||||
//
|
||||
// the returned SDP message will leak memory if not freed manually
|
||||
func (msg *Message) UnownedCopy() *Message {
|
||||
var newMsg *C.GstSDPMessage
|
||||
res := C.gst_sdp_message_copy(msg.ptr, &newMsg)
|
||||
|
||||
if res != C.GST_SDP_OK || newMsg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Message{
|
||||
ptr: newMsg,
|
||||
}
|
||||
}
|
||||
|
||||
// Free frees the SDP message.
|
||||
//
|
||||
// This is called automatically when the object is garbage collected.
|
||||
func (msg *Message) Free() {
|
||||
C.gst_sdp_message_free(msg.ptr)
|
||||
msg.ptr = nil
|
||||
}
|
||||
|
||||
func (msg *Message) Instance() unsafe.Pointer {
|
||||
return unsafe.Pointer(msg.ptr)
|
||||
}
|
||||
7
gst/gstsdp/pkg_config.go
Normal file
7
gst/gstsdp/pkg_config.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package gstsdp
|
||||
|
||||
/*
|
||||
#cgo pkg-config: gstreamer-sdp-1.0
|
||||
#cgo CFLAGS: -Wno-deprecated-declarations -g -Wall
|
||||
*/
|
||||
import "C"
|
||||
67
gst/gstwebrtc/data_channel.go
Normal file
67
gst/gstwebrtc/data_channel.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package gstwebrtc
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gst/go-glib/glib"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
tm := []glib.TypeMarshaler{
|
||||
{T: glib.Type(C.GST_TYPE_WEBRTC_DATA_CHANNEL), F: marshalDataChannel},
|
||||
}
|
||||
|
||||
glib.RegisterGValueMarshalers(tm)
|
||||
}
|
||||
|
||||
// DataChannel is a representation of GstWebRTCDataChannel. See https://gstreamer.freedesktop.org/documentation/webrtclib/gstwebrtc-datachannel.html?gi-language=c
|
||||
//
|
||||
// there is no constructor for DataChannel, you can get it from webrtcbin signals
|
||||
type DataChannel struct {
|
||||
*glib.Object
|
||||
}
|
||||
|
||||
func (dc *DataChannel) Close() {
|
||||
C.gst_webrtc_data_channel_close((*C.GstWebRTCDataChannel)(dc.Native()))
|
||||
}
|
||||
|
||||
func (dc *DataChannel) SendData(data []byte) error {
|
||||
var gerr *C.GError
|
||||
|
||||
addr := unsafe.SliceData(data)
|
||||
|
||||
cbytes := C.g_bytes_new(C.gconstpointer(addr), C.gsize(len(data)))
|
||||
defer C.g_bytes_unref(cbytes)
|
||||
|
||||
C.gst_webrtc_data_channel_send_data_full((*C.GstWebRTCDataChannel)(dc.Native()), cbytes, &gerr)
|
||||
|
||||
if gerr != nil {
|
||||
defer C.g_error_free((*C.GError)(gerr))
|
||||
errMsg := C.GoString(gerr.message)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToGValue implements glib.ValueTransformer
|
||||
func (dc *DataChannel) ToGValue() (*glib.Value, error) {
|
||||
val, err := glib.ValueInit(glib.Type(C.GST_TYPE_WEBRTC_DATA_CHANNEL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val.SetInstance(unsafe.Pointer(dc.GObject))
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func marshalDataChannel(p unsafe.Pointer) (interface{}, error) {
|
||||
c := C.g_value_get_object((*C.GValue)(p))
|
||||
|
||||
return &DataChannel{
|
||||
Object: glib.Take(unsafe.Pointer(c)),
|
||||
}, nil
|
||||
}
|
||||
42
gst/gstwebrtc/data_channel_test.go
Normal file
42
gst/gstwebrtc/data_channel_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package gstwebrtc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-gst/go-gst/gst"
|
||||
)
|
||||
|
||||
func TestDataChannelMarshal(t *testing.T) {
|
||||
gst.Init(nil)
|
||||
|
||||
// hack to get a valid glib.Object
|
||||
el, err := gst.NewElement("webrtcbin")
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dc := &DataChannel{
|
||||
Object: el.Object.Object,
|
||||
}
|
||||
|
||||
gv, err := dc.ToGValue()
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dcI, err := gv.GoValue()
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dc, ok := dcI.(*DataChannel)
|
||||
|
||||
if !ok {
|
||||
t.Error("Failed to convert to DataChannel")
|
||||
}
|
||||
|
||||
_ = dc
|
||||
}
|
||||
2
gst/gstwebrtc/doc.go
Normal file
2
gst/gstwebrtc/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// gstwebrtc contains bindings for the gstreamer webrtclib. See also https://gstreamer.freedesktop.org/documentation/webrtclib/index.html
|
||||
package gstwebrtc
|
||||
507
gst/gstwebrtc/enums.go
Normal file
507
gst/gstwebrtc/enums.go
Normal file
@@ -0,0 +1,507 @@
|
||||
package gstwebrtc
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
|
||||
type BundlePolicy C.GstWebRTCBundlePolicy
|
||||
|
||||
const (
|
||||
BUNDLE_POLICY_NONE BundlePolicy = C.GST_WEBRTC_BUNDLE_POLICY_NONE // none
|
||||
BUNDLE_POLICY_BALANCED BundlePolicy = C.GST_WEBRTC_BUNDLE_POLICY_BALANCED // balanced
|
||||
BUNDLE_POLICY_MAX_COMPAT BundlePolicy = C.GST_WEBRTC_BUNDLE_POLICY_MAX_COMPAT // max-compat
|
||||
BUNDLE_POLICY_MAX_BUNDLE BundlePolicy = C.GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE // max-bundle
|
||||
)
|
||||
|
||||
func (e BundlePolicy) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_BUNDLE_POLICY_NONE:
|
||||
return "none"
|
||||
case C.GST_WEBRTC_BUNDLE_POLICY_BALANCED:
|
||||
return "balanced"
|
||||
case C.GST_WEBRTC_BUNDLE_POLICY_MAX_COMPAT:
|
||||
return "max-compat"
|
||||
case C.GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE:
|
||||
return "max-bundle"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type DTLSSetup C.GstWebRTCDTLSSetup
|
||||
|
||||
const (
|
||||
DTLS_SETUP_NONE DTLSSetup = C.GST_WEBRTC_DTLS_SETUP_NONE // none
|
||||
DTLS_SETUP_ACTPASS DTLSSetup = C.GST_WEBRTC_DTLS_SETUP_ACTPASS // actpass
|
||||
DTLS_SETUP_ACTIVE DTLSSetup = C.GST_WEBRTC_DTLS_SETUP_ACTIVE // sendonly
|
||||
DTLS_SETUP_PASSIVE DTLSSetup = C.GST_WEBRTC_DTLS_SETUP_PASSIVE // recvonly
|
||||
)
|
||||
|
||||
func (e DTLSSetup) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_DTLS_SETUP_NONE:
|
||||
return "none"
|
||||
case C.GST_WEBRTC_DTLS_SETUP_ACTPASS:
|
||||
return "actpass"
|
||||
case C.GST_WEBRTC_DTLS_SETUP_ACTIVE:
|
||||
return "sendonly"
|
||||
case C.GST_WEBRTC_DTLS_SETUP_PASSIVE:
|
||||
return "recvonly"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type DTLSTransportState C.GstWebRTCDTLSTransportState
|
||||
|
||||
const (
|
||||
DTLS_TRANSPORT_STATE_NEW DTLSTransportState = C.GST_WEBRTC_DTLS_TRANSPORT_STATE_NEW // new
|
||||
DTLS_TRANSPORT_STATE_CLOSED DTLSTransportState = C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CLOSED // closed
|
||||
DTLS_TRANSPORT_STATE_FAILED DTLSTransportState = C.GST_WEBRTC_DTLS_TRANSPORT_STATE_FAILED // failed
|
||||
DTLS_TRANSPORT_STATE_CONNECTING DTLSTransportState = C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTING // connecting
|
||||
DTLS_TRANSPORT_STATE_CONNECTED DTLSTransportState = C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTED // connected
|
||||
)
|
||||
|
||||
func (e DTLSTransportState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_DTLS_TRANSPORT_STATE_NEW:
|
||||
return "new"
|
||||
case C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CLOSED:
|
||||
return "closed"
|
||||
case C.GST_WEBRTC_DTLS_TRANSPORT_STATE_FAILED:
|
||||
return "failed"
|
||||
case C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTING:
|
||||
return "connecting"
|
||||
case C.GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTED:
|
||||
return "connected"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type DataChannelState C.GstWebRTCDataChannelState
|
||||
|
||||
const (
|
||||
DATA_CHANNEL_STATE_CONNECTING DataChannelState = C.GST_WEBRTC_DATA_CHANNEL_STATE_CONNECTING // connecting
|
||||
DATA_CHANNEL_STATE_OPEN DataChannelState = C.GST_WEBRTC_DATA_CHANNEL_STATE_OPEN // open
|
||||
DATA_CHANNEL_STATE_CLOSING DataChannelState = C.GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING // closing
|
||||
DATA_CHANNEL_STATE_CLOSED DataChannelState = C.GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED // closed
|
||||
)
|
||||
|
||||
func (e DataChannelState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_DATA_CHANNEL_STATE_CONNECTING:
|
||||
return "connecting"
|
||||
case C.GST_WEBRTC_DATA_CHANNEL_STATE_OPEN:
|
||||
return "open"
|
||||
case C.GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING:
|
||||
return "closing"
|
||||
case C.GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED:
|
||||
return "closed"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type Error C.GstWebRTCError
|
||||
|
||||
const (
|
||||
ERROR_DATA_CHANNEL_FAILURE Error = C.GST_WEBRTC_ERROR_DATA_CHANNEL_FAILURE // data-channel-failure
|
||||
ERROR_DTLS_FAILURE Error = C.GST_WEBRTC_ERROR_DTLS_FAILURE // dtls-failure
|
||||
ERROR_FINGERPRINT_FAILURE Error = C.GST_WEBRTC_ERROR_FINGERPRINT_FAILURE // fingerprint-failure
|
||||
ERROR_SCTP_FAILURE Error = C.GST_WEBRTC_ERROR_SCTP_FAILURE // sctp-failure
|
||||
ERROR_SDP_SYNTAX_ERROR Error = C.GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR // sdp-syntax-error
|
||||
ERROR_HARDWARE_ENCODER_NOT_AVAILABLE Error = C.GST_WEBRTC_ERROR_HARDWARE_ENCODER_NOT_AVAILABLE // hardware-encoder-not-available
|
||||
ERROR_ENCODER_ERROR Error = C.GST_WEBRTC_ERROR_ENCODER_ERROR // encoder-error
|
||||
ERROR_INVALID_STATE Error = C.GST_WEBRTC_ERROR_INVALID_STATE // invalid-state
|
||||
ERROR_INTERNAL_FAILURE Error = C.GST_WEBRTC_ERROR_INTERNAL_FAILURE // internal-failure
|
||||
ERROR_INVALID_MODIFICATION Error = C.GST_WEBRTC_ERROR_INVALID_MODIFICATION // invalid-modification
|
||||
ERROR_TYPE_ERROR Error = C.GST_WEBRTC_ERROR_TYPE_ERROR // type-error
|
||||
)
|
||||
|
||||
func (e Error) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ERROR_DATA_CHANNEL_FAILURE:
|
||||
return "data-channel-failure"
|
||||
case C.GST_WEBRTC_ERROR_DTLS_FAILURE:
|
||||
return "dtls-failure"
|
||||
case C.GST_WEBRTC_ERROR_FINGERPRINT_FAILURE:
|
||||
return "fingerprint-failure"
|
||||
case C.GST_WEBRTC_ERROR_SCTP_FAILURE:
|
||||
return "sctp-failure"
|
||||
case C.GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR:
|
||||
return "sdp-syntax-error"
|
||||
case C.GST_WEBRTC_ERROR_HARDWARE_ENCODER_NOT_AVAILABLE:
|
||||
return "hardware-encoder-not-available"
|
||||
case C.GST_WEBRTC_ERROR_ENCODER_ERROR:
|
||||
return "encoder-error"
|
||||
case C.GST_WEBRTC_ERROR_INVALID_STATE:
|
||||
return "invalid-state"
|
||||
case C.GST_WEBRTC_ERROR_INTERNAL_FAILURE:
|
||||
return "internal-failure"
|
||||
case C.GST_WEBRTC_ERROR_INVALID_MODIFICATION:
|
||||
return "invalid-modification"
|
||||
case C.GST_WEBRTC_ERROR_TYPE_ERROR:
|
||||
return "type-error"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type FECType C.GstWebRTCFECType
|
||||
|
||||
const (
|
||||
FEC_TYPE_NONE FECType = C.GST_WEBRTC_FEC_TYPE_NONE // none
|
||||
FEC_TYPE_ULP_RED FECType = C.GST_WEBRTC_FEC_TYPE_ULP_RED // ulpfec + red
|
||||
)
|
||||
|
||||
func (e FECType) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_FEC_TYPE_NONE:
|
||||
return "none"
|
||||
case C.GST_WEBRTC_FEC_TYPE_ULP_RED:
|
||||
return "ulpfec + red"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type ICEComponent C.GstWebRTCICEComponent
|
||||
|
||||
// GST_WEBRTC_ICE_COMPONENT_RTP (0)RTP component
|
||||
// GST_WEBRTC_ICE_COMPONENT_RTCP (1)RTCP component
|
||||
|
||||
const (
|
||||
ICE_COMPONENT_RTP ICEComponent = C.GST_WEBRTC_ICE_COMPONENT_RTP // RTP component
|
||||
ICE_COMPONENT_RTCP ICEComponent = C.GST_WEBRTC_ICE_COMPONENT_RTCP // RTCP component
|
||||
)
|
||||
|
||||
func (e ICEComponent) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ICE_COMPONENT_RTP:
|
||||
return "RTP component"
|
||||
case C.GST_WEBRTC_ICE_COMPONENT_RTCP:
|
||||
return "RTCP component"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type ICEConnectionState C.GstWebRTCICEConnectionState
|
||||
|
||||
const (
|
||||
ICE_CONNECTION_STATE_NEW ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_NEW // new
|
||||
ICE_CONNECTION_STATE_CHECKING ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING // checking
|
||||
ICE_CONNECTION_STATE_CONNECTED ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED // connected
|
||||
ICE_CONNECTION_STATE_COMPLETED ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED // completed
|
||||
ICE_CONNECTION_STATE_FAILED ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_FAILED // failed
|
||||
ICE_CONNECTION_STATE_DISCONNECTED ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED // disconnected
|
||||
ICE_CONNECTION_STATE_CLOSED ICEConnectionState = C.GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED // closed
|
||||
)
|
||||
|
||||
func (e ICEConnectionState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_NEW:
|
||||
return "new"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING:
|
||||
return "checking"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED:
|
||||
return "connected"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED:
|
||||
return "completed"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_FAILED:
|
||||
return "failed"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED:
|
||||
return "disconnected"
|
||||
case C.GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED:
|
||||
return "closed"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type ICEGatheringState C.GstWebRTCICEGatheringState
|
||||
|
||||
const (
|
||||
ICE_GATHERING_STATE_NEW ICEGatheringState = C.GST_WEBRTC_ICE_GATHERING_STATE_NEW // new
|
||||
ICE_GATHERING_STATE_GATHERING ICEGatheringState = C.GST_WEBRTC_ICE_GATHERING_STATE_GATHERING // gathering
|
||||
ICE_GATHERING_STATE_COMPLETE ICEGatheringState = C.GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE // complete
|
||||
)
|
||||
|
||||
func (e ICEGatheringState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ICE_GATHERING_STATE_NEW:
|
||||
return "new"
|
||||
case C.GST_WEBRTC_ICE_GATHERING_STATE_GATHERING:
|
||||
return "gathering"
|
||||
case C.GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE:
|
||||
return "complete"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type ICERole C.GstWebRTCICERole
|
||||
|
||||
const (
|
||||
ICE_ROLE_CONTROLLED ICERole = C.GST_WEBRTC_ICE_ROLE_CONTROLLED // controlled
|
||||
ICE_ROLE_CONTROLLING ICERole = C.GST_WEBRTC_ICE_ROLE_CONTROLLING // controlling
|
||||
)
|
||||
|
||||
func (e ICERole) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ICE_ROLE_CONTROLLED:
|
||||
return "controlled"
|
||||
case C.GST_WEBRTC_ICE_ROLE_CONTROLLING:
|
||||
return "controlling"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type ICETransportPolicy C.GstWebRTCICETransportPolicy
|
||||
|
||||
const (
|
||||
ICE_TRANSPORT_POLICY_ALL ICETransportPolicy = C.GST_WEBRTC_ICE_TRANSPORT_POLICY_ALL // all
|
||||
ICE_TRANSPORT_POLICY_RELAY ICETransportPolicy = C.GST_WEBRTC_ICE_TRANSPORT_POLICY_RELAY // relay
|
||||
)
|
||||
|
||||
func (e ICETransportPolicy) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_ICE_TRANSPORT_POLICY_ALL:
|
||||
return "all"
|
||||
case C.GST_WEBRTC_ICE_TRANSPORT_POLICY_RELAY:
|
||||
return "relay"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type Kind C.GstWebRTCKind
|
||||
|
||||
const (
|
||||
UNKNOWN Kind = C.GST_WEBRTC_KIND_UNKNOWN // unknown
|
||||
AUDIO Kind = C.GST_WEBRTC_KIND_AUDIO // audio
|
||||
VIDEO Kind = C.GST_WEBRTC_KIND_VIDEO // video
|
||||
)
|
||||
|
||||
func (e Kind) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_KIND_UNKNOWN:
|
||||
return "unknown"
|
||||
case C.GST_WEBRTC_KIND_AUDIO:
|
||||
return "audio"
|
||||
case C.GST_WEBRTC_KIND_VIDEO:
|
||||
return "video"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type PeerConnectionState C.GstWebRTCPeerConnectionState
|
||||
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_NEW (0)new
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTING (1)connecting
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTED (2)connected
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_DISCONNECTED (3)disconnected
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_FAILED (4)failed
|
||||
// GST_WEBRTC_PEER_CONNECTION_STATE_CLOSED (5)closed
|
||||
|
||||
const (
|
||||
PEER_CONNECTION_STATE_NEW PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_NEW // new
|
||||
PEER_CONNECTION_STATE_CONNECTING PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTING // connecting
|
||||
PEER_CONNECTION_STATE_CONNECTED PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTED // connected
|
||||
PEER_CONNECTION_STATE_DISCONNECTED PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_DISCONNECTED // disconnected
|
||||
PEER_CONNECTION_STATE_FAILED PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_FAILED // failed
|
||||
PEER_CONNECTION_STATE_CLOSED PeerConnectionState = C.GST_WEBRTC_PEER_CONNECTION_STATE_CLOSED // closed
|
||||
)
|
||||
|
||||
func (e PeerConnectionState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_NEW:
|
||||
return "new"
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTING:
|
||||
return "connecting"
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_CONNECTED:
|
||||
return "connected"
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_DISCONNECTED:
|
||||
return "disconnected"
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_FAILED:
|
||||
return "failed"
|
||||
case C.GST_WEBRTC_PEER_CONNECTION_STATE_CLOSED:
|
||||
return "closed"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type PriorityType C.GstWebRTCPriorityType
|
||||
|
||||
const (
|
||||
PRIORITY_TYPE_VERY_LOW PriorityType = C.GST_WEBRTC_PRIORITY_TYPE_VERY_LOW // very-low
|
||||
PRIORITY_TYPE_LOW PriorityType = C.GST_WEBRTC_PRIORITY_TYPE_LOW // low
|
||||
PRIORITY_TYPE_MEDIUM PriorityType = C.GST_WEBRTC_PRIORITY_TYPE_MEDIUM // medium
|
||||
PRIORITY_TYPE_HIGH PriorityType = C.GST_WEBRTC_PRIORITY_TYPE_HIGH // high
|
||||
)
|
||||
|
||||
func (e PriorityType) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_PRIORITY_TYPE_VERY_LOW:
|
||||
return "very-low"
|
||||
case C.GST_WEBRTC_PRIORITY_TYPE_LOW:
|
||||
return "low"
|
||||
case C.GST_WEBRTC_PRIORITY_TYPE_MEDIUM:
|
||||
return "medium"
|
||||
case C.GST_WEBRTC_PRIORITY_TYPE_HIGH:
|
||||
return "high"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type RTPTransceiverDirection C.GstWebRTCRTPTransceiverDirection
|
||||
|
||||
const (
|
||||
RTP_TRANSCEIVER_DIRECTION_NONE RTPTransceiverDirection = C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE // none
|
||||
RTP_TRANSCEIVER_DIRECTION_INACTIVE RTPTransceiverDirection = C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE // inactive
|
||||
RTP_TRANSCEIVER_DIRECTION_SENDONLY RTPTransceiverDirection = C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY // sendonly
|
||||
RTP_TRANSCEIVER_DIRECTION_RECVONLY RTPTransceiverDirection = C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY // recvonly
|
||||
RTP_TRANSCEIVER_DIRECTION_SENDRECV RTPTransceiverDirection = C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV // sendrecv
|
||||
)
|
||||
|
||||
func (e RTPTransceiverDirection) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE:
|
||||
return "none"
|
||||
case C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE:
|
||||
return "inactive"
|
||||
case C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY:
|
||||
return "sendonly"
|
||||
case C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY:
|
||||
return "recvonly"
|
||||
case C.GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV:
|
||||
return "sendrecv"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type SCTPTransportState C.GstWebRTCSCTPTransportState
|
||||
|
||||
const (
|
||||
SCTP_TRANSPORT_STATE_NEW SCTPTransportState = C.GST_WEBRTC_SCTP_TRANSPORT_STATE_NEW // new
|
||||
SCTP_TRANSPORT_STATE_CONNECTING SCTPTransportState = C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTING // connecting
|
||||
SCTP_TRANSPORT_STATE_CONNECTED SCTPTransportState = C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED // connected
|
||||
SCTP_TRANSPORT_STATE_CLOSED SCTPTransportState = C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CLOSED // closed
|
||||
)
|
||||
|
||||
func (e SCTPTransportState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_SCTP_TRANSPORT_STATE_NEW:
|
||||
return "new"
|
||||
case C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTING:
|
||||
return "connecting"
|
||||
case C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED:
|
||||
return "connected"
|
||||
case C.GST_WEBRTC_SCTP_TRANSPORT_STATE_CLOSED:
|
||||
return "closed"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type SDPType C.GstWebRTCSDPType
|
||||
|
||||
const (
|
||||
SDP_TYPE_OFFER SDPType = C.GST_WEBRTC_SDP_TYPE_OFFER // offer
|
||||
SDP_TYPE_PRANSWER SDPType = C.GST_WEBRTC_SDP_TYPE_PRANSWER // pranswer
|
||||
SDP_TYPE_ANSWER SDPType = C.GST_WEBRTC_SDP_TYPE_ANSWER // answer
|
||||
SDP_TYPE_ROLLBACK SDPType = C.GST_WEBRTC_SDP_TYPE_ROLLBACK // rollback
|
||||
)
|
||||
|
||||
func (e SDPType) String() string {
|
||||
// returned string is const gchar* and must not be freed
|
||||
cstring := C.gst_webrtc_sdp_type_to_string(C.GstWebRTCSDPType(e))
|
||||
|
||||
return C.GoString(cstring)
|
||||
}
|
||||
|
||||
func SDPTypeFromString(s string) SDPType {
|
||||
switch s {
|
||||
case "offer":
|
||||
return SDP_TYPE_OFFER
|
||||
case "pranswer":
|
||||
return SDP_TYPE_PRANSWER
|
||||
case "answer":
|
||||
return SDP_TYPE_ANSWER
|
||||
case "rollback":
|
||||
return SDP_TYPE_ROLLBACK
|
||||
default:
|
||||
panic("Unknown SDPType")
|
||||
}
|
||||
}
|
||||
|
||||
type SignalingState C.GstWebRTCSignalingState
|
||||
|
||||
const (
|
||||
SIGNALING_STATE_STABLE SignalingState = C.GST_WEBRTC_SIGNALING_STATE_STABLE // stable
|
||||
SIGNALING_STATE_CLOSED SignalingState = C.GST_WEBRTC_SIGNALING_STATE_CLOSED // closed
|
||||
SIGNALING_STATE_HAVE_LOCAL_OFFER SignalingState = C.GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER // have-local-offer
|
||||
SIGNALING_STATE_HAVE_REMOTE_OFFER SignalingState = C.GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER // have-remote-offer
|
||||
SIGNALING_STATE_HAVE_LOCAL_PRANSWER SignalingState = C.GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_PRANSWER // have-local-pranswer
|
||||
SIGNALING_STATE_HAVE_REMOTE_PRANSWER SignalingState = C.GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_PRANSWER // have-remote-pranswer
|
||||
)
|
||||
|
||||
func (e SignalingState) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_STABLE:
|
||||
return "stable"
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_CLOSED:
|
||||
return "closed"
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER:
|
||||
return "have-local-offer"
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER:
|
||||
return "have-remote-offer"
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_PRANSWER:
|
||||
return "have-local-pranswer"
|
||||
case C.GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_PRANSWER:
|
||||
return "have-remote-pranswer"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type StatsType C.GstWebRTCStatsType
|
||||
|
||||
const (
|
||||
STATS_CODEC StatsType = C.GST_WEBRTC_STATS_CODEC // codec
|
||||
STATS_INBOUND_RTP StatsType = C.GST_WEBRTC_STATS_INBOUND_RTP // inbound-rtp
|
||||
STATS_OUTBOUND_RTP StatsType = C.GST_WEBRTC_STATS_OUTBOUND_RTP // outbound-rtp
|
||||
STATS_REMOTE_INBOUND_RTP StatsType = C.GST_WEBRTC_STATS_REMOTE_INBOUND_RTP // remote-inbound-rtp
|
||||
STATS_REMOTE_OUTBOUND_RTP StatsType = C.GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP // remote-outbound-rtp
|
||||
STATS_CSRC StatsType = C.GST_WEBRTC_STATS_CSRC // csrc
|
||||
STATS_PEER_CONNECTION StatsType = C.GST_WEBRTC_STATS_PEER_CONNECTION // peer-connection
|
||||
STATS_DATA_CHANNEL StatsType = C.GST_WEBRTC_STATS_DATA_CHANNEL // data-channel
|
||||
STATS_STREAM StatsType = C.GST_WEBRTC_STATS_STREAM // stream
|
||||
STATS_TRANSPORT StatsType = C.GST_WEBRTC_STATS_TRANSPORT // transport
|
||||
STATS_CANDIDATE_PAIR StatsType = C.GST_WEBRTC_STATS_CANDIDATE_PAIR // candidate-pair
|
||||
STATS_LOCAL_CANDIDATE StatsType = C.GST_WEBRTC_STATS_LOCAL_CANDIDATE // local-candidate
|
||||
STATS_REMOTE_CANDIDATE StatsType = C.GST_WEBRTC_STATS_REMOTE_CANDIDATE // remote-candidate
|
||||
STATS_CERTIFICATE StatsType = C.GST_WEBRTC_STATS_CERTIFICATE // certificate
|
||||
)
|
||||
|
||||
func (e StatsType) String() string {
|
||||
switch e {
|
||||
case C.GST_WEBRTC_STATS_CODEC:
|
||||
return "codec"
|
||||
case C.GST_WEBRTC_STATS_INBOUND_RTP:
|
||||
return "inbound-rtp"
|
||||
case C.GST_WEBRTC_STATS_OUTBOUND_RTP:
|
||||
return "outbound-rtp"
|
||||
case C.GST_WEBRTC_STATS_REMOTE_INBOUND_RTP:
|
||||
return "remote-inbound-rtp"
|
||||
case C.GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP:
|
||||
return "remote-outbound-rtp"
|
||||
case C.GST_WEBRTC_STATS_CSRC:
|
||||
return "csrc"
|
||||
case C.GST_WEBRTC_STATS_PEER_CONNECTION:
|
||||
return "peer-connection"
|
||||
case C.GST_WEBRTC_STATS_DATA_CHANNEL:
|
||||
return "data-channel"
|
||||
case C.GST_WEBRTC_STATS_STREAM:
|
||||
return "stream"
|
||||
case C.GST_WEBRTC_STATS_TRANSPORT:
|
||||
return "transport"
|
||||
case C.GST_WEBRTC_STATS_CANDIDATE_PAIR:
|
||||
return "candidate-pair"
|
||||
case C.GST_WEBRTC_STATS_LOCAL_CANDIDATE:
|
||||
return "local-candidate"
|
||||
case C.GST_WEBRTC_STATS_REMOTE_CANDIDATE:
|
||||
return "remote-candidate"
|
||||
case C.GST_WEBRTC_STATS_CERTIFICATE:
|
||||
return "certificate"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
8
gst/gstwebrtc/gst.go.h
Normal file
8
gst/gstwebrtc/gst.go.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __GST_WEBRTC_GO_H__
|
||||
#define __GST_WEBRTC_GO_H__
|
||||
|
||||
#define GST_USE_UNSTABLE_API // webrtc is unstable
|
||||
|
||||
#include <gst/webrtc/webrtc.h>
|
||||
|
||||
#endif
|
||||
7
gst/gstwebrtc/pkg_config.go
Normal file
7
gst/gstwebrtc/pkg_config.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package gstwebrtc
|
||||
|
||||
/*
|
||||
#cgo pkg-config: gstreamer-webrtc-1.0
|
||||
#cgo CFLAGS: -Wno-deprecated-declarations -g -Wall
|
||||
*/
|
||||
import "C"
|
||||
45
gst/gstwebrtc/rtp_transceiver.go
Normal file
45
gst/gstwebrtc/rtp_transceiver.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package gstwebrtc
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gst/go-glib/glib"
|
||||
"github.com/go-gst/go-gst/gst"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
tm := []glib.TypeMarshaler{
|
||||
{T: glib.Type(C.GST_TYPE_WEBRTC_RTP_TRANSCEIVER), F: marshalRTPTransceiver},
|
||||
}
|
||||
|
||||
glib.RegisterGValueMarshalers(tm)
|
||||
}
|
||||
|
||||
type RTPTransceiver struct {
|
||||
*gst.Object
|
||||
}
|
||||
|
||||
// ToGValue implements glib.ValueTransformer
|
||||
func (tc *RTPTransceiver) ToGValue() (*glib.Value, error) {
|
||||
val, err := glib.ValueInit(glib.Type(C.GST_TYPE_WEBRTC_RTP_TRANSCEIVER))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val.SetInstance(unsafe.Pointer(tc.Instance()))
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func wrapRTPTransceiver(p unsafe.Pointer) *RTPTransceiver {
|
||||
return &RTPTransceiver{
|
||||
Object: gst.FromGstObjectUnsafeNone(p),
|
||||
}
|
||||
}
|
||||
|
||||
func marshalRTPTransceiver(p unsafe.Pointer) (interface{}, error) {
|
||||
c := C.g_value_get_object((*C.GValue)(p))
|
||||
|
||||
return wrapRTPTransceiver(unsafe.Pointer(c)), nil
|
||||
}
|
||||
9
gst/gstwebrtc/rtp_transceiver_test.go
Normal file
9
gst/gstwebrtc/rtp_transceiver_test.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package gstwebrtc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRTPTransceiverGValueMarshal(t *testing.T) {
|
||||
t.Skip("Not implemented, because we don't have a constructor for RTPTransceiver")
|
||||
}
|
||||
120
gst/gstwebrtc/session_description.go
Normal file
120
gst/gstwebrtc/session_description.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package gstwebrtc
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gst/go-glib/glib"
|
||||
"github.com/go-gst/go-gst/gst/gstsdp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
tm := []glib.TypeMarshaler{
|
||||
{T: glib.Type(C.GST_TYPE_WEBRTC_SESSION_DESCRIPTION), F: marshalSessionDescription},
|
||||
}
|
||||
|
||||
glib.RegisterGValueMarshalers(tm)
|
||||
}
|
||||
|
||||
type SessionDescription struct {
|
||||
ptr *C.GstWebRTCSessionDescription
|
||||
}
|
||||
|
||||
func NewSessionDescription(t SDPType, sdp *gstsdp.Message) *SessionDescription {
|
||||
sd := C.gst_webrtc_session_description_new(
|
||||
C.GstWebRTCSDPType(t),
|
||||
(*C.GstSDPMessage)(sdp.UnownedCopy().Instance()),
|
||||
)
|
||||
|
||||
return wrapSessionDescriptionAndFinalize(sd)
|
||||
}
|
||||
|
||||
func wrapSessionDescriptionAndFinalize(sdp *C.GstWebRTCSessionDescription) *SessionDescription {
|
||||
sd := &SessionDescription{
|
||||
ptr: sdp,
|
||||
}
|
||||
|
||||
// this requires that we copy the SDP message before passing it to any transfer-ownership function
|
||||
runtime.SetFinalizer(sd, func(sd *SessionDescription) {
|
||||
sd.Free()
|
||||
})
|
||||
|
||||
return sd
|
||||
}
|
||||
|
||||
// W3RTCSessionDescription is used to marshal/unmarshal SessionDescription to/from JSON.
|
||||
//
|
||||
// We cannot implement the json.(Un-)Marshaler interfaces on SessionDescription directly because
|
||||
// the finalizer would run and free the memory, because the value would have to be copied.
|
||||
//
|
||||
// it complies with the WebRTC spec for SessionDescription, see https://www.w3.org/TR/webrtc/#rtcsessiondescription-class
|
||||
type W3RTCSessionDescription struct {
|
||||
Type string `json:"type"`
|
||||
Sdp string `json:"sdp"`
|
||||
}
|
||||
|
||||
// ToGstSDP converts a W3RTCSessionDescription to a SessionDescription
|
||||
func (w3SDP *W3RTCSessionDescription) ToGstSDP() (*SessionDescription, error) {
|
||||
sdp, err := gstsdp.ParseSDPMessage(w3SDP.Sdp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSessionDescription(SDPTypeFromString(w3SDP.Type), sdp), nil
|
||||
}
|
||||
|
||||
// ToW3SDP returns a W3RTCSessionDescription that can be marshaled to JSON
|
||||
func (sd *SessionDescription) ToW3SDP() W3RTCSessionDescription {
|
||||
jsonSDP := W3RTCSessionDescription{
|
||||
Type: SDPType(sd.ptr._type).String(),
|
||||
Sdp: gstsdp.NewMessageFromUnsafe(unsafe.Pointer(sd.ptr.sdp)).String(),
|
||||
}
|
||||
|
||||
return jsonSDP
|
||||
}
|
||||
|
||||
func (sd *SessionDescription) Free() {
|
||||
C.gst_webrtc_session_description_free(sd.ptr)
|
||||
}
|
||||
|
||||
// UnownedCopy creates a new copy of the SessionDescription that will not be finalized
|
||||
//
|
||||
// this is needed for passing the SessionDescription to other functions that will take ownership of it.
|
||||
//
|
||||
// used in the bindings, should not be called by application code
|
||||
func (sd *SessionDescription) UnownedCopy() *SessionDescription {
|
||||
newSD := C.gst_webrtc_session_description_copy(sd.ptr)
|
||||
|
||||
return &SessionDescription{
|
||||
ptr: newSD,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates a new copy of the SessionDescription
|
||||
func (sd *SessionDescription) Copy() *SessionDescription {
|
||||
return wrapSessionDescriptionAndFinalize(sd.UnownedCopy().ptr)
|
||||
}
|
||||
|
||||
// ToGValue implements glib.ValueTransformer
|
||||
func (sd *SessionDescription) ToGValue() (*glib.Value, error) {
|
||||
val, err := glib.ValueInit(glib.Type(C.GST_TYPE_WEBRTC_SESSION_DESCRIPTION))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val.SetBoxed(unsafe.Pointer(sd.ptr))
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func marshalSessionDescription(p unsafe.Pointer) (interface{}, error) {
|
||||
c := C.g_value_get_boxed((*C.GValue)(p))
|
||||
|
||||
// we don't own this memory, so we need to copy it to prevent other code from freeing it
|
||||
ref := &SessionDescription{
|
||||
ptr: (*C.GstWebRTCSessionDescription)(c),
|
||||
}
|
||||
|
||||
return ref.Copy(), nil
|
||||
}
|
||||
58
gst/gstwebrtc/session_description_test.go
Normal file
58
gst/gstwebrtc/session_description_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package gstwebrtc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-gst/go-gst/gst/gstsdp"
|
||||
"github.com/go-gst/go-gst/gst/gstwebrtc"
|
||||
)
|
||||
|
||||
func TestSessionDescriptionGValueMarshal(t *testing.T) {
|
||||
sdp, err := gstsdp.ParseSDPMessage("v=0\nm=audio 4000 RTP/AVP 111\na=rtpmap:111 OPUS/48000/2\nm=video 4000 RTP/AVP 96\na=rtpmap:96 VP8/90000\na=my-sdp-value")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sd := gstwebrtc.NewSessionDescription(gstwebrtc.SDP_TYPE_OFFER, sdp)
|
||||
|
||||
gv, err := sd.ToGValue()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sdI, err := gv.GoValue()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sd, ok := sdI.(*gstwebrtc.SessionDescription)
|
||||
|
||||
if !ok {
|
||||
t.Fatal("Failed to convert to SessionDescription")
|
||||
}
|
||||
|
||||
_ = sd
|
||||
}
|
||||
|
||||
func TestSessionDescriptionJSONMarshal(t *testing.T) {
|
||||
sdp, err := gstsdp.ParseSDPMessage("v=0\nm=audio 4000 RTP/AVP 111\na=rtpmap:111 OPUS/48000/2\nm=video 4000 RTP/AVP 96\na=rtpmap:96 VP8/90000\na=my-sdp-value")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sd := gstwebrtc.NewSessionDescription(gstwebrtc.SDP_TYPE_OFFER, sdp)
|
||||
|
||||
w3 := sd.ToW3SDP()
|
||||
|
||||
sd, err = w3.ToGstSDP()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_ = sd
|
||||
}
|
||||
Reference in New Issue
Block a user