-
Notifications
You must be signed in to change notification settings - Fork 256
/
Copy pathbridge.go
112 lines (98 loc) · 2.7 KB
/
bridge.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
// c-data-channels shows how to mix C and Go code
package main
/*
#include <stddef.h>
#include <stdint.h>
typedef struct GoDataChannelMessage
{
// bool in cgo is really weird, so it's simpler to just use classic int as bool
int is_string;
void *data;
size_t data_len;
} GoDataChannelMessage;
typedef uint16_t GoDataChannel;
typedef void (*GoOnDataChannelFunc)(GoDataChannel);
typedef void (*GoOnOpenFunc)(GoDataChannel);
typedef void (*GoOnMessageFunc)(GoDataChannel, GoDataChannelMessage);
// Calling C function pointers is currently not supported, however you can
// declare Go variables which hold C function pointers and pass them back
// and forth between Go and C. C code may call function pointers received from Go.
// Reference: https://golang.org/cmd/cgo/#hdr-Go_references_to_C
inline void bridge_on_data_channel(GoOnDataChannelFunc cb, GoDataChannel d)
{
cb(d);
}
inline void bridge_on_open(GoOnOpenFunc cb, GoDataChannel d)
{
cb(d);
}
inline void bridge_on_message(GoOnMessageFunc cb, GoDataChannel d, GoDataChannelMessage msg)
{
cb(d, msg);
}
*/
import "C"
import (
"github.com/pion/webrtc/v4"
)
// nolint
var store = map[C.GoDataChannel]*webrtc.DataChannel{}
// nolint
//
//export GoRun
func GoRun(f C.GoOnDataChannelFunc) {
Run(func(d *webrtc.DataChannel) {
// Since cgo doesn't allow storing Go pointers in C, we need to store some data in C
// that can tell Go how to get webrtc.DataChannel later. So, here we simply use data channel's
// id, which is just a simple 16 unsigned int that we can pass easily from/to C.
id := C.GoDataChannel(*d.ID())
store[id] = d
C.bridge_on_data_channel(f, id)
})
}
// nolint
//
//export GoOnOpen
func GoOnOpen(d C.GoDataChannel, f C.GoOnOpenFunc) {
// get the actual DataChannel using a unique id
dc := store[d]
dc.OnOpen(func() {
C.bridge_on_open(f, d)
})
}
// nolint
//
//export GoOnMessage
func GoOnMessage(d C.GoDataChannel, f C.GoOnMessageFunc) {
dc := store[d]
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
var isString int
// Since C interprets non-zero to be true, we can simply set isString to be 1
// or any non-zero value to make C to think that isString is true
if msg.IsString {
isString = 1
}
cMsg := C.GoDataChannelMessage{
is_string: C.int(isString),
data: C.CBytes(msg.Data),
data_len: C.ulong(len(msg.Data)),
}
C.bridge_on_message(f, d, cMsg)
})
}
// nolint
//
//export GoSendText
func GoSendText(d C.GoDataChannel, t *C.char) {
dc := store[d]
_ = dc.SendText(C.GoString(t))
}
// nolint
//
//export GoLabel
func GoLabel(d C.GoDataChannel) *C.char {
dc := store[d]
return C.CString(dc.Label())
}