1#include <string>
2
3#include "mtx/events/voip.hpp"
4
5#include <nlohmann/json.hpp>
6
7using json = nlohmann::json;
8
9namespace {
10std::string
11version(const json &obj)
12{
13 auto v = obj.at(key: "version");
14 return v.is_number() ? "0" : v.get<std::string>();
15}
16
17void
18add_version(json &obj, std::string_view version)
19{
20 if (version == "0")
21 obj["version"] = 0;
22 else
23 obj["version"] = version;
24}
25}
26
27namespace mtx::events::voip {
28
29// RTC Session Description
30void
31from_json(const json &obj, RTCSessionDescriptionInit &content)
32{
33 content.sdp = obj.at(key: "sdp").get<std::string>();
34 if (obj.at(key: "type").get<std::string>() == "answer")
35 content.type = RTCSessionDescriptionInit::Type::Answer;
36 else if (obj.at(key: "type").get<std::string>() == "offer")
37 content.type = RTCSessionDescriptionInit::Type::Offer;
38}
39
40void
41to_json(json &obj, const RTCSessionDescriptionInit &content)
42{
43 obj["sdp"] = content.sdp;
44 if (content.type == RTCSessionDescriptionInit::Type::Answer)
45 obj["type"] = "answer";
46 else if (content.type == RTCSessionDescriptionInit::Type::Offer)
47 obj["type"] = "offer";
48}
49
50// m.call.invite
51void
52from_json(const json &obj, CallInvite &content)
53{
54 content.call_id = obj.at(key: "call_id").get<std::string>();
55 content.offer = obj.at(key: "offer").get<RTCSessionDescriptionInit>();
56 content.version = version(obj);
57 content.lifetime = obj.at(key: "lifetime").get<uint32_t>();
58 if (content.version != "0") {
59 content.party_id = obj.at(key: "party_id").get<std::string>();
60 if (obj.contains(key: "invitee"))
61 content.invitee = obj.at(key: "invitee").get<std::string>();
62 }
63}
64
65void
66to_json(json &obj, const CallInvite &content)
67{
68 obj["call_id"] = content.call_id;
69 obj["offer"] = content.offer;
70 add_version(obj, version: content.version);
71 obj["lifetime"] = content.lifetime;
72 if (content.version != "0") {
73 obj["party_id"] = content.party_id;
74 obj["invitee"] = content.invitee;
75 }
76}
77
78// m.call.candidates
79void
80from_json(const json &obj, CallCandidates::Candidate &content)
81{
82 if (obj.contains(key: "sdpMid"))
83 content.sdpMid = obj.at(key: "sdpMid").get<std::string>();
84 if (obj.contains(key: "sdpMLineIndex"))
85 content.sdpMLineIndex = obj.at(key: "sdpMLineIndex").get<uint16_t>();
86 if (obj.contains(key: "candidate"))
87 content.candidate = obj.at(key: "candidate").get<std::string>();
88}
89
90void
91to_json(json &obj, const CallCandidates::Candidate &content)
92{
93 obj["sdpMid"] = content.sdpMid;
94 obj["sdpMLineIndex"] = content.sdpMLineIndex;
95 obj["candidate"] = content.candidate;
96}
97
98void
99from_json(const json &obj, CallCandidates &content)
100{
101 content.call_id = obj.at(key: "call_id").get<std::string>();
102 content.candidates = obj.at(key: "candidates").get<std::vector<CallCandidates::Candidate>>();
103 content.version = version(obj);
104 if (content.version != "0") {
105 content.party_id = obj.at(key: "party_id").get<std::string>();
106 }
107}
108
109void
110to_json(json &obj, const CallCandidates &content)
111{
112 obj["call_id"] = content.call_id;
113 obj["candidates"] = content.candidates;
114 add_version(obj, version: content.version);
115 if (content.version != "0") {
116 obj["party_id"] = content.party_id;
117 }
118}
119
120// m.call.answer
121void
122from_json(const json &obj, CallAnswer &content)
123{
124 content.call_id = obj.at(key: "call_id").get<std::string>();
125 content.answer = obj.at(key: "answer").get<RTCSessionDescriptionInit>();
126 content.version = version(obj);
127 if (content.version != "0") {
128 content.party_id = obj.at(key: "party_id").get<std::string>();
129 }
130}
131
132void
133to_json(json &obj, const CallAnswer &content)
134{
135 obj["call_id"] = content.call_id;
136 obj["answer"] = content.answer;
137 add_version(obj, version: content.version);
138 if (content.version != "0") {
139 obj["party_id"] = content.party_id;
140 }
141}
142
143// m.call.hangup
144void
145from_json(const json &obj, CallHangUp &content)
146{
147 content.call_id = obj.at(key: "call_id").get<std::string>();
148 content.version = version(obj);
149 if (content.version != "0") {
150 content.party_id = obj.at(key: "party_id").get<std::string>();
151 }
152 if (obj.count(key: "reason") == 0) {
153 content.reason = CallHangUp::Reason::User;
154 } else {
155 if (obj.at(key: "reason").get<std::string>() == "ice_failed")
156 content.reason = CallHangUp::Reason::ICEFailed;
157 else if (obj.at(key: "reason").get<std::string>() == "invite_timeout")
158 content.reason = CallHangUp::Reason::InviteTimeOut;
159 else if (obj.at(key: "reason").get<std::string>() == "ice_timeout")
160 content.reason = CallHangUp::Reason::ICETimeOut;
161 else if (obj.at(key: "reason").get<std::string>() == "user_hangup")
162 content.reason = CallHangUp::Reason::UserHangUp;
163 else if (obj.at(key: "reason").get<std::string>() == "user_media_failed")
164 content.reason = CallHangUp::Reason::UserMediaFailed;
165 else if (obj.at(key: "reason").get<std::string>() == "user_busy")
166 content.reason = CallHangUp::Reason::UserBusy;
167 else if (obj.at(key: "reason").get<std::string>() == "unknown_error")
168 content.reason = CallHangUp::Reason::UnknownError;
169 }
170}
171
172void
173to_json(json &obj, const CallHangUp &content)
174{
175 obj["call_id"] = content.call_id;
176 add_version(obj, version: content.version);
177 if (content.version != "0") {
178 obj["party_id"] = content.party_id;
179 }
180 if (content.reason == CallHangUp::Reason::ICEFailed)
181 obj["reason"] = "ice_failed";
182 else if (content.reason == CallHangUp::Reason::InviteTimeOut)
183 obj["reason"] = "invite_timeout";
184 else if (content.reason == CallHangUp::Reason::ICETimeOut)
185 obj["reason"] = "ice_timeout";
186 else if (content.reason == CallHangUp::Reason::UserHangUp)
187 obj["reason"] = "user_hangup";
188 else if (content.reason == CallHangUp::Reason::UserMediaFailed)
189 obj["reason"] = "user_media_failed";
190 else if (content.reason == CallHangUp::Reason::UserBusy)
191 obj["reason"] = "user_busy";
192 else if (content.reason == CallHangUp::Reason::UnknownError)
193 obj["reason"] = "unknown_error";
194}
195
196// m.call.select_answer
197void
198from_json(const json &obj, CallSelectAnswer &content)
199{
200 content.call_id = obj.at(key: "call_id").get<std::string>();
201 content.version = version(obj);
202 content.party_id = obj.at(key: "party_id").get<std::string>();
203 content.selected_party_id = obj.at(key: "selected_party_id").get<std::string>();
204}
205
206void
207to_json(json &obj, const CallSelectAnswer &content)
208{
209 obj["call_id"] = content.call_id;
210 add_version(obj, version: content.version);
211 obj["party_id"] = content.party_id;
212 obj["selected_party_id"] = content.selected_party_id;
213}
214
215// m.call.reject
216void
217from_json(const json &obj, CallReject &content)
218{
219 content.call_id = obj.at(key: "call_id").get<std::string>();
220 content.version = version(obj);
221 content.party_id = obj.at(key: "party_id").get<std::string>();
222}
223
224void
225to_json(json &obj, const CallReject &content)
226{
227 obj["call_id"] = content.call_id;
228 add_version(obj, version: content.version);
229 obj["party_id"] = content.party_id;
230}
231
232// m.call.negotiate
233void
234from_json(const json &obj, CallNegotiate &content)
235{
236 content.call_id = obj.at(key: "call_id").get<std::string>();
237 content.party_id = obj.at(key: "party_id").get<std::string>();
238 content.lifetime = obj.at(key: "lifetime").get<uint32_t>();
239 content.description = obj.at(key: "description");
240}
241
242void
243to_json(json &obj, const CallNegotiate &content)
244{
245 obj["call_id"] = content.call_id;
246 obj["party_id"] = content.party_id;
247 obj["lifetime"] = content.lifetime;
248 obj["description"] = content.description;
249}
250
251} // namespace mtx::events::voip
252