summaryrefslogtreecommitdiff
path: root/src/WebRTCLibDataChannel.cpp
blob: ede89a93edb7b62c50741f6a0d1414d6194a814a (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "WebRTCLibDataChannel.hpp"

using namespace godot_webrtc;

// Channel observer
WebRTCLibDataChannel::ChannelObserver::ChannelObserver(WebRTCLibDataChannel *parent) {
	this->parent = parent;
}

void WebRTCLibDataChannel::ChannelObserver::OnMessage(const webrtc::DataBuffer &buffer) {
	parent->queue_packet(buffer.data.data<uint8_t>(), buffer.data.size());
}

void WebRTCLibDataChannel::ChannelObserver::OnStateChange() {
}

void WebRTCLibDataChannel::ChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) {
}

// DataChannel
WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
	// Invalid channel result in NULL return
	ERR_FAIL_COND_V(p_channel.get() == nullptr, NULL);

	// Instance a WebRTCDataChannelGDNative object
	godot::WebRTCDataChannelGDNative *out = godot::WebRTCDataChannelGDNative::_new();
	// Set our implementation as it's script
	godot::NativeScript *script = godot::NativeScript::_new();
	script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib));
	script->set_class_name("WebRTCLibDataChannel");
	out->set_script(script);

	// Bind the data channel to the ScriptInstance userdata (our script)
	WebRTCLibDataChannel *tmp = godot::as<WebRTCLibDataChannel>(out);
	tmp->bind_channel(p_channel);

	return tmp;
}


void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
	ERR_FAIL_COND(p_channel.get() == nullptr);

	channel = p_channel;
	label = p_channel->label();
	protocol = p_channel->protocol();
	channel->RegisterObserver(&observer);
}

void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size) {
	mutex->lock();

	godot::PoolByteArray packet;
	packet.resize(size);
	{
		godot::PoolByteArray::Write w = packet.write();
		memcpy(w.ptr(), data, size);
	}
	packet_queue.push(packet);

	mutex->unlock();
}

void WebRTCLibDataChannel::set_write_mode(godot_int mode) {
}

godot_int WebRTCLibDataChannel::get_write_mode() const {
	return 0;
}

bool WebRTCLibDataChannel::was_string_packet() const {
	return false;
}

WebRTCLibDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, STATE_CLOSED);
	return (ChannelState)channel->state();
}

const char *WebRTCLibDataChannel::get_label() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, "");
	return label.c_str();
}

bool WebRTCLibDataChannel::is_ordered() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, false);
	return channel->ordered();
}

int WebRTCLibDataChannel::get_id() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, -1);
	return channel->id();
}

int WebRTCLibDataChannel::get_max_packet_life_time() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, 0);
	return channel->maxRetransmitTime();
}

int WebRTCLibDataChannel::get_max_retransmits() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, 0);
	return channel->maxRetransmits();
}

const char *WebRTCLibDataChannel::get_protocol() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, "");
	return protocol.c_str();
}

bool WebRTCLibDataChannel::is_negotiated() const {
	ERR_FAIL_COND_V(channel.get() == nullptr, false);
	return channel->negotiated();
}

godot_error WebRTCLibDataChannel::poll() {
	return GODOT_OK;
}

void WebRTCLibDataChannel::close() {
	if(channel.get() != nullptr) {
		channel->Close();
		channel->UnregisterObserver();
	}
}

godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_len) {
	ERR_FAIL_COND_V(packet_queue.empty(), GODOT_ERR_UNAVAILABLE);

	mutex->lock();

	// Update current packet and pop queue
	current_packet = packet_queue.front();
	packet_queue.pop();
	// Set out buffer and size (buffer will be gone at next get_packet or close)
	*r_buffer = current_packet.read().ptr();
	*r_len = current_packet.size();

	mutex->unlock();

	return GODOT_OK;
}

godot_error WebRTCLibDataChannel::put_packet(const uint8_t *p_buffer, int p_len) {
	ERR_FAIL_COND_V(channel.get() == nullptr, GODOT_ERR_UNAVAILABLE);

	webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
	ERR_FAIL_COND_V(!channel->Send(webrtc_buffer), GODOT_FAILED);

	return GODOT_OK;
}

godot_int WebRTCLibDataChannel::get_available_packet_count() const {
	return packet_queue.size();
}

godot_int WebRTCLibDataChannel::get_max_packet_size() const {
	return 1200;
}

void WebRTCLibDataChannel::_register_methods() {
}

void WebRTCLibDataChannel::_init() {
	register_interface(&interface);
}

WebRTCLibDataChannel::WebRTCLibDataChannel() : observer(this) {
	mutex = new std::mutex;
}

WebRTCLibDataChannel::~WebRTCLibDataChannel() {
	close();
	if (_owner) {
		register_interface(NULL);
	}
	delete mutex;
}