|
@@ -1,5 +1,5 @@
|
|
/**
|
|
/**
|
|
- * Copyright (c) 2019-2020 Paul-Louis Ageneau
|
|
|
|
|
|
+ * Copyright (c) 2019-2021 Paul-Louis Ageneau
|
|
*
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
@@ -134,8 +134,75 @@ void eraseTrack(int tr) {
|
|
userPointerMap.erase(tr);
|
|
userPointerMap.erase(tr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+shared_ptr<Channel> getChannel(int id) {
|
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
|
+ if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
|
|
|
|
+ return it->second;
|
|
|
|
+ if (auto it = trackMap.find(id); it != trackMap.end())
|
|
|
|
+ return it->second;
|
|
|
|
+#if RTC_ENABLE_WEBSOCKET
|
|
|
|
+ if (auto it = webSocketMap.find(id); it != webSocketMap.end())
|
|
|
|
+ return it->second;
|
|
|
|
+#endif
|
|
|
|
+ throw std::invalid_argument("DataChannel, Track, or WebSocket ID does not exist");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int copyAndReturn(string s, char *buffer, int size) {
|
|
|
|
+ if (!buffer)
|
|
|
|
+ return int(s.size() + 1);
|
|
|
|
+
|
|
|
|
+ if (size < int(s.size()))
|
|
|
|
+ return RTC_ERR_TOO_SMALL;
|
|
|
|
+
|
|
|
|
+ std::copy(s.begin(), s.end(), buffer);
|
|
|
|
+ buffer[s.size()] = '\0';
|
|
|
|
+ return int(s.size() + 1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int copyAndReturn(binary b, char *buffer, int size) {
|
|
|
|
+ if (!buffer)
|
|
|
|
+ return int(b.size());
|
|
|
|
+
|
|
|
|
+ if (size < int(b.size()))
|
|
|
|
+ return RTC_ERR_TOO_SMALL;
|
|
|
|
+
|
|
|
|
+ auto data = reinterpret_cast<const char *>(b.data());
|
|
|
|
+ std::copy(data, data + b.size(), buffer);
|
|
|
|
+ buffer[b.size()] = '\0';
|
|
|
|
+ return int(b.size());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template <typename T> int copyAndReturn(std::vector<T> b, T *buffer, int size) {
|
|
|
|
+ if (!buffer)
|
|
|
|
+ return int(b.size());
|
|
|
|
+
|
|
|
|
+ if (size < int(b.size()))
|
|
|
|
+ return RTC_ERR_TOO_SMALL;
|
|
|
|
+ std::copy(b.begin(), b.end(), buffer);
|
|
|
|
+ return int(b.size());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template <typename F> int wrap(F func) {
|
|
|
|
+ try {
|
|
|
|
+ return int(func());
|
|
|
|
+
|
|
|
|
+ } catch (const std::invalid_argument &e) {
|
|
|
|
+ PLOG_ERROR << e.what();
|
|
|
|
+ return RTC_ERR_INVALID;
|
|
|
|
+ } catch (const std::exception &e) {
|
|
|
|
+ PLOG_ERROR << e.what();
|
|
|
|
+ return RTC_ERR_FAILURE;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
#if RTC_ENABLE_MEDIA
|
|
#if RTC_ENABLE_MEDIA
|
|
|
|
|
|
|
|
+string lowercased(string str) {
|
|
|
|
+ std::transform(str.begin(), str.end(), str.begin(),
|
|
|
|
+ [](unsigned char c) { return std::tolower(c); });
|
|
|
|
+ return str;
|
|
|
|
+}
|
|
|
|
+
|
|
shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
|
|
shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
|
|
std::lock_guard lock(mutex);
|
|
std::lock_guard lock(mutex);
|
|
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
|
|
if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
|
|
@@ -243,75 +310,6 @@ void eraseWebSocketServer(int wsserver) {
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-shared_ptr<Channel> getChannel(int id) {
|
|
|
|
- std::lock_guard lock(mutex);
|
|
|
|
- if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
|
|
|
|
- return it->second;
|
|
|
|
- if (auto it = trackMap.find(id); it != trackMap.end())
|
|
|
|
- return it->second;
|
|
|
|
-#if RTC_ENABLE_WEBSOCKET
|
|
|
|
- if (auto it = webSocketMap.find(id); it != webSocketMap.end())
|
|
|
|
- return it->second;
|
|
|
|
-#endif
|
|
|
|
- throw std::invalid_argument("DataChannel, Track, or WebSocket ID does not exist");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-template <typename F> int wrap(F func) {
|
|
|
|
- try {
|
|
|
|
- return int(func());
|
|
|
|
-
|
|
|
|
- } catch (const std::invalid_argument &e) {
|
|
|
|
- PLOG_ERROR << e.what();
|
|
|
|
- return RTC_ERR_INVALID;
|
|
|
|
- } catch (const std::exception &e) {
|
|
|
|
- PLOG_ERROR << e.what();
|
|
|
|
- return RTC_ERR_FAILURE;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int copyAndReturn(string s, char *buffer, int size) {
|
|
|
|
- if (!buffer)
|
|
|
|
- return int(s.size() + 1);
|
|
|
|
-
|
|
|
|
- if (size < int(s.size()))
|
|
|
|
- return RTC_ERR_TOO_SMALL;
|
|
|
|
-
|
|
|
|
- std::copy(s.begin(), s.end(), buffer);
|
|
|
|
- buffer[s.size()] = '\0';
|
|
|
|
- return int(s.size() + 1);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int copyAndReturn(binary b, char *buffer, int size) {
|
|
|
|
- if (!buffer)
|
|
|
|
- return int(b.size());
|
|
|
|
-
|
|
|
|
- if (size < int(b.size()))
|
|
|
|
- return RTC_ERR_TOO_SMALL;
|
|
|
|
-
|
|
|
|
- auto data = reinterpret_cast<const char *>(b.data());
|
|
|
|
- std::copy(data, data + b.size(), buffer);
|
|
|
|
- buffer[b.size()] = '\0';
|
|
|
|
- return int(b.size());
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-template <typename T> int copyAndReturn(std::vector<T> b, T *buffer, int size) {
|
|
|
|
- if (!buffer)
|
|
|
|
- return int(b.size());
|
|
|
|
-
|
|
|
|
- if (size < int(b.size()))
|
|
|
|
- return RTC_ERR_TOO_SMALL;
|
|
|
|
- std::copy(b.begin(), b.end(), buffer);
|
|
|
|
- return int(b.size());
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#if RTC_ENABLE_MEDIA
|
|
|
|
-// function is used in RTC_ENABLE_MEDIA only
|
|
|
|
-string lowercased(string str) {
|
|
|
|
- std::transform(str.begin(), str.end(), str.begin(),
|
|
|
|
- [](unsigned char c) { return std::tolower(c); });
|
|
|
|
- return str;
|
|
|
|
-}
|
|
|
|
-#endif // RTC_ENABLE_MEDIA
|
|
|
|
} // namespace
|
|
} // namespace
|
|
|
|
|
|
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
|
|
void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
|
|
@@ -372,968 +370,969 @@ int rtcDeletePeerConnection(int pc) {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcCreateDataChannel(int pc, const char *label) {
|
|
|
|
- return rtcCreateDataChannelEx(pc, label, nullptr);
|
|
|
|
|
|
+int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onLocalDescription([pc, cb](Description desc) {
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ cb(pc, string(desc).c_str(), desc.typeString().c_str(), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onLocalDescription(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init) {
|
|
|
|
|
|
+int rtcSetLocalCandidateCallback(int pc, rtcCandidateCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- DataChannelInit dci = {};
|
|
|
|
- if (init) {
|
|
|
|
- auto *reliability = &init->reliability;
|
|
|
|
- dci.reliability.unordered = reliability->unordered;
|
|
|
|
- if (reliability->unreliable) {
|
|
|
|
- if (reliability->maxPacketLifeTime > 0) {
|
|
|
|
- dci.reliability.type = Reliability::Type::Timed;
|
|
|
|
- dci.reliability.rexmit = milliseconds(reliability->maxPacketLifeTime);
|
|
|
|
- } else {
|
|
|
|
- dci.reliability.type = Reliability::Type::Rexmit;
|
|
|
|
- dci.reliability.rexmit = reliability->maxRetransmits;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- dci.reliability.type = Reliability::Type::Reliable;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dci.negotiated = init->negotiated;
|
|
|
|
- dci.id = init->manualStream ? std::make_optional(init->stream) : nullopt;
|
|
|
|
- dci.protocol = init->protocol ? init->protocol : "";
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
auto peerConnection = getPeerConnection(pc);
|
|
auto peerConnection = getPeerConnection(pc);
|
|
- int dc = emplaceDataChannel(
|
|
|
|
- peerConnection->createDataChannel(string(label ? label : ""), std::move(dci)));
|
|
|
|
-
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- rtcSetUserPointer(dc, *ptr);
|
|
|
|
-
|
|
|
|
- return dc;
|
|
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onLocalCandidate([pc, cb](Candidate cand) {
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ cb(pc, cand.candidate().c_str(), cand.mid().c_str(), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onLocalCandidate(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcIsOpen(int cid) {
|
|
|
|
- return wrap([cid] { return getChannel(cid)->isOpen(); });
|
|
|
|
|
|
+int rtcSetStateChangeCallback(int pc, rtcStateChangeCallbackFunc cb) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ cb(pc, static_cast<rtcState>(state), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onStateChange(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcDeleteDataChannel(int dc) {
|
|
|
|
- return wrap([dc] {
|
|
|
|
- auto dataChannel = getDataChannel(dc);
|
|
|
|
- dataChannel->onOpen(nullptr);
|
|
|
|
- dataChannel->onClosed(nullptr);
|
|
|
|
- dataChannel->onError(nullptr);
|
|
|
|
- dataChannel->onMessage(nullptr);
|
|
|
|
- dataChannel->onBufferedAmountLow(nullptr);
|
|
|
|
- dataChannel->onAvailable(nullptr);
|
|
|
|
-
|
|
|
|
- eraseDataChannel(dc);
|
|
|
|
|
|
+int rtcSetGatheringStateChangeCallback(int pc, rtcGatheringStateCallbackFunc cb) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ cb(pc, static_cast<rtcGatheringState>(state), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onGatheringStateChange(nullptr);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
|
|
|
|
|
|
+int rtcSetSignalingStateChangeCallback(int pc, rtcSignalingStateCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- if (!mediaDescriptionSdp)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for track media description");
|
|
|
|
-
|
|
|
|
auto peerConnection = getPeerConnection(pc);
|
|
auto peerConnection = getPeerConnection(pc);
|
|
- Description::Media media{string(mediaDescriptionSdp)};
|
|
|
|
- int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- rtcSetUserPointer(tr, *ptr);
|
|
|
|
-
|
|
|
|
- return tr;
|
|
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onSignalingStateChange([pc, cb](PeerConnection::SignalingState state) {
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ cb(pc, static_cast<rtcSignalingState>(state), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onGatheringStateChange(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
|
|
|
|
|
|
+int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
auto peerConnection = getPeerConnection(pc);
|
|
auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onDataChannel([pc, cb](shared_ptr<DataChannel> dataChannel) {
|
|
|
|
+ int dc = emplaceDataChannel(dataChannel);
|
|
|
|
+ if (auto ptr = getUserPointer(pc)) {
|
|
|
|
+ rtcSetUserPointer(dc, *ptr);
|
|
|
|
+ cb(pc, dc, *ptr);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onDataChannel(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
|
|
- if (!init)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for track init");
|
|
|
|
-
|
|
|
|
- auto direction = static_cast<Description::Direction>(init->direction);
|
|
|
|
-
|
|
|
|
- string mid;
|
|
|
|
- if (init->mid) {
|
|
|
|
- mid = string(init->mid);
|
|
|
|
- } else {
|
|
|
|
- switch (init->codec) {
|
|
|
|
- case RTC_CODEC_H264:
|
|
|
|
- case RTC_CODEC_VP8:
|
|
|
|
- case RTC_CODEC_VP9:
|
|
|
|
- mid = "video";
|
|
|
|
- break;
|
|
|
|
- case RTC_CODEC_OPUS:
|
|
|
|
- mid = "audio";
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- mid = "video";
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- optional<Description::Media> optDescription = nullopt;
|
|
|
|
-
|
|
|
|
- switch (init->codec) {
|
|
|
|
- case RTC_CODEC_H264:
|
|
|
|
- case RTC_CODEC_VP8:
|
|
|
|
- case RTC_CODEC_VP9: {
|
|
|
|
- auto desc = Description::Video(mid, direction);
|
|
|
|
- switch (init->codec) {
|
|
|
|
- case RTC_CODEC_H264:
|
|
|
|
- desc.addH264Codec(init->payloadType);
|
|
|
|
- break;
|
|
|
|
- case RTC_CODEC_VP8:
|
|
|
|
- desc.addVP8Codec(init->payloadType);
|
|
|
|
- break;
|
|
|
|
- case RTC_CODEC_VP9:
|
|
|
|
- desc.addVP8Codec(init->payloadType);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- optDescription = desc;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case RTC_CODEC_OPUS: {
|
|
|
|
- auto desc = Description::Audio(mid, direction);
|
|
|
|
- switch (init->codec) {
|
|
|
|
- case RTC_CODEC_OPUS:
|
|
|
|
- desc.addOpusCodec(init->payloadType);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- optDescription = desc;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!optDescription)
|
|
|
|
- throw std::invalid_argument("Unexpected codec");
|
|
|
|
-
|
|
|
|
- auto desc = std::move(*optDescription);
|
|
|
|
- desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
|
|
|
|
- init->msid ? std::make_optional(string(init->msid)) : nullopt,
|
|
|
|
- init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
|
|
|
|
-
|
|
|
|
- int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
|
|
|
|
-
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- rtcSetUserPointer(tr, *ptr);
|
|
|
|
-
|
|
|
|
- return tr;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int rtcDeleteTrack(int tr) {
|
|
|
|
|
|
+int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- track->onOpen(nullptr);
|
|
|
|
- track->onClosed(nullptr);
|
|
|
|
- track->onError(nullptr);
|
|
|
|
- track->onMessage(nullptr);
|
|
|
|
- track->onBufferedAmountLow(nullptr);
|
|
|
|
- track->onAvailable(nullptr);
|
|
|
|
-
|
|
|
|
- eraseTrack(tr);
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ if (cb)
|
|
|
|
+ peerConnection->onTrack([pc, cb](shared_ptr<Track> track) {
|
|
|
|
+ int tr = emplaceTrack(track);
|
|
|
|
+ if (auto ptr = getUserPointer(pc)) {
|
|
|
|
+ rtcSetUserPointer(tr, *ptr);
|
|
|
|
+ cb(pc, tr, *ptr);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ peerConnection->onTrack(nullptr);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetTrackDescription(int tr, char *buffer, int size) {
|
|
|
|
|
|
+int rtcSetLocalDescription(int pc, const char *type) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- return copyAndReturn(track->description(), buffer, size);
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ peerConnection->setLocalDescription(type ? Description::stringToType(type)
|
|
|
|
+ : Description::Type::Unspec);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-#if RTC_ENABLE_MEDIA
|
|
|
|
-
|
|
|
|
-void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid,
|
|
|
|
- const char *_trackID) {
|
|
|
|
-
|
|
|
|
- optional<string> name = nullopt;
|
|
|
|
- if (_name) {
|
|
|
|
- name = string(_name);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- optional<string> msid = nullopt;
|
|
|
|
- if (_msid) {
|
|
|
|
- msid = string(_msid);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- optional<string> trackID = nullopt;
|
|
|
|
- if (_trackID) {
|
|
|
|
- trackID = string(_trackID);
|
|
|
|
- }
|
|
|
|
|
|
+int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
- description->addSSRC(ssrc, name, msid, trackID);
|
|
|
|
-}
|
|
|
|
|
|
+ if (!sdp)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for remote description");
|
|
|
|
|
|
-int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto track = getTrack(tr);
|
|
|
|
- // create RTP configuration
|
|
|
|
- auto rtpConfig = createRtpPacketizationConfig(init);
|
|
|
|
- // create packetizer
|
|
|
|
- auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
|
|
|
|
- : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
|
|
|
|
- auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
|
|
|
|
- // create H264 handler
|
|
|
|
- auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
|
|
|
|
- emplaceMediaChainableHandler(h264Handler, tr);
|
|
|
|
- emplaceRtpConfig(rtpConfig, tr);
|
|
|
|
- // set handler
|
|
|
|
- track->setMediaHandler(h264Handler);
|
|
|
|
|
|
+ peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""});
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
|
|
|
|
|
+int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- // create RTP configuration
|
|
|
|
- auto rtpConfig = createRtpPacketizationConfig(init);
|
|
|
|
- // create packetizer
|
|
|
|
- auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
|
|
|
|
- // create Opus handler
|
|
|
|
- auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
|
|
|
|
- emplaceMediaChainableHandler(opusHandler, tr);
|
|
|
|
- emplaceRtpConfig(rtpConfig, tr);
|
|
|
|
- // set handler
|
|
|
|
- track->setMediaHandler(opusHandler);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
-int rtcChainRtcpSrReporter(int tr) {
|
|
|
|
- return wrap([tr] {
|
|
|
|
- auto config = getRtpConfig(tr);
|
|
|
|
- auto reporter = std::make_shared<RtcpSrReporter>(config);
|
|
|
|
- emplaceRtcpSrReporter(reporter, tr);
|
|
|
|
- auto chainableHandler = getMediaChainableHandler(tr);
|
|
|
|
- chainableHandler->addToChain(reporter);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ if (!cand)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for remote candidate");
|
|
|
|
|
|
-int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
|
|
|
|
- return wrap([tr, maxStoredPacketsCount] {
|
|
|
|
- auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
|
|
|
|
- auto chainableHandler = getMediaChainableHandler(tr);
|
|
|
|
- chainableHandler->addToChain(responder);
|
|
|
|
|
|
+ peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""});
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
|
|
|
|
|
|
+int rtcGetLocalDescription(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
|
|
|
|
- : RtpPacketizationConfig::EpochStart::T1900;
|
|
|
|
- config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
-int rtcStartRtcpSenderReporterRecording(int id) {
|
|
|
|
- return wrap([id] {
|
|
|
|
- auto sender = getRtcpSrReporter(id);
|
|
|
|
- sender->startRecording();
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ if (auto desc = peerConnection->localDescription())
|
|
|
|
+ return copyAndReturn(string(*desc), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
|
|
|
|
|
|
+int rtcGetRemoteDescription(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- *timestamp = config->secondsToTimestamp(seconds);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
-int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- *seconds = config->timestampToSeconds(timestamp);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ if (auto desc = peerConnection->remoteDescription())
|
|
|
|
+ return copyAndReturn(string(*desc), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
|
|
|
|
|
|
+int rtcGetLocalDescriptionType(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- *timestamp = config->timestamp;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+
|
|
|
|
+ if (auto desc = peerConnection->localDescription())
|
|
|
|
+ return copyAndReturn(desc->typeString(), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
|
|
|
|
|
|
+int rtcGetRemoteDescriptionType(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- *timestamp = config->startTimestamp;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+
|
|
|
|
+ if (auto desc = peerConnection->remoteDescription())
|
|
|
|
+ return copyAndReturn(desc->typeString(), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
|
|
|
|
|
|
+int rtcGetLocalAddress(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto config = getRtpConfig(id);
|
|
|
|
- config->timestamp = timestamp;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+
|
|
|
|
+ if (auto addr = peerConnection->localAddress())
|
|
|
|
+ return copyAndReturn(std::move(*addr), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
|
|
|
|
|
|
+int rtcGetRemoteAddress(int pc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto sender = getRtcpSrReporter(id);
|
|
|
|
- *timestamp = sender->previousReportedTimestamp;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+
|
|
|
|
+ if (auto addr = peerConnection->remoteAddress())
|
|
|
|
+ return copyAndReturn(std::move(*addr), buffer, size);
|
|
|
|
+ else
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetNeedsToSendRtcpSr(int id) {
|
|
|
|
- return wrap([id] {
|
|
|
|
- auto sender = getRtcpSrReporter(id);
|
|
|
|
- sender->setNeedsToReport();
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote, int remoteSize) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+
|
|
|
|
+ Candidate localCand;
|
|
|
|
+ Candidate remoteCand;
|
|
|
|
+ if (!peerConnection->getSelectedCandidatePair(&localCand, &remoteCand))
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
|
|
+
|
|
|
|
+ int localRet = copyAndReturn(string(localCand), local, localSize);
|
|
|
|
+ if (localRet < 0)
|
|
|
|
+ return localRet;
|
|
|
|
+
|
|
|
|
+ int remoteRet = copyAndReturn(string(remoteCand), remote, remoteSize);
|
|
|
|
+ if (remoteRet < 0)
|
|
|
|
+ return remoteRet;
|
|
|
|
+
|
|
|
|
+ return std::max(localRet, remoteRet);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetTrackPayloadTypesForCodec(int tr, const char *ccodec, int *buffer, int size) {
|
|
|
|
|
|
+int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- auto codec = lowercased(string(ccodec));
|
|
|
|
- auto description = track->description();
|
|
|
|
- std::vector<int> payloadTypes{};
|
|
|
|
- payloadTypes.reserve(std::max(size, 0));
|
|
|
|
- for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
|
|
|
|
- auto element = *it;
|
|
|
|
- if (lowercased(element.second.format) == codec) {
|
|
|
|
- payloadTypes.push_back(element.first);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return copyAndReturn(payloadTypes, buffer, size);
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onOpen([id, cb]() {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ channel->onOpen(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetSsrcsForTrack(int tr, uint32_t *buffer, int count) {
|
|
|
|
|
|
+int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- auto ssrcs = track->description().getSSRCs();
|
|
|
|
- return copyAndReturn(ssrcs, buffer, count);
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onClosed([id, cb]() {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ channel->onClosed(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char *cname, int cnameSize) {
|
|
|
|
|
|
+int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto track = getTrack(tr);
|
|
|
|
- auto description = track->description();
|
|
|
|
- auto optCName = description.getCNameForSsrc(ssrc);
|
|
|
|
- if (optCName.has_value()) {
|
|
|
|
- return copyAndReturn(optCName.value(), cname, cnameSize);
|
|
|
|
- } else {
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onError([id, cb](string error) {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, error.c_str(), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ channel->onError(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetSsrcsForType(const char *mediaType, const char *sdp, uint32_t *buffer, int bufferSize) {
|
|
|
|
|
|
+int rtcSetMessageCallback(int id, rtcMessageCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto type = lowercased(string(mediaType));
|
|
|
|
- auto oldSDP = string(sdp);
|
|
|
|
- auto description = Description(oldSDP, "unspec");
|
|
|
|
- auto mediaCount = description.mediaCount();
|
|
|
|
- for (unsigned int i = 0; i < mediaCount; i++) {
|
|
|
|
- if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
|
|
|
- auto media = std::get<Description::Media *>(description.media(i));
|
|
|
|
- auto currentMediaType = lowercased(media->type());
|
|
|
|
- if (currentMediaType == type) {
|
|
|
|
- auto ssrcs = media->getSSRCs();
|
|
|
|
- return copyAndReturn(ssrcs, buffer, bufferSize);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onMessage(
|
|
|
|
+ [id, cb](binary b) {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, reinterpret_cast<const char *>(b.data()), int(b.size()), *ptr);
|
|
|
|
+ },
|
|
|
|
+ [id, cb](string s) {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, s.c_str(), -int(s.size() + 1), *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ channel->onMessage(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetSsrcForType(const char *mediaType, const char *sdp, char *buffer, const int bufferSize,
|
|
|
|
- rtcSsrcForTypeInit *init) {
|
|
|
|
|
|
+int rtcSendMessage(int id, const char *data, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto type = lowercased(string(mediaType));
|
|
|
|
- auto prevSDP = string(sdp);
|
|
|
|
- auto description = Description(prevSDP, "unspec");
|
|
|
|
- auto mediaCount = description.mediaCount();
|
|
|
|
- for (unsigned int i = 0; i < mediaCount; i++) {
|
|
|
|
- if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
|
|
|
- auto media = std::get<Description::Media *>(description.media(i));
|
|
|
|
- auto currentMediaType = lowercased(media->type());
|
|
|
|
- if (currentMediaType == type) {
|
|
|
|
- setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+
|
|
|
|
+ if (!data && size != 0)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for data");
|
|
|
|
+
|
|
|
|
+ if (size >= 0) {
|
|
|
|
+ auto b = reinterpret_cast<const byte *>(data);
|
|
|
|
+ channel->send(binary(b, b + size));
|
|
|
|
+ return size;
|
|
|
|
+ } else {
|
|
|
|
+ string str(data);
|
|
|
|
+ int len = int(str.size());
|
|
|
|
+ channel->send(std::move(str));
|
|
|
|
+ return len;
|
|
}
|
|
}
|
|
- return copyAndReturn(string(description), buffer, bufferSize);
|
|
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-#endif // RTC_ENABLE_MEDIA
|
|
|
|
-#if RTC_ENABLE_WEBSOCKET
|
|
|
|
|
|
+int rtcIsOpen(int id) {
|
|
|
|
+ return wrap([id] { return getChannel(id)->isOpen(); });
|
|
|
|
+}
|
|
|
|
|
|
-int rtcCreateWebSocket(const char *url) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto webSocket = std::make_shared<WebSocket>();
|
|
|
|
- webSocket->open(url);
|
|
|
|
- return emplaceWebSocket(webSocket);
|
|
|
|
|
|
+int rtcGetBufferedAmount(int id) {
|
|
|
|
+ return wrap([id] {
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ return int(channel->bufferedAmount());
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config) {
|
|
|
|
|
|
+int rtcSetBufferedAmountLowThreshold(int id, int amount) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- if (!url)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for URL");
|
|
|
|
-
|
|
|
|
- if (!config)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for config");
|
|
|
|
-
|
|
|
|
- WebSocket::Configuration c;
|
|
|
|
- c.disableTlsVerification = config->disableTlsVerification;
|
|
|
|
- auto webSocket = std::make_shared<WebSocket>(std::move(c));
|
|
|
|
- webSocket->open(url);
|
|
|
|
- return emplaceWebSocket(webSocket);
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ channel->setBufferedAmountLowThreshold(size_t(amount));
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcDeleteWebSocket(int ws) {
|
|
|
|
|
|
+int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto webSocket = getWebSocket(ws);
|
|
|
|
- webSocket->onOpen(nullptr);
|
|
|
|
- webSocket->onClosed(nullptr);
|
|
|
|
- webSocket->onError(nullptr);
|
|
|
|
- webSocket->onMessage(nullptr);
|
|
|
|
- webSocket->onBufferedAmountLow(nullptr);
|
|
|
|
- webSocket->onAvailable(nullptr);
|
|
|
|
-
|
|
|
|
- eraseWebSocket(ws);
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onBufferedAmountLow([id, cb]() {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, *ptr);
|
|
|
|
+ });
|
|
|
|
+ else
|
|
|
|
+ channel->onBufferedAmountLow(nullptr);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetWebSocketRemoteAddress(int ws, char *buffer, int size) {
|
|
|
|
|
|
+int rtcGetAvailableAmount(int id) {
|
|
|
|
+ return wrap([id] { return int(getChannel(id)->availableAmount()); });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto webSocket = getWebSocket(ws);
|
|
|
|
- if (auto remoteAddress = webSocket->remoteAddress())
|
|
|
|
- return copyAndReturn(*remoteAddress, buffer, size);
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+ if (cb)
|
|
|
|
+ channel->onAvailable([id, cb]() {
|
|
|
|
+ if (auto ptr = getUserPointer(id))
|
|
|
|
+ cb(id, *ptr);
|
|
|
|
+ });
|
|
else
|
|
else
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ channel->onAvailable(nullptr);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetWebSocketPath(int ws, char *buffer, int size) {
|
|
|
|
|
|
+int rtcReceiveMessage(int id, char *buffer, int *size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto webSocket = getWebSocket(ws);
|
|
|
|
- if (auto path = webSocket->path())
|
|
|
|
- return copyAndReturn(*path, buffer, size);
|
|
|
|
- else
|
|
|
|
|
|
+ auto channel = getChannel(id);
|
|
|
|
+
|
|
|
|
+ if (!size)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for size");
|
|
|
|
+
|
|
|
|
+ *size = std::abs(*size);
|
|
|
|
+
|
|
|
|
+ auto message = channel->peek();
|
|
|
|
+ if (!message)
|
|
return RTC_ERR_NOT_AVAIL;
|
|
return RTC_ERR_NOT_AVAIL;
|
|
|
|
+
|
|
|
|
+ return std::visit( //
|
|
|
|
+ overloaded{
|
|
|
|
+ [&](binary b) {
|
|
|
|
+ int ret = copyAndReturn(std::move(b), buffer, *size);
|
|
|
|
+ if (ret >= 0) {
|
|
|
|
+ channel->receive(); // discard
|
|
|
|
+ *size = ret;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ } else {
|
|
|
|
+ *size = int(b.size());
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ [&](string s) {
|
|
|
|
+ int ret = copyAndReturn(std::move(s), buffer, *size);
|
|
|
|
+ if (ret >= 0) {
|
|
|
|
+ channel->receive(); // discard
|
|
|
|
+ *size = -ret;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ } else {
|
|
|
|
+ *size = -int(s.size() + 1);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ *message);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-RTC_EXPORT int rtcCreateWebSocketServer(const rtcWsServerConfiguration *config,
|
|
|
|
- rtcWebSocketClientCallbackFunc cb) {
|
|
|
|
|
|
+int rtcCreateDataChannel(int pc, const char *label) {
|
|
|
|
+ return rtcCreateDataChannelEx(pc, label, nullptr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- if (!config)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for config");
|
|
|
|
|
|
+ DataChannelInit dci = {};
|
|
|
|
+ if (init) {
|
|
|
|
+ auto *reliability = &init->reliability;
|
|
|
|
+ dci.reliability.unordered = reliability->unordered;
|
|
|
|
+ if (reliability->unreliable) {
|
|
|
|
+ if (reliability->maxPacketLifeTime > 0) {
|
|
|
|
+ dci.reliability.type = Reliability::Type::Timed;
|
|
|
|
+ dci.reliability.rexmit = milliseconds(reliability->maxPacketLifeTime);
|
|
|
|
+ } else {
|
|
|
|
+ dci.reliability.type = Reliability::Type::Rexmit;
|
|
|
|
+ dci.reliability.rexmit = reliability->maxRetransmits;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ dci.reliability.type = Reliability::Type::Reliable;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!cb)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for client callback");
|
|
|
|
|
|
+ dci.negotiated = init->negotiated;
|
|
|
|
+ dci.id = init->manualStream ? std::make_optional(init->stream) : nullopt;
|
|
|
|
+ dci.protocol = init->protocol ? init->protocol : "";
|
|
|
|
+ }
|
|
|
|
|
|
- WebSocketServer::Configuration c;
|
|
|
|
- c.port = config->port;
|
|
|
|
- c.enableTls = config->enableTls;
|
|
|
|
- c.certificatePemFile = config->certificatePemFile
|
|
|
|
- ? make_optional(string(config->certificatePemFile))
|
|
|
|
- : nullopt;
|
|
|
|
- c.keyPemFile = config->keyPemFile ? make_optional(string(config->keyPemFile)) : nullopt;
|
|
|
|
- c.keyPemPass = config->keyPemPass ? make_optional(string(config->keyPemPass)) : nullopt;
|
|
|
|
- auto webSocketServer = std::make_shared<WebSocketServer>(std::move(c));
|
|
|
|
- int wsserver = emplaceWebSocketServer(webSocketServer);
|
|
|
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
|
+ int dc = emplaceDataChannel(
|
|
|
|
+ peerConnection->createDataChannel(string(label ? label : ""), std::move(dci)));
|
|
|
|
|
|
- webSocketServer->onClient([wsserver, cb](shared_ptr<WebSocket> webSocket) {
|
|
|
|
- int ws = emplaceWebSocket(webSocket);
|
|
|
|
- if (auto ptr = getUserPointer(wsserver)) {
|
|
|
|
- rtcSetUserPointer(wsserver, *ptr);
|
|
|
|
- cb(wsserver, ws, *ptr);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ rtcSetUserPointer(dc, *ptr);
|
|
|
|
|
|
- return wsserver;
|
|
|
|
|
|
+ return dc;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-RTC_EXPORT int rtcDeleteWebSocketServer(int wsserver) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto webSocketServer = getWebSocketServer(wsserver);
|
|
|
|
- webSocketServer->onClient(nullptr);
|
|
|
|
- webSocketServer->stop();
|
|
|
|
|
|
+int rtcDeleteDataChannel(int dc) {
|
|
|
|
+ return wrap([dc] {
|
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
|
+ dataChannel->onOpen(nullptr);
|
|
|
|
+ dataChannel->onClosed(nullptr);
|
|
|
|
+ dataChannel->onError(nullptr);
|
|
|
|
+ dataChannel->onMessage(nullptr);
|
|
|
|
+ dataChannel->onBufferedAmountLow(nullptr);
|
|
|
|
+ dataChannel->onAvailable(nullptr);
|
|
|
|
|
|
- eraseWebSocketServer(wsserver);
|
|
|
|
|
|
+ eraseDataChannel(dc);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-RTC_EXPORT int rtcGetWebSocketServerPort(int wsserver) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto webSocketServer = getWebSocketServer(wsserver);
|
|
|
|
- return int(webSocketServer->port());
|
|
|
|
|
|
+int rtcGetDataChannelStream(int dc) {
|
|
|
|
+ return wrap([dc] {
|
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
|
+ return int(dataChannel->id());
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- if (cb)
|
|
|
|
- peerConnection->onLocalDescription([pc, cb](Description desc) {
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- cb(pc, string(desc).c_str(), desc.typeString().c_str(), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onLocalDescription(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
|
+ return copyAndReturn(dataChannel->label(), buffer, size);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetLocalCandidateCallback(int pc, rtcCandidateCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetDataChannelProtocol(int dc, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- if (cb)
|
|
|
|
- peerConnection->onLocalCandidate([pc, cb](Candidate cand) {
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- cb(pc, cand.candidate().c_str(), cand.mid().c_str(), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onLocalCandidate(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
|
+ return copyAndReturn(dataChannel->protocol(), buffer, size);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetStateChangeCallback(int pc, rtcStateChangeCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetDataChannelReliability(int dc, rtcReliability *reliability) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- if (cb)
|
|
|
|
- peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- cb(pc, static_cast<rtcState>(state), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onStateChange(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
|
|
|
-int rtcSetGatheringStateChangeCallback(int pc, rtcGatheringStateCallbackFunc cb) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- if (cb)
|
|
|
|
- peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- cb(pc, static_cast<rtcGatheringState>(state), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onGatheringStateChange(nullptr);
|
|
|
|
|
|
+ if (!reliability)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for reliability");
|
|
|
|
+
|
|
|
|
+ Reliability dcr = dataChannel->reliability();
|
|
|
|
+ std::memset(reliability, 0, sizeof(*reliability));
|
|
|
|
+ reliability->unordered = dcr.unordered;
|
|
|
|
+ if (dcr.type == Reliability::Type::Timed) {
|
|
|
|
+ reliability->unreliable = true;
|
|
|
|
+ reliability->maxPacketLifeTime = int(std::get<milliseconds>(dcr.rexmit).count());
|
|
|
|
+ } else if (dcr.type == Reliability::Type::Rexmit) {
|
|
|
|
+ reliability->unreliable = true;
|
|
|
|
+ reliability->maxRetransmits = std::get<int>(dcr.rexmit);
|
|
|
|
+ } else {
|
|
|
|
+ reliability->unreliable = false;
|
|
|
|
+ }
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetSignalingStateChangeCallback(int pc, rtcSignalingStateCallbackFunc cb) {
|
|
|
|
|
|
+int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
|
|
+ if (!mediaDescriptionSdp)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for track media description");
|
|
|
|
+
|
|
auto peerConnection = getPeerConnection(pc);
|
|
auto peerConnection = getPeerConnection(pc);
|
|
- if (cb)
|
|
|
|
- peerConnection->onSignalingStateChange([pc, cb](PeerConnection::SignalingState state) {
|
|
|
|
- if (auto ptr = getUserPointer(pc))
|
|
|
|
- cb(pc, static_cast<rtcSignalingState>(state), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onGatheringStateChange(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ Description::Media media{string(mediaDescriptionSdp)};
|
|
|
|
+ int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ rtcSetUserPointer(tr, *ptr);
|
|
|
|
+
|
|
|
|
+ return tr;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb) {
|
|
|
|
|
|
+int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
auto peerConnection = getPeerConnection(pc);
|
|
auto peerConnection = getPeerConnection(pc);
|
|
- if (cb)
|
|
|
|
- peerConnection->onDataChannel([pc, cb](shared_ptr<DataChannel> dataChannel) {
|
|
|
|
- int dc = emplaceDataChannel(dataChannel);
|
|
|
|
- if (auto ptr = getUserPointer(pc)) {
|
|
|
|
- rtcSetUserPointer(dc, *ptr);
|
|
|
|
- cb(pc, dc, *ptr);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onDataChannel(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+
|
|
|
|
+ if (!init)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for track init");
|
|
|
|
+
|
|
|
|
+ auto direction = static_cast<Description::Direction>(init->direction);
|
|
|
|
+
|
|
|
|
+ string mid;
|
|
|
|
+ if (init->mid) {
|
|
|
|
+ mid = string(init->mid);
|
|
|
|
+ } else {
|
|
|
|
+ switch (init->codec) {
|
|
|
|
+ case RTC_CODEC_H264:
|
|
|
|
+ case RTC_CODEC_VP8:
|
|
|
|
+ case RTC_CODEC_VP9:
|
|
|
|
+ mid = "video";
|
|
|
|
+ break;
|
|
|
|
+ case RTC_CODEC_OPUS:
|
|
|
|
+ mid = "audio";
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ mid = "video";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ optional<Description::Media> optDescription = nullopt;
|
|
|
|
+
|
|
|
|
+ switch (init->codec) {
|
|
|
|
+ case RTC_CODEC_H264:
|
|
|
|
+ case RTC_CODEC_VP8:
|
|
|
|
+ case RTC_CODEC_VP9: {
|
|
|
|
+ auto desc = Description::Video(mid, direction);
|
|
|
|
+ switch (init->codec) {
|
|
|
|
+ case RTC_CODEC_H264:
|
|
|
|
+ desc.addH264Codec(init->payloadType);
|
|
|
|
+ break;
|
|
|
|
+ case RTC_CODEC_VP8:
|
|
|
|
+ desc.addVP8Codec(init->payloadType);
|
|
|
|
+ break;
|
|
|
|
+ case RTC_CODEC_VP9:
|
|
|
|
+ desc.addVP8Codec(init->payloadType);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ optDescription = desc;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case RTC_CODEC_OPUS: {
|
|
|
|
+ auto desc = Description::Audio(mid, direction);
|
|
|
|
+ switch (init->codec) {
|
|
|
|
+ case RTC_CODEC_OPUS:
|
|
|
|
+ desc.addOpusCodec(init->payloadType);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ optDescription = desc;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!optDescription)
|
|
|
|
+ throw std::invalid_argument("Unexpected codec");
|
|
|
|
+
|
|
|
|
+ auto desc = std::move(*optDescription);
|
|
|
|
+ desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
|
|
|
|
+ init->msid ? std::make_optional(string(init->msid)) : nullopt,
|
|
|
|
+ init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
|
|
|
|
+
|
|
|
|
+ int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
|
|
|
|
+
|
|
|
|
+ if (auto ptr = getUserPointer(pc))
|
|
|
|
+ rtcSetUserPointer(tr, *ptr);
|
|
|
|
+
|
|
|
|
+ return tr;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb) {
|
|
|
|
|
|
+int rtcDeleteTrack(int tr) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- if (cb)
|
|
|
|
- peerConnection->onTrack([pc, cb](shared_ptr<Track> track) {
|
|
|
|
- int tr = emplaceTrack(track);
|
|
|
|
- if (auto ptr = getUserPointer(pc)) {
|
|
|
|
- rtcSetUserPointer(tr, *ptr);
|
|
|
|
- cb(pc, tr, *ptr);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- peerConnection->onTrack(nullptr);
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ track->onOpen(nullptr);
|
|
|
|
+ track->onClosed(nullptr);
|
|
|
|
+ track->onError(nullptr);
|
|
|
|
+ track->onMessage(nullptr);
|
|
|
|
+ track->onBufferedAmountLow(nullptr);
|
|
|
|
+ track->onAvailable(nullptr);
|
|
|
|
+
|
|
|
|
+ eraseTrack(tr);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetLocalDescription(int pc, const char *type) {
|
|
|
|
|
|
+int rtcGetTrackDescription(int tr, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
- peerConnection->setLocalDescription(type ? Description::stringToType(type)
|
|
|
|
- : Description::Type::Unspec);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ return copyAndReturn(track->description(), buffer, size);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
+#if RTC_ENABLE_MEDIA
|
|
|
|
|
|
- if (!sdp)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for remote description");
|
|
|
|
|
|
+void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid,
|
|
|
|
+ const char *_trackID) {
|
|
|
|
|
|
- peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""});
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
|
|
+ optional<string> name = nullopt;
|
|
|
|
+ if (_name) {
|
|
|
|
+ name = string(_name);
|
|
|
|
+ }
|
|
|
|
|
|
-int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
+ optional<string> msid = nullopt;
|
|
|
|
+ if (_msid) {
|
|
|
|
+ msid = string(_msid);
|
|
|
|
+ }
|
|
|
|
|
|
- if (!cand)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for remote candidate");
|
|
|
|
|
|
+ optional<string> trackID = nullopt;
|
|
|
|
+ if (_trackID) {
|
|
|
|
+ trackID = string(_trackID);
|
|
|
|
+ }
|
|
|
|
|
|
- peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""});
|
|
|
|
|
|
+ description->addSSRC(ssrc, name, msid, trackID);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ // create RTP configuration
|
|
|
|
+ auto rtpConfig = createRtpPacketizationConfig(init);
|
|
|
|
+ // create packetizer
|
|
|
|
+ auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
|
|
|
|
+ : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
|
|
|
|
+ auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
|
|
|
|
+ // create H264 handler
|
|
|
|
+ auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
|
|
|
|
+ emplaceMediaChainableHandler(h264Handler, tr);
|
|
|
|
+ emplaceRtpConfig(rtpConfig, tr);
|
|
|
|
+ // set handler
|
|
|
|
+ track->setMediaHandler(h264Handler);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetLocalDescription(int pc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
-
|
|
|
|
- if (auto desc = peerConnection->localDescription())
|
|
|
|
- return copyAndReturn(string(*desc), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ // create RTP configuration
|
|
|
|
+ auto rtpConfig = createRtpPacketizationConfig(init);
|
|
|
|
+ // create packetizer
|
|
|
|
+ auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
|
|
|
|
+ // create Opus handler
|
|
|
|
+ auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
|
|
|
|
+ emplaceMediaChainableHandler(opusHandler, tr);
|
|
|
|
+ emplaceRtpConfig(rtpConfig, tr);
|
|
|
|
+ // set handler
|
|
|
|
+ track->setMediaHandler(opusHandler);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetRemoteDescription(int pc, char *buffer, int size) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
+int rtcChainRtcpSrReporter(int tr) {
|
|
|
|
+ return wrap([tr] {
|
|
|
|
+ auto config = getRtpConfig(tr);
|
|
|
|
+ auto reporter = std::make_shared<RtcpSrReporter>(config);
|
|
|
|
+ emplaceRtcpSrReporter(reporter, tr);
|
|
|
|
+ auto chainableHandler = getMediaChainableHandler(tr);
|
|
|
|
+ chainableHandler->addToChain(reporter);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
|
|
- if (auto desc = peerConnection->remoteDescription())
|
|
|
|
- return copyAndReturn(string(*desc), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
|
|
|
|
+ return wrap([tr, maxStoredPacketsCount] {
|
|
|
|
+ auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
|
|
|
|
+ auto chainableHandler = getMediaChainableHandler(tr);
|
|
|
|
+ chainableHandler->addToChain(responder);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetLocalDescriptionType(int pc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
|
|
|
|
+ : RtpPacketizationConfig::EpochStart::T1900;
|
|
|
|
+ config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
|
|
- if (auto desc = peerConnection->localDescription())
|
|
|
|
- return copyAndReturn(desc->typeString(), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+int rtcStartRtcpSenderReporterRecording(int id) {
|
|
|
|
+ return wrap([id] {
|
|
|
|
+ auto sender = getRtcpSrReporter(id);
|
|
|
|
+ sender->startRecording();
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetRemoteDescriptionType(int pc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
-
|
|
|
|
- if (auto desc = peerConnection->remoteDescription())
|
|
|
|
- return copyAndReturn(desc->typeString(), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ *timestamp = config->secondsToTimestamp(seconds);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetLocalAddress(int pc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
-
|
|
|
|
- if (auto addr = peerConnection->localAddress())
|
|
|
|
- return copyAndReturn(std::move(*addr), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ *seconds = config->timestampToSeconds(timestamp);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetRemoteAddress(int pc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
-
|
|
|
|
- if (auto addr = peerConnection->remoteAddress())
|
|
|
|
- return copyAndReturn(std::move(*addr), buffer, size);
|
|
|
|
- else
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ *timestamp = config->timestamp;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote, int remoteSize) {
|
|
|
|
|
|
+int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto peerConnection = getPeerConnection(pc);
|
|
|
|
-
|
|
|
|
- Candidate localCand;
|
|
|
|
- Candidate remoteCand;
|
|
|
|
- if (!peerConnection->getSelectedCandidatePair(&localCand, &remoteCand))
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
-
|
|
|
|
- int localRet = copyAndReturn(string(localCand), local, localSize);
|
|
|
|
- if (localRet < 0)
|
|
|
|
- return localRet;
|
|
|
|
-
|
|
|
|
- int remoteRet = copyAndReturn(string(remoteCand), remote, remoteSize);
|
|
|
|
- if (remoteRet < 0)
|
|
|
|
- return remoteRet;
|
|
|
|
-
|
|
|
|
- return std::max(localRet, remoteRet);
|
|
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ *timestamp = config->startTimestamp;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetDataChannelStream(int dc) {
|
|
|
|
- return wrap([dc] {
|
|
|
|
- auto dataChannel = getDataChannel(dc);
|
|
|
|
- return int(dataChannel->id());
|
|
|
|
|
|
+int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto config = getRtpConfig(id);
|
|
|
|
+ config->timestamp = timestamp;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
|
|
|
|
|
|
+int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto dataChannel = getDataChannel(dc);
|
|
|
|
- return copyAndReturn(dataChannel->label(), buffer, size);
|
|
|
|
|
|
+ auto sender = getRtcpSrReporter(id);
|
|
|
|
+ *timestamp = sender->previousReportedTimestamp;
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetDataChannelProtocol(int dc, char *buffer, int size) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto dataChannel = getDataChannel(dc);
|
|
|
|
- return copyAndReturn(dataChannel->protocol(), buffer, size);
|
|
|
|
|
|
+int rtcSetNeedsToSendRtcpSr(int id) {
|
|
|
|
+ return wrap([id] {
|
|
|
|
+ auto sender = getRtcpSrReporter(id);
|
|
|
|
+ sender->setNeedsToReport();
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetDataChannelReliability(int dc, rtcReliability *reliability) {
|
|
|
|
|
|
+int rtcGetTrackPayloadTypesForCodec(int tr, const char *ccodec, int *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto dataChannel = getDataChannel(dc);
|
|
|
|
-
|
|
|
|
- if (!reliability)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for reliability");
|
|
|
|
-
|
|
|
|
- Reliability dcr = dataChannel->reliability();
|
|
|
|
- std::memset(reliability, 0, sizeof(*reliability));
|
|
|
|
- reliability->unordered = dcr.unordered;
|
|
|
|
- if (dcr.type == Reliability::Type::Timed) {
|
|
|
|
- reliability->unreliable = true;
|
|
|
|
- reliability->maxPacketLifeTime = int(std::get<milliseconds>(dcr.rexmit).count());
|
|
|
|
- } else if (dcr.type == Reliability::Type::Rexmit) {
|
|
|
|
- reliability->unreliable = true;
|
|
|
|
- reliability->maxRetransmits = std::get<int>(dcr.rexmit);
|
|
|
|
- } else {
|
|
|
|
- reliability->unreliable = false;
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ auto codec = lowercased(string(ccodec));
|
|
|
|
+ auto description = track->description();
|
|
|
|
+ std::vector<int> payloadTypes{};
|
|
|
|
+ payloadTypes.reserve(std::max(size, 0));
|
|
|
|
+ for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
|
|
|
|
+ auto element = *it;
|
|
|
|
+ if (lowercased(element.second.format) == codec) {
|
|
|
|
+ payloadTypes.push_back(element.first);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ return copyAndReturn(payloadTypes, buffer, size);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetSsrcsForTrack(int tr, uint32_t *buffer, int count) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onOpen([id, cb]() {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- channel->onOpen(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ auto ssrcs = track->description().getSSRCs();
|
|
|
|
+ return copyAndReturn(ssrcs, buffer, count);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char *cname, int cnameSize) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onClosed([id, cb]() {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- channel->onClosed(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto track = getTrack(tr);
|
|
|
|
+ auto description = track->description();
|
|
|
|
+ auto optCName = description.getCNameForSsrc(ssrc);
|
|
|
|
+ if (optCName.has_value()) {
|
|
|
|
+ return copyAndReturn(optCName.value(), cname, cnameSize);
|
|
|
|
+ } else {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetSsrcsForType(const char *mediaType, const char *sdp, uint32_t *buffer, int bufferSize) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onError([id, cb](string error) {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, error.c_str(), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- channel->onError(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto type = lowercased(string(mediaType));
|
|
|
|
+ auto oldSDP = string(sdp);
|
|
|
|
+ auto description = Description(oldSDP, "unspec");
|
|
|
|
+ auto mediaCount = description.mediaCount();
|
|
|
|
+ for (unsigned int i = 0; i < mediaCount; i++) {
|
|
|
|
+ if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
|
|
|
+ auto media = std::get<Description::Media *>(description.media(i));
|
|
|
|
+ auto currentMediaType = lowercased(media->type());
|
|
|
|
+ if (currentMediaType == type) {
|
|
|
|
+ auto ssrcs = media->getSSRCs();
|
|
|
|
+ return copyAndReturn(ssrcs, buffer, bufferSize);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetMessageCallback(int id, rtcMessageCallbackFunc cb) {
|
|
|
|
|
|
+int rtcSetSsrcForType(const char *mediaType, const char *sdp, char *buffer, const int bufferSize,
|
|
|
|
+ rtcSsrcForTypeInit *init) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onMessage(
|
|
|
|
- [id, cb](binary b) {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, reinterpret_cast<const char *>(b.data()), int(b.size()), *ptr);
|
|
|
|
- },
|
|
|
|
- [id, cb](string s) {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, s.c_str(), -int(s.size() + 1), *ptr);
|
|
|
|
- });
|
|
|
|
- else
|
|
|
|
- channel->onMessage(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ auto type = lowercased(string(mediaType));
|
|
|
|
+ auto prevSDP = string(sdp);
|
|
|
|
+ auto description = Description(prevSDP, "unspec");
|
|
|
|
+ auto mediaCount = description.mediaCount();
|
|
|
|
+ for (unsigned int i = 0; i < mediaCount; i++) {
|
|
|
|
+ if (std::holds_alternative<Description::Media *>(description.media(i))) {
|
|
|
|
+ auto media = std::get<Description::Media *>(description.media(i));
|
|
|
|
+ auto currentMediaType = lowercased(media->type());
|
|
|
|
+ if (currentMediaType == type) {
|
|
|
|
+ setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return copyAndReturn(string(description), buffer, bufferSize);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSendMessage(int id, const char *data, int size) {
|
|
|
|
- return wrap([&] {
|
|
|
|
- auto channel = getChannel(id);
|
|
|
|
|
|
+#endif // RTC_ENABLE_MEDIA
|
|
|
|
|
|
- if (!data && size != 0)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for data");
|
|
|
|
|
|
+#if RTC_ENABLE_WEBSOCKET
|
|
|
|
|
|
- if (size >= 0) {
|
|
|
|
- auto b = reinterpret_cast<const byte *>(data);
|
|
|
|
- channel->send(binary(b, b + size));
|
|
|
|
- return size;
|
|
|
|
- } else {
|
|
|
|
- string str(data);
|
|
|
|
- int len = int(str.size());
|
|
|
|
- channel->send(std::move(str));
|
|
|
|
- return len;
|
|
|
|
- }
|
|
|
|
|
|
+int rtcCreateWebSocket(const char *url) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto webSocket = std::make_shared<WebSocket>();
|
|
|
|
+ webSocket->open(url);
|
|
|
|
+ return emplaceWebSocket(webSocket);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetBufferedAmount(int id) {
|
|
|
|
- return wrap([id] {
|
|
|
|
- auto channel = getChannel(id);
|
|
|
|
- return int(channel->bufferedAmount());
|
|
|
|
|
|
+int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ if (!url)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for URL");
|
|
|
|
+
|
|
|
|
+ if (!config)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for config");
|
|
|
|
+
|
|
|
|
+ WebSocket::Configuration c;
|
|
|
|
+ c.disableTlsVerification = config->disableTlsVerification;
|
|
|
|
+ auto webSocket = std::make_shared<WebSocket>(std::move(c));
|
|
|
|
+ webSocket->open(url);
|
|
|
|
+ return emplaceWebSocket(webSocket);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetBufferedAmountLowThreshold(int id, int amount) {
|
|
|
|
|
|
+int rtcDeleteWebSocket(int ws) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- channel->setBufferedAmountLowThreshold(size_t(amount));
|
|
|
|
|
|
+ auto webSocket = getWebSocket(ws);
|
|
|
|
+ webSocket->onOpen(nullptr);
|
|
|
|
+ webSocket->onClosed(nullptr);
|
|
|
|
+ webSocket->onError(nullptr);
|
|
|
|
+ webSocket->onMessage(nullptr);
|
|
|
|
+ webSocket->onBufferedAmountLow(nullptr);
|
|
|
|
+ webSocket->onAvailable(nullptr);
|
|
|
|
+
|
|
|
|
+ eraseWebSocket(ws);
|
|
return RTC_ERR_SUCCESS;
|
|
return RTC_ERR_SUCCESS;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetWebSocketRemoteAddress(int ws, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onBufferedAmountLow([id, cb]() {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, *ptr);
|
|
|
|
- });
|
|
|
|
|
|
+ auto webSocket = getWebSocket(ws);
|
|
|
|
+ if (auto remoteAddress = webSocket->remoteAddress())
|
|
|
|
+ return copyAndReturn(*remoteAddress, buffer, size);
|
|
else
|
|
else
|
|
- channel->onBufferedAmountLow(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcGetAvailableAmount(int id) {
|
|
|
|
- return wrap([id] { return int(getChannel(id)->availableAmount()); });
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb) {
|
|
|
|
|
|
+int rtcGetWebSocketPath(int ws, char *buffer, int size) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
- if (cb)
|
|
|
|
- channel->onAvailable([id, cb]() {
|
|
|
|
- if (auto ptr = getUserPointer(id))
|
|
|
|
- cb(id, *ptr);
|
|
|
|
- });
|
|
|
|
|
|
+ auto webSocket = getWebSocket(ws);
|
|
|
|
+ if (auto path = webSocket->path())
|
|
|
|
+ return copyAndReturn(*path, buffer, size);
|
|
else
|
|
else
|
|
- channel->onAvailable(nullptr);
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
|
|
+ return RTC_ERR_NOT_AVAIL;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
-int rtcReceiveMessage(int id, char *buffer, int *size) {
|
|
|
|
|
|
+RTC_EXPORT int rtcCreateWebSocketServer(const rtcWsServerConfiguration *config,
|
|
|
|
+ rtcWebSocketClientCallbackFunc cb) {
|
|
return wrap([&] {
|
|
return wrap([&] {
|
|
- auto channel = getChannel(id);
|
|
|
|
|
|
+ if (!config)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for config");
|
|
|
|
|
|
- if (!size)
|
|
|
|
- throw std::invalid_argument("Unexpected null pointer for size");
|
|
|
|
|
|
+ if (!cb)
|
|
|
|
+ throw std::invalid_argument("Unexpected null pointer for client callback");
|
|
|
|
|
|
- *size = std::abs(*size);
|
|
|
|
|
|
+ WebSocketServer::Configuration c;
|
|
|
|
+ c.port = config->port;
|
|
|
|
+ c.enableTls = config->enableTls;
|
|
|
|
+ c.certificatePemFile = config->certificatePemFile
|
|
|
|
+ ? make_optional(string(config->certificatePemFile))
|
|
|
|
+ : nullopt;
|
|
|
|
+ c.keyPemFile = config->keyPemFile ? make_optional(string(config->keyPemFile)) : nullopt;
|
|
|
|
+ c.keyPemPass = config->keyPemPass ? make_optional(string(config->keyPemPass)) : nullopt;
|
|
|
|
+ auto webSocketServer = std::make_shared<WebSocketServer>(std::move(c));
|
|
|
|
+ int wsserver = emplaceWebSocketServer(webSocketServer);
|
|
|
|
|
|
- auto message = channel->peek();
|
|
|
|
- if (!message)
|
|
|
|
- return RTC_ERR_NOT_AVAIL;
|
|
|
|
|
|
+ webSocketServer->onClient([wsserver, cb](shared_ptr<WebSocket> webSocket) {
|
|
|
|
+ int ws = emplaceWebSocket(webSocket);
|
|
|
|
+ if (auto ptr = getUserPointer(wsserver)) {
|
|
|
|
+ rtcSetUserPointer(wsserver, *ptr);
|
|
|
|
+ cb(wsserver, ws, *ptr);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
|
|
- return std::visit( //
|
|
|
|
- overloaded{
|
|
|
|
- [&](binary b) {
|
|
|
|
- int ret = copyAndReturn(std::move(b), buffer, *size);
|
|
|
|
- if (ret >= 0) {
|
|
|
|
- channel->receive(); // discard
|
|
|
|
- *size = ret;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- } else {
|
|
|
|
- *size = int(b.size());
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- [&](string s) {
|
|
|
|
- int ret = copyAndReturn(std::move(s), buffer, *size);
|
|
|
|
- if (ret >= 0) {
|
|
|
|
- channel->receive(); // discard
|
|
|
|
- *size = -ret;
|
|
|
|
- return RTC_ERR_SUCCESS;
|
|
|
|
- } else {
|
|
|
|
- *size = -int(s.size() + 1);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- *message);
|
|
|
|
|
|
+ return wsserver;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+RTC_EXPORT int rtcDeleteWebSocketServer(int wsserver) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto webSocketServer = getWebSocketServer(wsserver);
|
|
|
|
+ webSocketServer->onClient(nullptr);
|
|
|
|
+ webSocketServer->stop();
|
|
|
|
+
|
|
|
|
+ eraseWebSocketServer(wsserver);
|
|
|
|
+ return RTC_ERR_SUCCESS;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+RTC_EXPORT int rtcGetWebSocketServerPort(int wsserver) {
|
|
|
|
+ return wrap([&] {
|
|
|
|
+ auto webSocketServer = getWebSocketServer(wsserver);
|
|
|
|
+ return int(webSocketServer->port());
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#endif
|
|
|
|
+
|
|
void rtcPreload() { rtc::Preload(); }
|
|
void rtcPreload() { rtc::Preload(); }
|
|
|
|
|
|
void rtcCleanup() { rtc::Cleanup(); }
|
|
void rtcCleanup() { rtc::Cleanup(); }
|