diff --git a/build.sh b/build.sh index 33453f2..2c89e5e 100755 --- a/build.sh +++ b/build.sh @@ -9,7 +9,7 @@ DEPOT_TOOLS_DIR="$THIRD_PARTY_DIR/depot_tools" OS=$(go env GOOS) ARCH=$(go env GOARCH) CONFIG="Release" -COMMIT="c279861207c5b15fc51069e96595782350e0ac12" # branch-heads/58 +COMMIT="6f21dc245689c29730002da09534a8d275e6aa92" # branch-heads/62 # Values are from, # https://github.com/golang/go/blob/master/src/go/build/syslist.go diff --git a/ctestenums-win.go b/ctestenums-win.go new file mode 100644 index 0000000..efd5aa4 --- /dev/null +++ b/ctestenums-win.go @@ -0,0 +1,32 @@ +// +build windows + +package webrtc + +/* +#ifdef _WIN32 +int CGO_IceTransportPolicyNone = 0; +int CGO_IceTransportPolicyRelay = 0; +int CGO_IceTransportPolicyNoHost = 0; +int CGO_IceTransportPolicyAll = 0; +int CGO_BundlePolicyBalanced = 0; +int CGO_BundlePolicyMaxBundle = 0; +int CGO_BundlePolicyMaxCompat = 0; +int CGO_SignalingStateStable = 0; +int CGO_SignalingStateHaveLocalOffer = 0; +int CGO_SignalingStateHaveLocalPrAnswer = 0; +int CGO_SignalingStateHaveRemoteOffer = 0; +int CGO_SignalingStateHaveRemotePrAnswer = 0; +int CGO_SignalingStateClosed = 0; +int CGO_IceConnectionStateNew = 0; +int CGO_IceConnectionStateChecking = 0; +int CGO_IceConnectionStateConnected = 0; +int CGO_IceConnectionStateCompleted = 0; +int CGO_IceConnectionStateFailed = 0; +int CGO_IceConnectionStateDisconnected = 0; +int CGO_IceConnectionStateClosed = 0; +int CGO_IceGatheringStateNew = 0; +int CGO_IceGatheringStateGathering = 0; +int CGO_IceGatheringStateComplete = 0; +#endif +*/ +import "C" diff --git a/ctestenums.cc b/ctestenums.cc index ab2e37a..f500af1 100644 --- a/ctestenums.cc +++ b/ctestenums.cc @@ -1,3 +1,4 @@ +#if !_WIN32 || WIN_WEBRTC #include "ctestenums.h" #include "webrtc/api/peerconnectioninterface.h" @@ -64,3 +65,4 @@ const int CGO_IceGatheringStateGathering = PeerConnectionInterface::IceGatheringState::kIceGatheringGathering; const int CGO_IceGatheringStateComplete = PeerConnectionInterface::IceGatheringState::kIceGatheringComplete; +#endif \ No newline at end of file diff --git a/ctestenums.h b/ctestenums.h index 13ec2b7..ecae325 100644 --- a/ctestenums.h +++ b/ctestenums.h @@ -1,7 +1,13 @@ +#ifndef NOMINMAX +# define NOMINMAX +#endif + #ifndef _C_TEST_ENUMS_H_ #define _C_TEST_ENUMS_H_ +#ifndef _WIN32 #define WEBRTC_POSIX 1 +#endif #ifdef __cplusplus extern "C" { diff --git a/datachannel-win.c b/datachannel-win.c new file mode 100644 index 0000000..226802b --- /dev/null +++ b/datachannel-win.c @@ -0,0 +1,81 @@ +#ifdef _WIN32 +#include <_cgo_export.h> // Allow calling certain Go functions. + +#include "datachannel.h" + +int CGO_DataStateConnecting = 0; +int CGO_DataStateOpen = 0; +int CGO_DataStateClosing = 0; +int CGO_DataStateClosed = 0; + +void CGO_DataChannelInit() { + CGO_DataStateConnecting = dll_DataStateConnecting(); + CGO_DataStateOpen = dll_DataStateOpen(); + CGO_DataStateClosing = dll_DataStateClosing(); + CGO_DataStateClosed = dll_DataStateClosed(); +} + +int CGO_Channel_BufferedAmount(CGO_Channel channel) { + return dll_Channel_BufferedAmount(channel); +} + +int CGO_Channel_ID(CGO_Channel channel) { + return dll_Channel_ID(channel); +} + +const char *CGO_Channel_Label(CGO_Channel channel) { + return (const char*)dll_Channel_Label(channel); +} + +const char *CGO_Channel_Protocol(CGO_Channel channel) { + return (const char*)dll_Channel_Protocol(channel); +} + +CGO_Channel CGO_Channel_RegisterObserver(void *o, int goChannel) { + return dll_Channel_RegisterObserver(o, goChannel); +} + +int CGO_Channel_MaxRetransmitTime(CGO_Channel channel) { + return dll_Channel_MaxRetransmitTime(channel); +} + +int CGO_Channel_MaxRetransmits(CGO_Channel channel) { + return dll_Channel_MaxRetransmits(channel); +} + +int CGO_Channel_ReadyState(CGO_Channel channel) { + return dll_Channel_ReadyState(channel); +} + +const bool CGO_Channel_Negotiated(CGO_Channel channel) { + return dll_Channel_Negotiated(channel); +} + +void* CGO_getFakeDataChannel() { + return dll_getFakeDataChannel(); +} + +const bool CGO_Channel_Ordered(CGO_Channel channel) { + return dll_Channel_Ordered(channel); +} + +void CGO_Channel_Close(CGO_Channel channel) { + return dll_Channel_Close(channel); +} + +void CGO_Channel_Send(CGO_Channel channel, void *data, int size, bool binary) { + return dll_Channel_Send( channel, data, size, binary); +} + +void CGO_fakeBufferAmount(CGO_Channel channel, int amount) { + return dll_fakeBufferAmount(channel, amount); +} + +void CGO_fakeMessage(CGO_Channel channel, void *data, int size) { + return dll_fakeMessage(channel, data, size); +} + +void CGO_fakeStateChange(CGO_Channel channel, int state) { + return dll_fakeStateChange(channel, state); +} +#endif \ No newline at end of file diff --git a/datachannel.cc b/datachannel.cc index 46afd86..2ca40af 100644 --- a/datachannel.cc +++ b/datachannel.cc @@ -1,3 +1,4 @@ +#if !_WIN32 || WIN_WEBRTC #include "datachannel.h" #include "datachannel.hpp" @@ -182,7 +183,8 @@ void CGO_fakeBufferAmount(CGO_Channel channel, int amount) { dc->SetBufferedAmount(amount); } -const int CGO_DataStateConnecting = DataChannelInterface::DataState::kConnecting; -const int CGO_DataStateOpen = DataChannelInterface::DataState::kOpen; -const int CGO_DataStateClosing = DataChannelInterface::DataState::kClosing; -const int CGO_DataStateClosed = DataChannelInterface::DataState::kClosed; +int CGO_DataStateConnecting = DataChannelInterface::DataState::kConnecting; +int CGO_DataStateOpen = DataChannelInterface::DataState::kOpen; +int CGO_DataStateClosing = DataChannelInterface::DataState::kClosing; +int CGO_DataStateClosed = DataChannelInterface::DataState::kClosed; +#endif \ No newline at end of file diff --git a/datachannel.h b/datachannel.h index eeec66b..d828bd2 100644 --- a/datachannel.h +++ b/datachannel.h @@ -1,7 +1,13 @@ +#ifndef NOMINMAX +# define NOMINMAX +#endif + #ifndef _C_DATACHANNEL_H_ #define _C_DATACHANNEL_H_ +#ifndef _WIN32 #define WEBRTC_POSIX 1 +#endif #include @@ -30,10 +36,10 @@ extern "C" { int CGO_Channel_ReadyState(CGO_Channel); int CGO_Channel_BufferedAmount(CGO_Channel channel); - extern const int CGO_DataStateConnecting; - extern const int CGO_DataStateOpen; - extern const int CGO_DataStateClosing; - extern const int CGO_DataStateClosed; + extern int CGO_DataStateConnecting; + extern int CGO_DataStateOpen; + extern int CGO_DataStateClosing; + extern int CGO_DataStateClosed; // Testing helpers: CGO_Channel CGO_getFakeDataChannel(); @@ -41,6 +47,9 @@ extern "C" { void CGO_fakeStateChange(CGO_Channel channel, int state); void CGO_fakeBufferAmount(CGO_Channel channel, int amount); +// Windows init +void CGO_DataChannelInit(); + #ifdef __cplusplus } #endif diff --git a/datachannel.hpp b/datachannel.hpp index 440b695..6e87f33 100644 --- a/datachannel.hpp +++ b/datachannel.hpp @@ -1,12 +1,18 @@ #ifndef _DATACHANNEL_H_ #define _DATACHANNEL_H_ -#include <_cgo_export.h> // Allow calling certain Go functions. + #include #include "webrtc/api/peerconnectioninterface.h" #include "webrtc/api/datachannelinterface.h" +#ifdef _WIN32 +#include "externs.h" +#else +#include <_cgo_export.h> // Allow calling certain Go functions. +#endif + typedef rtc::scoped_refptr DataChannel; class CGoDataChannelObserver diff --git a/datachannel_test.go b/datachannel_test.go index 9fc5678..0abca91 100644 --- a/datachannel_test.go +++ b/datachannel_test.go @@ -10,10 +10,10 @@ import ( func TestDataStateEnums(t *testing.T) { Convey("Enum: DataState", t, func() { - So(DataStateConnecting, ShouldEqual, _cgoDataStateConnecting) - So(DataStateOpen, ShouldEqual, _cgoDataStateOpen) - So(DataStateClosing, ShouldEqual, _cgoDataStateClosing) - So(DataStateClosed, ShouldEqual, _cgoDataStateClosed) + So(_cgoDataStateConnecting, ShouldEqual, DataStateConnecting) + So(_cgoDataStateOpen, ShouldEqual, DataStateOpen) + So(_cgoDataStateClosing, ShouldEqual, DataStateClosing) + So(_cgoDataStateClosed, ShouldEqual, DataStateClosed) }) Convey("DataChannel", t, func() { diff --git a/datachannel_windows.go b/datachannel_windows.go new file mode 100644 index 0000000..ee3d67b --- /dev/null +++ b/datachannel_windows.go @@ -0,0 +1,124 @@ +// +build windows +package webrtc + +/* +#include "datachannel.h" +#include "string.h" +*/ +import "C" +import ( + "unsafe" +) + +//export dll_Channel_BufferedAmount +func dll_Channel_BufferedAmount(channel C.CGO_Channel) C.int { + r1, _, _ := myfuncs["dll_Channel_BufferedAmount"].Call(uintptr(channel)) + return C.int(r1) +} + +//export dll_Channel_ID +func dll_Channel_ID(channel C.CGO_Channel) C.int { + r1, _, _ := myfuncs["dll_Channel_ID"].Call(uintptr(channel)) + return C.int(r1) +} + +//export dll_Channel_Label +func dll_Channel_Label(channel C.CGO_Channel) *C.char { + r1, _, _ := myfuncs["dll_Channel_Label"].Call(uintptr(channel)) + // The caller is going to call free using C.free, that will invoke gcc's free which + // is NOT the same as MSVC's free + res := C.strdup((*C.char)(unsafe.Pointer(r1))) + myfuncs["dll_Free"].Call(r1) + return res +} + +//export dll_Channel_Protocol +func dll_Channel_Protocol(channel C.CGO_Channel) *C.char { + r1, _, _ := myfuncs["dll_Channel_Protocol"].Call(uintptr(channel)) + // The caller is going to call free using C.free, that will invoke gcc's free which + // is NOT the same as MSVC's free + res := C.strdup((*C.char)(unsafe.Pointer(r1))) + myfuncs["dll_Free"].Call(r1) + return res +} + +//export dll_Channel_RegisterObserver +func dll_Channel_RegisterObserver(o unsafe.Pointer, index C.int) unsafe.Pointer { + r1, _, _ := myfuncs["dll_Channel_RegisterObserver"].Call(uintptr(o), uintptr(index)) + return unsafe.Pointer(r1) +} + +//export dll_Channel_MaxRetransmitTime +func dll_Channel_MaxRetransmitTime(channel C.CGO_Channel) C.int { + r1, _, _ := myfuncs["dll_Channel_MaxRetransmitTime"].Call(uintptr(channel)) + return C.int(r1) +} + +//export dll_Channel_MaxRetransmits +func dll_Channel_MaxRetransmits(channel C.CGO_Channel) C.int { + r1, _, _ := myfuncs["dll_Channel_MaxRetransmits"].Call(uintptr(channel)) + return C.int(r1) +} + +//export dll_Channel_Negotiated +func dll_Channel_Negotiated(channel C.CGO_Channel) C.bool { + r1, _, _ := myfuncs["dll_Channel_Negotiated"].Call(uintptr(channel)) + res := int8(r1) + if res == 1 { + return C.bool(true) + } else { + return C.bool(false) + } +} + +//export dll_getFakeDataChannel +func dll_getFakeDataChannel() unsafe.Pointer { + r1, _, _ := myfuncs["dll_getFakeDataChannel"].Call() + return unsafe.Pointer(r1) +} + +//export dll_Channel_Ordered +func dll_Channel_Ordered(channel C.CGO_Channel) C.bool { + r1, _, _ := myfuncs["dll_Channel_Ordered"].Call(uintptr(channel)) + res := int8(r1) + if res == 1 { + return C.bool(true) + } else { + return C.bool(false) + } +} + +//export dll_Channel_ReadyState +func dll_Channel_ReadyState(channel C.CGO_Channel) C.int { + r1, _, _ := myfuncs["dll_Channel_ReadyState"].Call(uintptr(channel)) + return C.int(r1) +} + +//export dll_Channel_Close +func dll_Channel_Close(channel C.CGO_Channel) { + myfuncs["dll_Channel_Close"].Call(uintptr(channel)) +} + +//export dll_Channel_Send +func dll_Channel_Send(channel C.CGO_Channel, data unsafe.Pointer, size C.int, binary C.bool) { + var intBool = 0 + if binary == C.bool(true) { + intBool = 1 + } + myfuncs["dll_Channel_Send"].Call(uintptr(channel), uintptr(data), uintptr(size), uintptr(intBool)) +} + +//export dll_fakeBufferAmount +func dll_fakeBufferAmount(channel C.CGO_Channel, amount C.int) { + myfuncs["dll_fakeBufferAmount"].Call(uintptr(channel), uintptr(amount)) +} + +//export dll_fakeMessage +func dll_fakeMessage(channel C.CGO_Channel, data unsafe.Pointer, size C.int) { + myfuncs["dll_fakeMessage"].Call(uintptr(channel), uintptr(data), uintptr(size)) +} + +//export dll_fakeStateChange +func dll_fakeStateChange(channel C.CGO_Channel, state C.int) { + myfuncs["dll_fakeStateChange"].Call(uintptr(channel), uintptr(state)) +} diff --git a/demo/chat/chat.go b/demo/chat/chat.go index 0bc441d..e4ef864 100644 --- a/demo/chat/chat.go +++ b/demo/chat/chat.go @@ -13,6 +13,7 @@ import ( "fmt" "os" "os/signal" + "runtime" "strings" "github.com/keroserene/go-webrtc" @@ -274,7 +275,12 @@ func main() { // Input loop. for { - text, _ := reader.ReadString('\n') + text := "" + if runtime.GOOS == "windows" { + text, _ = reader.ReadString('\r') + } else { + text, _ = reader.ReadString('\n') + } switch mode { case ModeInit: if strings.HasPrefix(text, "start") { diff --git a/dllinit_windows.go b/dllinit_windows.go new file mode 100644 index 0000000..9964586 --- /dev/null +++ b/dllinit_windows.go @@ -0,0 +1,257 @@ +//+build windows +package webrtc + +/* +#include "datachannel.h" +#include "peerconnection.h" +#include "string.h" +*/ +import "C" +import ( + "sync" + "syscall" + "unsafe" +) + +var once sync.Once +var dllHandle *syscall.DLL +var myfuncs map[string]*syscall.Proc + +func LoadMyDllOnce() { + once.Do(loadMyDll) +} + +func loadMyDll() { + var err error + dllHandle, err = syscall.LoadDLL("webrtc.dll") + if err != nil { + panic(err) + } + myfuncs = make(map[string]*syscall.Proc) + funcs := []string{ + // Enums + "dll_DataStateConnecting", + "dll_DataStateOpen", + "dll_DataStateClosing", + "dll_DataStateClosed", + "dll_IceTransportPolicyNone", + "dll_IceTransportPolicyRelay", + "dll_IceTransportPolicyNoHost", + "dll_IceTransportPolicyAll", + "dll_BundlePolicyBalanced", + "dll_BundlePolicyMaxCompat", + "dll_BundlePolicyMaxBundle", + "dll_SignalingStateStable", + "dll_SignalingStateHaveLocalOffer", + "dll_SignalingStateHaveLocalPrAnswer", + "dll_SignalingStateHaveRemoteOffer", + "dll_SignalingStateHaveRemotePrAnswer", + "dll_SignalingStateClosed", + "dll_IceConnectionStateNew", + "dll_IceConnectionStateChecking", + "dll_IceConnectionStateConnected", + "dll_IceConnectionStateCompleted", + "dll_IceConnectionStateFailed", + "dll_IceConnectionStateDisconnected", + "dll_IceConnectionStateClosed", + "dll_IceGatheringStateNew", + "dll_IceGatheringStateGathering", + "dll_IceGatheringStateComplete", + + // DataChannel + "dll_Channel_ReadyState", + "dll_Channel_RegisterObserver", + "dll_getFakeDataChannel", + "dll_Channel_Label", + "dll_Channel_Ordered", + "dll_Channel_Negotiated", + "dll_Channel_Protocol", + "dll_Channel_BufferedAmount", + "dll_Channel_MaxRetransmitTime", + "dll_Channel_MaxRetransmits", + "dll_Channel_ID", + "dll_Channel_Send", + "dll_Channel_Close", + "dll_fakeMessage", + "dll_fakeStateChange", + "dll_fakeBufferAmount", + "SetCallbackChannelOnMessage", + "SetCallbackChannelOnStateChange", + "SetCallbackChannelOnBufferedAmountChange", + "SetCallbackOnIceCandidate", + "SetCallbackOnIceCandidateError", + "SetCallbackOnSignalingStateChange", + "SetCallbackOnNegotiationNeeded", + "SetCallbackOnIceConnectionStateChange", + "SetCallbackOnConnectionStateChange", + "SetCallbackOnIceGatheringStateChange", + "SetCallbackOnDataChannel", + + // PeerConnection + "dll_InitializePeer", + "dll_SetConfiguration", + "dll_Close", + "dll_CreatePeerConnection", + "dll_CreateOffer", + "dll_CreateAnswer", + "dll_SetLocalDescription", + "dll_SetRemoteDescription", + "dll_GetLocalDescription", + "dll_GetRemoteDescription", + "dll_GetSignalingState", + "dll_IceConnectionState", + "dll_IceGatheringState", + "dll_AddIceCandidate", + "dll_DeserializeSDP", + "dll_SerializeSDP", + "dll_CreateDataChannel", + "dll_fakeIceCandidateError", + + // Misc + "dll_Free", + } + for _, v := range funcs { + proc, err := dllHandle.FindProc(v) + if err != nil { + panic(err) + } + myfuncs[v] = proc + } + + // Initialize the enums + _cgoIceTransportPolicyNone = dll_LoadInt("dll_IceTransportPolicyNone") + _cgoIceTransportPolicyRelay = dll_LoadInt("dll_IceTransportPolicyRelay") + _cgoIceTransportPolicyNoHost = dll_LoadInt("dll_IceTransportPolicyNoHost") + _cgoIceTransportPolicyAll = dll_LoadInt("dll_IceTransportPolicyAll") + _cgoBundlePolicyBalanced = dll_LoadInt("dll_BundlePolicyBalanced") + _cgoBundlePolicyMaxCompat = dll_LoadInt("dll_BundlePolicyMaxCompat") + _cgoBundlePolicyMaxBundle = dll_LoadInt("dll_BundlePolicyMaxBundle") + _cgoSignalingStateStable = dll_LoadInt("dll_SignalingStateStable") + _cgoSignalingStateHaveLocalOffer = dll_LoadInt("dll_SignalingStateHaveLocalOffer") + _cgoSignalingStateHaveLocalPrAnswer = dll_LoadInt("dll_SignalingStateHaveLocalPrAnswer") + _cgoSignalingStateHaveRemoteOffer = dll_LoadInt("dll_SignalingStateHaveRemoteOffer") + _cgoSignalingStateHaveRemotePrAnswer = dll_LoadInt("dll_SignalingStateHaveRemotePrAnswer") + _cgoSignalingStateClosed = dll_LoadInt("dll_SignalingStateClosed") + + _cgoIceConnectionStateNew = dll_LoadInt("dll_IceConnectionStateNew") + _cgoIceConnectionStateChecking = dll_LoadInt("dll_IceConnectionStateChecking") + _cgoIceConnectionStateConnected = dll_LoadInt("dll_IceConnectionStateConnected") + _cgoIceConnectionStateCompleted = dll_LoadInt("dll_IceConnectionStateCompleted") + _cgoIceConnectionStateFailed = dll_LoadInt("dll_IceConnectionStateFailed") + _cgoIceConnectionStateDisconnected = dll_LoadInt("dll_IceConnectionStateDisconnected") + _cgoIceConnectionStateClosed = dll_LoadInt("dll_IceConnectionStateClosed") + _cgoIceGatheringStateNew = dll_LoadInt("dll_IceGatheringStateNew") + _cgoIceGatheringStateGathering = dll_LoadInt("dll_IceGatheringStateGathering") + _cgoIceGatheringStateComplete = dll_LoadInt("dll_IceGatheringStateComplete") + + C.CGO_DataChannelInit() + + // Setup the callbacks + cb := syscall.NewCallback(func(goChannel int, data unsafe.Pointer, size int) uintptr { + cgoChannelOnMessage(goChannel, data, size) + return 0 + }) + myfuncs["SetCallbackChannelOnMessage"].Call(cb) + cb = syscall.NewCallback(func(goChannel int) uintptr { + cgoChannelOnStateChange(goChannel) + return 0 + }) + myfuncs["SetCallbackChannelOnStateChange"].Call(cb) + cb = syscall.NewCallback(func(goChannel int, amount int) uintptr { + cgoChannelOnBufferedAmountChange(goChannel, amount) + return 0 + }) + myfuncs["SetCallbackChannelOnBufferedAmountChange"].Call(cb) + + // We cannot pass a struct to NewCallback(), so we must use a pointer + cb = syscall.NewCallback(func(p int, cIC *C.CGO_IceCandidate) uintptr { + cgoOnIceCandidate(p, *cIC) + return 0 + }) + myfuncs["SetCallbackOnIceCandidate"].Call(cb) + + cb = syscall.NewCallback(func(p int) uintptr { + cgoOnIceCandidateError(p) + return 0 + }) + myfuncs["SetCallbackOnIceCandidateError"].Call(cb) + + cb = syscall.NewCallback(func(p int, s SignalingState) uintptr { + cgoOnSignalingStateChange(p, s) + return 0 + }) + myfuncs["SetCallbackOnSignalingStateChange"].Call(cb) + + cb = syscall.NewCallback(func(p int) uintptr { + cgoOnNegotiationNeeded(p) + return 0 + }) + myfuncs["SetCallbackOnNegotiationNeeded"].Call(cb) + + cb = syscall.NewCallback(func(p int, s IceConnectionState) uintptr { + cgoOnIceConnectionStateChange(p, s) + return 0 + }) + myfuncs["SetCallbackOnIceConnectionStateChange"].Call(cb) + + cb = syscall.NewCallback(func(p int, s IceConnectionState) uintptr { + cgoOnConnectionStateChange(p, s) + return 0 + }) + myfuncs["SetCallbackOnConnectionStateChange"].Call(cb) + + cb = syscall.NewCallback(func(p int, s IceGatheringState) uintptr { + cgoOnIceGatheringStateChange(p, s) + return 0 + }) + myfuncs["SetCallbackOnIceGatheringStateChange"].Call(cb) + + cb = syscall.NewCallback(func(p int, o unsafe.Pointer) uintptr { + cgoOnDataChannel(p, o) + return 0 + }) + myfuncs["SetCallbackOnDataChannel"].Call(cb) + +} + +func init() { + LoadMyDllOnce() +} + +//*********** Enums are all initialized here +//export dll_DataStateConnecting +func dll_DataStateConnecting() C.int { + r1, _, _ := myfuncs["dll_DataStateConnecting"].Call() + // Variables (consts) need to be set explicitly here + _cgoDataStateConnecting = int(r1) + return C.int(r1) +} + +//export dll_DataStateOpen +func dll_DataStateOpen() C.int { + r1, _, _ := myfuncs["dll_DataStateOpen"].Call() + // Variables (consts) need to be set explicitly here + _cgoDataStateOpen = int(r1) + return C.int(r1) +} + +//export dll_DataStateClosing +func dll_DataStateClosing() C.int { + r1, _, _ := myfuncs["dll_DataStateClosing"].Call() + // Variables (consts) need to be set explicitly here + _cgoDataStateClosing = int(r1) + return C.int(r1) +} + +//export dll_DataStateClosed +func dll_DataStateClosed() C.int { + r1, _, _ := myfuncs["dll_DataStateClosed"].Call() + // Variables (consts) need to be set explicitly here + _cgoDataStateClosed = int(r1) + return C.int(r1) +} + +func dll_LoadInt(procName string) int { + r1, _, _ := myfuncs[procName].Call() + return int(r1) +} diff --git a/lib/libwebrtc-linux-amd64-magic.a b/lib/libwebrtc-linux-amd64-magic.a index 87a983a..f9b94f4 100644 Binary files a/lib/libwebrtc-linux-amd64-magic.a and b/lib/libwebrtc-linux-amd64-magic.a differ diff --git a/lib/libwebrtc_full.lib b/lib/libwebrtc_full.lib new file mode 100644 index 0000000..8005d88 Binary files /dev/null and b/lib/libwebrtc_full.lib differ diff --git a/peerconnection-win.c b/peerconnection-win.c new file mode 100644 index 0000000..7cdf781 --- /dev/null +++ b/peerconnection-win.c @@ -0,0 +1,75 @@ +#ifdef _WIN32 +#include <_cgo_export.h> // Allow calling certain Go functions. + +int CGO_AddIceCandidate(CGO_Peer cgoPeer, CGO_IceCandidate *cgoIC) { + return dll_AddIceCandidate(cgoPeer, cgoIC); +} + +CGO_sdpString CGO_CreateAnswer(CGO_Peer cgoPeer) { + return dll_CreateAnswer(cgoPeer); +} + +void* CGO_CreateDataChannel(CGO_Peer cgoPeer, char *label, void *dict) { + return dll_CreateDataChannel(cgoPeer, label, dict); +} + +CGO_sdpString CGO_CreateOffer(CGO_Peer cgoPeer) { + return dll_CreateOffer(cgoPeer); +} + +int CGO_CreatePeerConnection(CGO_Peer cgoPeer, CGO_Configuration *cgoConfig) { + return dll_CreatePeerConnection(cgoPeer, cgoConfig); +} + +CGO_sdp CGO_GetLocalDescription(CGO_Peer cgoPeer) { + return dll_GetLocalDescription(cgoPeer); +} + +CGO_sdp CGO_GetRemoteDescription(CGO_Peer cgoPeer) { + return dll_GetRemoteDescription(cgoPeer); +} + +int CGO_GetSignalingState(CGO_Peer cgoPeer) { + return dll_GetSignalingState(cgoPeer); +} + +int CGO_IceConnectionState(CGO_Peer cgoPeer) { + return dll_IceConnectionState(cgoPeer); +} + +int CGO_IceGatheringState(CGO_Peer cgoPeer) { + return dll_IceGatheringState(cgoPeer); +} + +CGO_Peer CGO_InitializePeer(int goPc) { + return dll_InitializePeer(goPc); +} + +int CGO_SetConfiguration(CGO_Peer cgoPeer, CGO_Configuration* cgoConfig) { + return dll_SetConfiguration(cgoPeer, cgoConfig); +} + +int CGO_SetLocalDescription(CGO_Peer cgoPeer, CGO_sdp sdp) { + return dll_SetLocalDescription(cgoPeer, sdp); +} + +int CGO_SetRemoteDescription(CGO_Peer cgoPeer, CGO_sdp sdp) { + return dll_SetRemoteDescription(cgoPeer, sdp); +} + +void CGO_Close(CGO_Peer peer) { + return dll_Close(peer); +} + +void CGO_fakeIceCandidateError(CGO_Peer peer) { + return dll_fakeIceCandidateError(peer); +} + +CGO_sdp CGO_DeserializeSDP(const char *type, const char *msg) { + return dll_DeserializeSDP((char*)type, (char*)msg); +} + +CGO_sdpString CGO_SerializeSDP(CGO_sdp sdp) { + return dll_SerializeSDP(sdp); +} +#endif \ No newline at end of file diff --git a/peerconnection.cc b/peerconnection.cc index 275007a..e78bccc 100644 --- a/peerconnection.cc +++ b/peerconnection.cc @@ -1,3 +1,5 @@ +#if !_WIN32 || WIN_WEBRTC + /** * C wrapper around the C++ webrtc::PeerConnectionInterface and related, which * allows compatibility with CGO's requirements so that everything may @@ -41,6 +43,10 @@ class Peer : public PeerConnectionObserver, public CreateSessionDescriptionObserver { public: + Peer() { + signalling_thread_ = NULL; + worker_thread_ = NULL; + } // Expected to be called before anything else happens for Peer. bool Initialize() { @@ -56,7 +62,7 @@ class Peer signalling_thread_->Start(); // Must start before being passed to worker_thread_->Start(); // PeerConnectionFactory. - this->fake_audio_ = FakeAudioCaptureModule::Create(); + this->fake_audio_ = NULL;//FakeAudioCaptureModule::Create(); pc_factory = CreatePeerConnectionFactory( worker_thread_, signalling_thread_, @@ -196,7 +202,7 @@ class Peer // Keep track of Peers in global scope to prevent deallocation, due to the // required scoped_refptr from implementing the Observer interface. -vector> localPeers; +map> localPeers; class PeerSDPObserver : public SetSessionDescriptionObserver { public: @@ -227,7 +233,7 @@ class PeerSDPObserver : public SetSessionDescriptionObserver { CGO_Peer CGO_InitializePeer(int goPc) { rtc::scoped_refptr localPeer = new rtc::RefCountedObject(); localPeer->Initialize(); - localPeers.push_back(localPeer); + localPeers[goPc] = localPeer; localPeer->goPeerConnection = goPc; return localPeer; } @@ -341,7 +347,8 @@ CGO_sdpString CGO_SerializeSDP(CGO_sdp sdp) { // Given a fully serialized SDP string |msg|, return a CGO sdp object. CGO_sdp CGO_DeserializeSDP(const char *type, const char *msg) { // TODO: Maybe use an enum instead of string for type. - auto jsep_sdp = new JsepSessionDescription(type); + const string typeS = string(type); + auto jsep_sdp = new JsepSessionDescription(typeS); SdpParseError err; std::string msg_str(msg); SdpDeserialize(msg_str, jsep_sdp, &err); @@ -450,6 +457,10 @@ void CGO_Close(CGO_Peer peer) { auto cPeer = (Peer*)peer; cPeer->pc_->Close(); CGO_DBG("Closed PeerConnection."); + auto iter = localPeers.find(cPeer->goPeerConnection); + if (iter != localPeers.end()) { + localPeers.erase(iter); + } } @@ -461,3 +472,4 @@ void CGO_fakeIceCandidateError(CGO_Peer peer) { cPeer->OnIceConnectionChange( PeerConnectionInterface::IceConnectionState::kIceConnectionFailed); } +#endif \ No newline at end of file diff --git a/peerconnection.h b/peerconnection.h index 29a84a0..35e5940 100644 --- a/peerconnection.h +++ b/peerconnection.h @@ -1,7 +1,13 @@ +#ifndef NOMINMAX +#define NOMINMAX +#endif + #ifndef _C_PEERCONNECTION_H_ #define _C_PEERCONNECTION_H_ +#ifndef _WIN32 #define WEBRTC_POSIX 1 +#endif #ifdef __cplusplus extern "C" { @@ -73,6 +79,10 @@ extern "C" { // Test helpers void CGO_fakeIceCandidateError(CGO_Peer peer); +#ifdef WIN_WEBRTC +extern void cgoOnIceCandidate(int, CGO_IceCandidate); +#endif + #ifdef __cplusplus } #endif diff --git a/peerconnection_test.go b/peerconnection_test.go index 4ada5a1..339976a 100644 --- a/peerconnection_test.go +++ b/peerconnection_test.go @@ -9,25 +9,25 @@ import ( func TestIceGatheringStateEnums(t *testing.T) { Convey(`Enum: IceGatheringState values should match C++ webrtc::PeerConnectionInterface values`, t, func() { - So(IceGatheringStateNew, ShouldEqual, _cgoIceGatheringStateNew) - So(IceGatheringStateGathering, ShouldEqual, _cgoIceGatheringStateGathering) - So(IceGatheringStateComplete, ShouldEqual, _cgoIceGatheringStateComplete) + So(_cgoIceGatheringStateNew, ShouldEqual, IceGatheringStateNew) + So(_cgoIceGatheringStateGathering, ShouldEqual, IceGatheringStateGathering) + So(_cgoIceGatheringStateComplete, ShouldEqual, IceGatheringStateComplete) }) } func TestIceConnectionStateEnums(t *testing.T) { Convey(`Enum: IceConnectionState values should match C++ webrtc::PeerConnectionInterface values`, t, func() { - So(IceConnectionStateNew, ShouldEqual, _cgoIceConnectionStateNew) - So(IceConnectionStateChecking, ShouldEqual, _cgoIceConnectionStateChecking) - So(IceConnectionStateConnected, ShouldEqual, - _cgoIceConnectionStateConnected) - So(IceConnectionStateCompleted, ShouldEqual, - _cgoIceConnectionStateCompleted) - So(IceConnectionStateFailed, ShouldEqual, _cgoIceConnectionStateFailed) - So(IceConnectionStateDisconnected, ShouldEqual, - _cgoIceConnectionStateDisconnected) - So(IceConnectionStateClosed, ShouldEqual, _cgoIceConnectionStateClosed) + So(_cgoIceConnectionStateNew, ShouldEqual, IceConnectionStateNew) + So(_cgoIceConnectionStateChecking, ShouldEqual, IceConnectionStateChecking) + So(_cgoIceConnectionStateConnected, ShouldEqual, + IceConnectionStateConnected) + So(_cgoIceConnectionStateCompleted, ShouldEqual, + IceConnectionStateCompleted) + So(_cgoIceConnectionStateFailed, ShouldEqual, IceConnectionStateFailed) + So(_cgoIceConnectionStateDisconnected, ShouldEqual, + IceConnectionStateDisconnected) + So(_cgoIceConnectionStateClosed, ShouldEqual, IceConnectionStateClosed) }) } diff --git a/peerconnection_windows.go b/peerconnection_windows.go new file mode 100644 index 0000000..6cffe26 --- /dev/null +++ b/peerconnection_windows.go @@ -0,0 +1,133 @@ +// +build windows +package webrtc + +/* +#include "peerconnection.h" +#include "string.h" +*/ +import "C" +import ( + "unsafe" +) + +func init() { + // mod, err := syscall.LoadDLL("webrtc.dll") +} + +//export dll_AddIceCandidate +func dll_AddIceCandidate(cgoPeer C.CGO_Peer, cgoIC *C.CGO_IceCandidate) C.int { + r1, _, _ := myfuncs["dll_AddIceCandidate"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(cgoIC))) + return C.int(r1) +} + +//export dll_CreateAnswer +func dll_CreateAnswer(cgoPeer C.CGO_Peer) C.CGO_sdpString { + r1, _, _ := myfuncs["dll_CreateAnswer"].Call(uintptr(cgoPeer)) + // The caller is going to call free using C.free, that will invoke gcc's free which + // is NOT the same as MSVC's free + res := C.strdup((*C.char)(unsafe.Pointer(r1))) + myfuncs["dll_Free"].Call(r1) + return C.CGO_sdpString(res) +} + +//export dll_CreateDataChannel +func dll_CreateDataChannel(cgoPeer C.CGO_Peer, label *C.char, dict unsafe.Pointer) unsafe.Pointer { + r1, _, _ := myfuncs["dll_CreateDataChannel"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(label)), uintptr(unsafe.Pointer(dict))) + return unsafe.Pointer(r1) +} + +//export dll_CreateOffer +func dll_CreateOffer(cgoPeer C.CGO_Peer) C.CGO_sdpString { + r1, _, _ := myfuncs["dll_CreateOffer"].Call(uintptr(cgoPeer)) + // The caller is going to call free using C.free, that will invoke gcc's free which + // is NOT the same as MSVC's free + res := C.strdup((*C.char)(unsafe.Pointer(r1))) + myfuncs["dll_Free"].Call(r1) + return C.CGO_sdpString(res) +} + +//export dll_GetLocalDescription +func dll_GetLocalDescription(cgoPeer C.CGO_Peer) C.CGO_sdp { + r1, _, _ := myfuncs["dll_GetLocalDescription"].Call(uintptr(cgoPeer)) + return C.CGO_sdp(r1) +} + +//export dll_GetRemoteDescription +func dll_GetRemoteDescription(cgoPeer C.CGO_Peer) C.CGO_sdp { + r1, _, _ := myfuncs["dll_GetRemoteDescription"].Call(uintptr(cgoPeer)) + return C.CGO_sdp(r1) +} + +//export dll_GetSignalingState +func dll_GetSignalingState(cgoPeer C.CGO_Peer) C.int { + r1, _, _ := myfuncs["dll_GetSignalingState"].Call(uintptr(cgoPeer)) + return C.int(r1) +} + +//export dll_IceConnectionState +func dll_IceConnectionState(cgoPeer C.CGO_Peer) C.int { + r1, _, _ := myfuncs["dll_IceConnectionState"].Call(uintptr(cgoPeer)) + return C.int(r1) +} + +//export dll_IceGatheringState +func dll_IceGatheringState(cgoPeer C.CGO_Peer) C.int { + r1, _, _ := myfuncs["dll_IceGatheringState"].Call(uintptr(cgoPeer)) + return C.int(r1) +} + +//export dll_InitializePeer +func dll_InitializePeer(goPc C.int) C.CGO_Peer { + r1, _, _ := myfuncs["dll_InitializePeer"].Call(uintptr(goPc)) + return C.CGO_Peer(r1) +} + +//export dll_SetLocalDescription +func dll_SetLocalDescription(cgoPeer C.CGO_Peer, sdp C.CGO_sdp) C.int { + r1, _, _ := myfuncs["dll_SetLocalDescription"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(sdp))) + return C.int(r1) +} + +//export dll_SetRemoteDescription +func dll_SetRemoteDescription(cgoPeer C.CGO_Peer, sdp C.CGO_sdp) C.int { + r1, _, _ := myfuncs["dll_SetRemoteDescription"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(sdp))) + return C.int(r1) +} + +//export dll_CreatePeerConnection +func dll_CreatePeerConnection(cgoPeer C.CGO_Peer, cgoConfig *C.CGO_Configuration) C.int { + r1, _, _ := myfuncs["dll_CreatePeerConnection"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(cgoConfig))) + return C.int(r1) +} + +//export dll_SetConfiguration +func dll_SetConfiguration(cgoPeer C.CGO_Peer, cgoConfig *C.CGO_Configuration) C.int { + r1, _, _ := myfuncs["dll_SetConfiguration"].Call(uintptr(cgoPeer), uintptr(unsafe.Pointer(cgoConfig))) + return C.int(r1) +} + +//export dll_Close +func dll_Close(peer C.CGO_Peer) { + myfuncs["dll_Close"].Call(uintptr(peer)) +} + +//export dll_fakeIceCandidateError +func dll_fakeIceCandidateError(peer C.CGO_Peer) { + myfuncs["dll_fakeIceCandidateError"].Call(uintptr(peer)) +} + +//export dll_DeserializeSDP +func dll_DeserializeSDP(sdpType *C.char, msg *C.char) C.CGO_sdp { + r1, _, _ := myfuncs["dll_DeserializeSDP"].Call(uintptr(unsafe.Pointer(sdpType)), uintptr(unsafe.Pointer(msg))) + return C.CGO_sdp(unsafe.Pointer(r1)) +} + +//export dll_SerializeSDP +func dll_SerializeSDP(sdp C.CGO_sdp) C.CGO_sdpString { + r1, _, _ := myfuncs["dll_SerializeSDP"].Call(uintptr(sdp)) + // The caller is going to call free using C.free, that will invoke gcc's free which + // is NOT the same as MSVC's free + res := C.strdup((*C.char)(unsafe.Pointer(r1))) + myfuncs["dll_Free"].Call(r1) + return C.CGO_sdpString(res) +} diff --git a/webrtc.dll b/webrtc.dll new file mode 100644 index 0000000..f0f3436 Binary files /dev/null and b/webrtc.dll differ diff --git a/webrtc.sln b/webrtc.sln new file mode 100644 index 0000000..810b2bb --- /dev/null +++ b/webrtc.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc", "webrtc_msvc\webrtc.vcxproj", "{E6D29416-2D9C-4B88-812A-26A67659D9B6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Debug|x64.ActiveCfg = Debug|x64 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Debug|x64.Build.0 = Debug|x64 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Debug|x86.ActiveCfg = Debug|Win32 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Debug|x86.Build.0 = Debug|Win32 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Release|x64.ActiveCfg = Release|x64 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Release|x64.Build.0 = Release|x64 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Release|x86.ActiveCfg = Release|Win32 + {E6D29416-2D9C-4B88-812A-26A67659D9B6}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C0EA1ACB-A60D-448B-9675-3DED5248CC82} + EndGlobalSection +EndGlobal diff --git a/webrtc_msvc/dllExports.h b/webrtc_msvc/dllExports.h new file mode 100644 index 0000000..6166ea6 --- /dev/null +++ b/webrtc_msvc/dllExports.h @@ -0,0 +1,88 @@ +#include + +extern "C" { + + // Enums + __declspec(dllexport) int dll_DataStateConnecting(); + __declspec(dllexport) int dll_DataStateOpen(); + __declspec(dllexport) int dll_DataStateClosing(); + __declspec(dllexport) int dll_DataStateClosed(); + __declspec(dllexport) int dll_IceTransportPolicyNone(); + __declspec(dllexport) int dll_IceTransportPolicyRelay(); + __declspec(dllexport) int dll_IceTransportPolicyNoHost(); + __declspec(dllexport) int dll_IceTransportPolicyAll(); + __declspec(dllexport) int dll_BundlePolicyBalanced(); + __declspec(dllexport) int dll_BundlePolicyMaxBundle(); + __declspec(dllexport) int dll_BundlePolicyMaxCompat(); + __declspec(dllexport) int dll_SignalingStateStable(); + __declspec(dllexport) int dll_SignalingStateHaveLocalOffer(); + __declspec(dllexport) int dll_SignalingStateHaveLocalPrAnswer(); + __declspec(dllexport) int dll_SignalingStateHaveRemoteOffer(); + __declspec(dllexport) int dll_SignalingStateHaveRemotePrAnswer(); + __declspec(dllexport) int dll_SignalingStateClosed(); + __declspec(dllexport) int dll_IceConnectionStateNew(); + __declspec(dllexport) int dll_IceConnectionStateChecking(); + __declspec(dllexport) int dll_IceConnectionStateConnected(); + __declspec(dllexport) int dll_IceConnectionStateCompleted(); + __declspec(dllexport) int dll_IceConnectionStateFailed(); + __declspec(dllexport) int dll_IceConnectionStateDisconnected(); + __declspec(dllexport) int dll_IceConnectionStateClosed(); + __declspec(dllexport) int dll_IceGatheringStateNew(); + __declspec(dllexport) int dll_IceGatheringStateGathering(); + __declspec(dllexport) int dll_IceGatheringStateComplete(); + + // DataChannel + __declspec(dllexport) void* dll_Channel_RegisterObserver(void* o, int index); + __declspec(dllexport) void* dll_getFakeDataChannel(); + __declspec(dllexport) const char *dll_Channel_Label(CGO_Channel channel); + __declspec(dllexport) const char *dll_Channel_Protocol(CGO_Channel channel); + __declspec(dllexport) int dll_Channel_ID(CGO_Channel channel); + __declspec(dllexport) int dll_Channel_BufferedAmount(CGO_Channel channel); + __declspec(dllexport) int dll_Channel_ReadyState(CGO_Channel channel); + __declspec(dllexport) bool dll_Channel_Ordered(CGO_Channel channel); + __declspec(dllexport) bool dll_Channel_Negotiated(CGO_Channel channel); + __declspec(dllexport) int dll_Channel_MaxRetransmitTime(CGO_Channel channel); + __declspec(dllexport) int dll_Channel_MaxRetransmits(CGO_Channel channel); + __declspec(dllexport) void dll_Channel_Send(CGO_Channel channel, void *data, int size, bool binary); + __declspec(dllexport) void dll_Channel_Close(CGO_Channel channel); + __declspec(dllexport) void dll_fakeMessage(CGO_Channel channel, void *data, int size); + __declspec(dllexport) void dll_fakeStateChange(CGO_Channel channel, int state); + __declspec(dllexport) void dll_fakeBufferAmount(CGO_Channel channel, int amount); + + // PeerConnection + __declspec(dllexport) void* dll_InitializePeer(int goPc); + __declspec(dllexport) void dll_Close(CGO_Peer peer); + __declspec(dllexport) int dll_CreatePeerConnection(CGO_Peer, CGO_Configuration *); + __declspec(dllexport) CGO_sdpString dll_CreateOffer(CGO_Peer); + __declspec(dllexport) CGO_sdpString dll_CreateAnswer(CGO_Peer); + __declspec(dllexport) int dll_SetLocalDescription(CGO_Peer, CGO_sdp); + __declspec(dllexport) int dll_SetRemoteDescription(CGO_Peer, CGO_sdp); + __declspec(dllexport) CGO_sdp dll_GetLocalDescription(CGO_Peer); + __declspec(dllexport) CGO_sdp dll_GetRemoteDescription(CGO_Peer); + __declspec(dllexport) int dll_GetSignalingState(CGO_Peer); + __declspec(dllexport) int dll_IceConnectionState(CGO_Peer); + __declspec(dllexport) int dll_IceGatheringState(CGO_Peer); + __declspec(dllexport) int dll_SetConfiguration(CGO_Peer, CGO_Configuration *); + __declspec(dllexport) int dll_AddIceCandidate(CGO_Peer cgoPeer, CGO_IceCandidate *cgoIC); + __declspec(dllexport) void* dll_CreateDataChannel(CGO_Peer, char *, void *); + __declspec(dllexport) CGO_sdpString dll_SerializeSDP(CGO_sdp); + __declspec(dllexport) CGO_sdp dll_DeserializeSDP(const char *type, const char *msg); + __declspec(dllexport) void dll_fakeIceCandidateError(CGO_Peer peer); + + // Callbacks + __declspec(dllexport) void SetCallbackChannelOnMessage(void(*cb)(int channel, void* data, int size)); + __declspec(dllexport) void SetCallbackChannelOnStateChange(void(*cb)(int channel)); + __declspec(dllexport) void SetCallbackChannelOnBufferedAmountChange(void(*cb)(int channel, int amount)); + __declspec(dllexport) void SetCallbackOnIceCandidate(void(*cb)(int, CGO_IceCandidate*)); + __declspec(dllexport) void SetCallbackOnIceCandidateError(void(*cb)(int)); + __declspec(dllexport) void SetCallbackOnSignalingStateChange(void(*cb)(int, int)); + __declspec(dllexport) void SetCallbackOnNegotiationNeeded(void(*cb)(int)); + __declspec(dllexport) void SetCallbackOnIceConnectionStateChange(void(*cb)(int, int)); + __declspec(dllexport) void SetCallbackOnConnectionStateChange(void(*cb)(int, int)); + __declspec(dllexport) void SetCallbackOnIceGatheringStateChange(void(*cb)(int, int)); + __declspec(dllexport) void SetCallbackOnDataChannel(void(*cb)(int, void*)); + + // Misc + __declspec(dllexport) void dll_Free(void* ptr); +} + diff --git a/webrtc_msvc/externs.h b/webrtc_msvc/externs.h new file mode 100644 index 0000000..df27376 --- /dev/null +++ b/webrtc_msvc/externs.h @@ -0,0 +1,11 @@ + +extern void cgoOnSignalingStateChange(int, int); +extern void cgoOnNegotiationNeeded(int); +extern void cgoChannelOnStateChange(int); +extern void cgoChannelOnMessage(int, void*, int); +extern void cgoChannelOnBufferedAmountChange(int, int); +extern void cgoOnIceCandidateError(int); +extern void cgoOnIceConnectionStateChange(int, int); +extern void cgoOnConnectionStateChange(int, int); +extern void cgoOnIceGatheringStateChange(int, int); +extern void cgoOnDataChannel(int, void *); diff --git a/webrtc_msvc/main.cpp b/webrtc_msvc/main.cpp new file mode 100644 index 0000000..0b1b1d1 --- /dev/null +++ b/webrtc_msvc/main.cpp @@ -0,0 +1,278 @@ +#include "peerconnection.h" +#include "datachannel.h" +#include "ctestenums.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "dllExports.h" + +#include +#include +#include + +// Callback forward declarations +void(*callbackChannelOnMessagePtr)(int channel, void* data, int size); +void(*callbackChannelOnStateChangePtr)(int channel); +void(*callbackChannelOnBufferedAmountChangePtr)(int channel, int amount); +void(*callbackOnIceCandidatePtr)(int, CGO_IceCandidate*); +void(*callbackOnIceCandidateErrorPtr)(int); +void(*callbackOnSignalingStateChangePtr)(int, int); +void(*callbackOnNegotiationNeededPtr)(int); +void(*callbackOnIceConnectionStateChangePtr)(int p, int state); +void(*callbackOnConnectionStateChangePtr)(int p, int state); +void(*callbackOnIceGatheringStateChangePtr)(int p, int state); +void(*callbackOnDataChannelPtr)(int index, void* o); + +extern "C" { + // Set callback function pointers + void SetCallbackChannelOnMessage(void(*cb)(int channel, void* data, int size)) { + callbackChannelOnMessagePtr = cb; + } + + void SetCallbackChannelOnStateChange(void(*cb)(int channel)) { + callbackChannelOnStateChangePtr = cb; + } + + void SetCallbackChannelOnBufferedAmountChange(void(*cb)(int channel, int amount)) { + callbackChannelOnBufferedAmountChangePtr = cb; + } + + void SetCallbackOnIceCandidate(void(*cb)(int, CGO_IceCandidate*)) { + callbackOnIceCandidatePtr = cb; + } + + void SetCallbackOnIceCandidateError(void(*cb)(int)) { + callbackOnIceCandidateErrorPtr = cb; + } + + void SetCallbackOnSignalingStateChange(void(*cb)(int, int)) { + callbackOnSignalingStateChangePtr = cb; + } + + void SetCallbackOnNegotiationNeeded(void(*cb)(int)) { + callbackOnNegotiationNeededPtr = cb; + } + + void SetCallbackOnIceConnectionStateChange(void(*cb)(int, int)) { + callbackOnIceConnectionStateChangePtr = cb; + } + + void SetCallbackOnConnectionStateChange(void(*cb)(int, int)) { + callbackOnConnectionStateChangePtr = cb; + } + + void SetCallbackOnIceGatheringStateChange(void(*cb)(int, int)) { + callbackOnIceGatheringStateChangePtr = cb; + } + + void SetCallbackOnDataChannel(void(*cb)(int, void*)) { + callbackOnDataChannelPtr = cb; + } + + // Enums + int dll_DataStateConnecting() { return CGO_DataStateConnecting; } + int dll_DataStateOpen() { return CGO_DataStateOpen; } + int dll_DataStateClosing() { return CGO_DataStateClosing; } + int dll_DataStateClosed() { return CGO_DataStateClosed; } + int dll_IceTransportPolicyNone() { return CGO_IceTransportPolicyNone; } + int dll_IceTransportPolicyRelay() { return CGO_IceTransportPolicyRelay; } + int dll_IceTransportPolicyNoHost() { return CGO_IceTransportPolicyNoHost; } + int dll_IceTransportPolicyAll() { return CGO_IceTransportPolicyAll; } + int dll_BundlePolicyBalanced() { return CGO_BundlePolicyBalanced; } + int dll_BundlePolicyMaxBundle() { return CGO_BundlePolicyMaxBundle; } + int dll_BundlePolicyMaxCompat() { return CGO_BundlePolicyMaxCompat; } + int dll_SignalingStateStable() { return CGO_SignalingStateStable; } + int dll_SignalingStateHaveLocalOffer() { return CGO_SignalingStateHaveLocalOffer; } + int dll_SignalingStateHaveLocalPrAnswer() { return CGO_SignalingStateHaveLocalPrAnswer; } + int dll_SignalingStateHaveRemoteOffer() { return CGO_SignalingStateHaveRemoteOffer; } + int dll_SignalingStateHaveRemotePrAnswer() { return CGO_SignalingStateHaveRemotePrAnswer; } + int dll_SignalingStateClosed() { return CGO_SignalingStateClosed; } + int dll_IceConnectionStateNew() { return CGO_IceConnectionStateNew; } + int dll_IceConnectionStateChecking() { return CGO_IceConnectionStateChecking; } + int dll_IceConnectionStateConnected() { return CGO_IceConnectionStateConnected; } + int dll_IceConnectionStateCompleted() { return CGO_IceConnectionStateCompleted; } + int dll_IceConnectionStateFailed() { return CGO_IceConnectionStateFailed; } + int dll_IceConnectionStateDisconnected() { return CGO_IceConnectionStateDisconnected; } + int dll_IceConnectionStateClosed() { return CGO_IceConnectionStateClosed; } + int dll_IceGatheringStateNew() { return CGO_IceGatheringStateNew; } + int dll_IceGatheringStateGathering() { return CGO_IceGatheringStateGathering; } + int dll_IceGatheringStateComplete() { return CGO_IceGatheringStateComplete; } + + void* dll_Channel_RegisterObserver(void* o, int index) { + return CGO_Channel_RegisterObserver(o, index); + } + + void* dll_getFakeDataChannel() { + return CGO_getFakeDataChannel(); + } + + const char *dll_Channel_Label(CGO_Channel channel) { + const char* res = CGO_Channel_Label(channel); + return res; + } + + const char *dll_Channel_Protocol(CGO_Channel channel) { + const char* res = CGO_Channel_Protocol(channel); + return res; + } + + bool dll_Channel_Ordered(CGO_Channel channel) { + return CGO_Channel_Ordered(channel); + } + + bool dll_Channel_Negotiated(CGO_Channel channel) { + return CGO_Channel_Negotiated(channel); + } + + int dll_Channel_MaxRetransmitTime(CGO_Channel channel) { + return CGO_Channel_MaxRetransmitTime(channel); + } + + int dll_Channel_MaxRetransmits(CGO_Channel channel) { + return CGO_Channel_MaxRetransmits(channel); + } + + int dll_Channel_ID(CGO_Channel channel) { + return CGO_Channel_ID(channel); + } + + int dll_Channel_BufferedAmount(CGO_Channel channel) { + return CGO_Channel_BufferedAmount(channel); + } + + int dll_Channel_ReadyState(CGO_Channel channel) { + return CGO_Channel_ReadyState(channel); + } + + void dll_Channel_Send(CGO_Channel channel, void *data, int size, bool binary) { + return CGO_Channel_Send(channel, data, size, binary); + } + + void dll_Channel_Close(CGO_Channel channel) { + CGO_Channel_Close(channel); + } + + void dll_fakeMessage(CGO_Channel channel, void *data, int size) { + return CGO_fakeMessage(channel, data, size); + } + + void dll_fakeStateChange(CGO_Channel channel, int state) { + return CGO_fakeStateChange(channel, state); + } + + void dll_fakeBufferAmount(CGO_Channel channel, int amount) { + return CGO_fakeBufferAmount(channel, amount); + } + + void dll_Free(void* ptr) { + free(ptr); + } + + // PeerConnection + void* dll_InitializePeer(int goPc) { + return CGO_InitializePeer(goPc); + } + + int dll_CreatePeerConnection(CGO_Peer peer, CGO_Configuration *config) { + return CGO_CreatePeerConnection(peer, config); + } + + CGO_sdpString dll_CreateOffer(CGO_Peer peer) { + return CGO_CreateOffer(peer); + } + + CGO_sdpString dll_CreateAnswer(CGO_Peer peer) { + return CGO_CreateAnswer(peer); + } + + int dll_SetLocalDescription(CGO_Peer peer, CGO_sdp sdp) { + return CGO_SetLocalDescription(peer, sdp); + } + + int dll_SetRemoteDescription(CGO_Peer peer, CGO_sdp sdp) { + return CGO_SetRemoteDescription(peer, sdp); + } + + CGO_sdp dll_GetLocalDescription(CGO_Peer peer) { + return CGO_GetLocalDescription(peer); + } + + CGO_sdp dll_GetRemoteDescription(CGO_Peer peer) { + return CGO_GetRemoteDescription(peer); + } + + int dll_GetSignalingState(CGO_Peer peer) { + return CGO_GetSignalingState(peer); + } + + int dll_IceConnectionState(CGO_Peer peer) { + return CGO_IceConnectionState(peer); + } + + int dll_IceGatheringState(CGO_Peer peer) { + return CGO_IceGatheringState(peer); + } + + int dll_SetConfiguration(CGO_Peer peer, CGO_Configuration *config) { + return CGO_SetConfiguration(peer, config); + } + + int dll_AddIceCandidate(CGO_Peer cgoPeer, CGO_IceCandidate *cgoIC) { + return CGO_AddIceCandidate(cgoPeer, cgoIC); + } + + void* dll_CreateDataChannel(CGO_Peer peer, char *label, void *dict) { + return CGO_CreateDataChannel(peer, label, dict); + } + + CGO_sdpString dll_SerializeSDP(CGO_sdp sdp) { + return CGO_SerializeSDP(sdp); + } + + CGO_sdp dll_DeserializeSDP(const char *type, const char *msg) { + return CGO_DeserializeSDP(type, msg); + } + + void dll_Close(CGO_Peer peer) { + CGO_Close(peer); + } + + void dll_fakeIceCandidateError(CGO_Peer peer) { + CGO_fakeIceCandidateError(peer); + } +} + +/* +* Callbacks +*/ + void cgoOnIceCandidate(int p, CGO_IceCandidate cIC) { + callbackOnIceCandidatePtr(p, &cIC); + } + void cgoOnIceCandidateError(int p) { + callbackOnIceCandidateErrorPtr(p); + } + void cgoOnSignalingStateChange(int p, int s) { + callbackOnSignalingStateChangePtr(p, s); + } + void cgoOnNegotiationNeeded(int p) { + callbackOnNegotiationNeededPtr(p); + } + void cgoChannelOnStateChange(int channel) { + callbackChannelOnStateChangePtr(channel); + } + void cgoChannelOnMessage(int channel, void* data, int size) { + callbackChannelOnMessagePtr(channel, data, size); + } + void cgoChannelOnBufferedAmountChange(int channel, int amount) { + callbackChannelOnBufferedAmountChangePtr(channel, amount); + } + void cgoOnIceConnectionStateChange(int p, int state) { + callbackOnIceConnectionStateChangePtr(p, state); + } + void cgoOnConnectionStateChange(int p, int state) { + callbackOnConnectionStateChangePtr(p, state); + } + void cgoOnIceGatheringStateChange(int p, int state) { + callbackOnIceGatheringStateChangePtr(p, state); + } + void cgoOnDataChannel(int index, void *o) { + callbackOnDataChannelPtr(index, o); + } diff --git a/webrtc_msvc/webrtc.vcxproj b/webrtc_msvc/webrtc.vcxproj new file mode 100644 index 0000000..a90e935 --- /dev/null +++ b/webrtc_msvc/webrtc.vcxproj @@ -0,0 +1,144 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E6D29416-2D9C-4B88-812A-26A67659D9B6} + webrtc + 10.0.15063.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + DynamicLibrary + true + v141 + NotSet + + + DynamicLibrary + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + + + + + Level3 + Disabled + true + ..\include;.\;..\ + WIN_WEBRTC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WEBRTC_WIN;_WINDLL;%(PreprocessorDefinitions) + MultiThreaded + + + libwebrtc_full.lib;winmm.lib;secur32.lib;dmoguids.lib;msdmo.lib;wmcodecdspuuid.lib;%(AdditionalDependencies) + ..\lib + ..\$(TargetName)$(TargetExt) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + ..\include;.\;..\ + WIN_WEBRTC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WEBRTC_WIN;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + true + true + libwebrtc_full.lib;winmm.lib;secur32.lib;dmoguids.lib;msdmo.lib;wmcodecdspuuid.lib;%(AdditionalDependencies) + ..\lib + ..\$(TargetName)$(TargetExt) + + + + + + + + + + + + + + + + + + + + \ No newline at end of file