Skip to content

Commit 4bda5bc

Browse files
committed
AppRTC signaling implementation
1 parent c6fb0d8 commit 4bda5bc

File tree

9 files changed

+1274
-2
lines changed

9 files changed

+1274
-2
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2019 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dev.onvoid.webrtc.demo.apprtc;
18+
19+
public interface AppRTCCommand {
20+
21+
String getCommand();
22+
23+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2019 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dev.onvoid.webrtc.demo.apprtc;
18+
19+
/**
20+
* Maintains connection parameters of an AppRTC room.
21+
*/
22+
public class AppRTCConnectionParameters {
23+
24+
public final String roomUrl;
25+
26+
public final String roomId;
27+
28+
public final boolean loopback;
29+
30+
public final String urlParameters;
31+
32+
33+
public AppRTCConnectionParameters(String roomUrl, String roomId) {
34+
this(roomUrl, roomId, false, null);
35+
}
36+
37+
public AppRTCConnectionParameters(String roomUrl, String roomId,
38+
boolean loopback) {
39+
this(roomUrl, roomId, loopback, null);
40+
}
41+
42+
public AppRTCConnectionParameters(String roomUrl, String roomId, boolean loopback,
43+
String urlParameters) {
44+
this.roomUrl = roomUrl;
45+
this.roomId = roomId;
46+
this.loopback = loopback;
47+
this.urlParameters = urlParameters;
48+
}
49+
50+
}
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
/*
2+
* Copyright 2019 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dev.onvoid.webrtc.demo.apprtc;
18+
19+
import static java.util.Objects.isNull;
20+
import static java.util.Objects.nonNull;
21+
22+
import dev.onvoid.webrtc.RTCIceCandidate;
23+
import dev.onvoid.webrtc.RTCIceServer;
24+
import dev.onvoid.webrtc.RTCSdpType;
25+
import dev.onvoid.webrtc.RTCSessionDescription;
26+
import dev.onvoid.webrtc.demo.apprtc.AppRTCMessage.Type;
27+
28+
import java.io.StringReader;
29+
import java.io.StringWriter;
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
import java.util.Map;
33+
34+
import javax.json.Json;
35+
import javax.json.JsonArray;
36+
import javax.json.JsonArrayBuilder;
37+
import javax.json.JsonBuilderFactory;
38+
import javax.json.JsonObject;
39+
import javax.json.JsonObjectBuilder;
40+
import javax.json.JsonReader;
41+
import javax.json.JsonWriter;
42+
43+
public class AppRTCJsonCodec {
44+
45+
AppRTCSignalingParameters toSignalingParameters(String json) {
46+
JsonReader reader = Json.createReader(new StringReader(json));
47+
JsonObject room = reader.readObject();
48+
49+
String result = room.getString("result");
50+
if (!result.equals("SUCCESS")) {
51+
throw new RuntimeException("Room response error: " + result);
52+
}
53+
54+
room = room.getJsonObject("params");
55+
56+
String clientId = room.getString("client_id");
57+
String wssUrl = room.getString("wss_url");
58+
String wssPostUrl = room.getString("wss_post_url");
59+
String iceServerUrl = room.getString("ice_server_url");
60+
boolean initiator = Boolean.parseBoolean(room.getString("is_initiator"));
61+
62+
List<RTCIceCandidate> iceCandidates = null;
63+
RTCSessionDescription offer = null;
64+
65+
if (!initiator) {
66+
iceCandidates = new ArrayList<>();
67+
JsonArray messages = room.getJsonArray("messages");
68+
69+
for (int i = 0; i < messages.size(); ++i) {
70+
String messageString = messages.getString(i);
71+
72+
reader = Json.createReader(new StringReader(messageString));
73+
74+
JsonObject message = reader.readObject();
75+
String messageType = message.getString("type");
76+
77+
if (messageType.equals("offer")) {
78+
offer = new RTCSessionDescription(
79+
RTCSdpType.valueOf(messageType.replace("_", "").toUpperCase()),
80+
message.getString("sdp"));
81+
}
82+
else if (messageType.equals("candidate")) {
83+
RTCIceCandidate candidate = new RTCIceCandidate(
84+
message.getString("id"),
85+
message.getInt("label"),
86+
message.getString("candidate"));
87+
88+
iceCandidates.add(candidate);
89+
}
90+
}
91+
}
92+
93+
List<RTCIceServer> iceServers = toJavaIceServers(room.getString("pc_config"));
94+
95+
return new AppRTCSignalingParameters(iceServers, initiator, clientId,
96+
wssUrl, wssPostUrl, iceServerUrl,
97+
offer, iceCandidates);
98+
}
99+
100+
String toJsonCommand(AppRTCCommand command) {
101+
JsonObjectBuilder builder = Json.createObjectBuilder();
102+
103+
if (command instanceof AppRTCRegisterCommand) {
104+
AppRTCRegisterCommand registerCommand = (AppRTCRegisterCommand) command;
105+
106+
builder.add("cmd", registerCommand.getCommand());
107+
builder.add("roomid", registerCommand.getRoomId());
108+
builder.add("clientid", registerCommand.getClientId());
109+
}
110+
else if (command instanceof AppRTCSendCommand) {
111+
AppRTCSendCommand sendCommand = (AppRTCSendCommand) command;
112+
113+
builder.add("cmd", sendCommand.getCommand());
114+
builder.add("msg", sendCommand.getMessage());
115+
}
116+
117+
return build(builder);
118+
}
119+
120+
String toJsonMessage(AppRTCMessage message) {
121+
JsonObjectBuilder builder = Json.createObjectBuilder();
122+
123+
switch (message.getType()) {
124+
case CANDIDATE:
125+
RTCIceCandidate candidate = (RTCIceCandidate) message.getObject();
126+
127+
builder.add("type", "candidate");
128+
builder.add("label", candidate.sdpMLineIndex);
129+
builder.add("id", candidate.sdpMid);
130+
builder.add("candidate", candidate.sdp);
131+
break;
132+
133+
case REMOVE_CANDIDATES:
134+
RTCIceCandidate[] candidates = (RTCIceCandidate[]) message.getObject();
135+
JsonBuilderFactory factory = Json.createBuilderFactory(Map.of());
136+
JsonArrayBuilder jsonArray = factory.createArrayBuilder();
137+
138+
for (RTCIceCandidate c : candidates) {
139+
jsonArray.add(toJsonCandidate(c));
140+
}
141+
142+
builder.add("type", "remove-candidates");
143+
builder.add("candidates", jsonArray);
144+
break;
145+
146+
case ANSWER:
147+
RTCSessionDescription answer = (RTCSessionDescription) message.getObject();
148+
149+
builder.add("type", "answer");
150+
builder.add("sdp", answer.sdp);
151+
break;
152+
153+
case OFFER:
154+
RTCSessionDescription offer = (RTCSessionDescription) message.getObject();
155+
156+
builder.add("type", "offer");
157+
builder.add("sdp", offer.sdp);
158+
break;
159+
160+
case BYE:
161+
builder.add("type", "bye");
162+
break;
163+
164+
default:
165+
break;
166+
}
167+
168+
return build(builder);
169+
}
170+
171+
AppRTCMessage toJavaMessage(String json) {
172+
JsonReader reader = Json.createReader(new StringReader(json));
173+
JsonObject jsonObject = reader.readObject();
174+
175+
String msgText = jsonObject.getString("msg");
176+
String errorText = jsonObject.getString("error");
177+
178+
if (msgText.length() > 0) {
179+
reader = Json.createReader(new StringReader(msgText));
180+
jsonObject = reader.readObject();
181+
String type = jsonObject.getString("type");
182+
183+
switch (type) {
184+
case "candidate":
185+
return new AppRTCMessage(Type.CANDIDATE,
186+
toJavaCandidate(jsonObject));
187+
188+
case "remove-candidates":
189+
return new AppRTCMessage(Type.REMOVE_CANDIDATES,
190+
toJavaCandidates(jsonObject));
191+
192+
case "answer":
193+
return new AppRTCMessage(Type.ANSWER,
194+
toJavaSessionDescription(jsonObject));
195+
196+
case "offer":
197+
return new AppRTCMessage(Type.OFFER,
198+
toJavaSessionDescription( jsonObject));
199+
200+
case "bye":
201+
return new AppRTCMessage(Type.BYE);
202+
203+
default:
204+
return new AppRTCMessage(Type.ERROR,
205+
"Unexpected message: " + json);
206+
}
207+
}
208+
else {
209+
if (nonNull(errorText) && errorText.length() > 0) {
210+
return new AppRTCMessage(Type.ERROR, errorText);
211+
}
212+
else {
213+
return new AppRTCMessage(Type.ERROR,
214+
"Unexpected message: " + json);
215+
}
216+
}
217+
}
218+
219+
List<RTCIceServer> toJavaIceServers(String json) {
220+
JsonReader reader = Json.createReader(new StringReader(json));
221+
JsonObject jsonObject = reader.readObject();
222+
JsonArray servers = jsonObject.getJsonArray("iceServers");
223+
224+
List<RTCIceServer> result = new ArrayList<>();
225+
226+
if (isNull(servers)) {
227+
return result;
228+
}
229+
230+
for (int i = 0; i < servers.size(); ++i) {
231+
JsonObject server = servers.getJsonObject(i);
232+
JsonArray urls = server.getJsonArray("urls");
233+
234+
String credential = server.containsKey("credential") ?
235+
server.getString("credential") :
236+
"";
237+
String username = server.containsKey("username") ?
238+
server.getString("username") :
239+
"";
240+
241+
RTCIceServer iceServer = new RTCIceServer();
242+
iceServer.username = username;
243+
iceServer.password = credential;
244+
245+
for (int j = 0; j < urls.size(); j++) {
246+
iceServer.urls.add(urls.getString(j));
247+
}
248+
249+
result.add(iceServer);
250+
}
251+
252+
return result;
253+
}
254+
255+
String toJavaPostResponse(String response) {
256+
JsonReader reader = Json.createReader(new StringReader(response));
257+
JsonObject roomJson = reader.readObject();
258+
259+
return roomJson.getString("result");
260+
}
261+
262+
private JsonObject toJsonCandidate(final RTCIceCandidate candidate) {
263+
JsonObjectBuilder builder = Json.createObjectBuilder()
264+
.add("label", candidate.sdpMLineIndex)
265+
.add("id", candidate.sdpMid)
266+
.add("candidate", candidate.sdp);
267+
268+
return builder.build();
269+
}
270+
271+
private RTCIceCandidate toJavaCandidate(JsonObject json) {
272+
return new RTCIceCandidate(json.getString("id"),
273+
json.getInt("label"),
274+
json.getString("candidate"));
275+
}
276+
277+
private RTCIceCandidate[] toJavaCandidates(JsonObject json) {
278+
JsonArray candidateArray = json.getJsonArray("candidates");
279+
RTCIceCandidate[] candidates = new RTCIceCandidate[candidateArray.size()];
280+
281+
for (int i = 0; i < candidateArray.size(); ++i) {
282+
candidates[i] = toJavaCandidate(candidateArray.getJsonObject(i));
283+
}
284+
285+
return candidates;
286+
}
287+
288+
private RTCSessionDescription toJavaSessionDescription(JsonObject json) {
289+
String type = json.getString("type");
290+
291+
return new RTCSessionDescription(
292+
RTCSdpType.valueOf(type.replace("_", "").toUpperCase()),
293+
json.getString("sdp"));
294+
}
295+
296+
private static String build(JsonObjectBuilder builder) {
297+
JsonObject json = builder.build();
298+
299+
if (isNull(json) || json.isEmpty()) {
300+
return null;
301+
}
302+
303+
StringWriter stringWriter = new StringWriter();
304+
305+
JsonWriter writer = Json.createWriter(stringWriter);
306+
writer.writeObject(json);
307+
writer.close();
308+
309+
return stringWriter.toString();
310+
}
311+
312+
}

0 commit comments

Comments
 (0)