|
@@ -102,6 +102,9 @@ void PeerConnection::setRemoteDescription(Description description,
|
|
std::optional<Description> mediaDescription) {
|
|
std::optional<Description> mediaDescription) {
|
|
PLOG_VERBOSE << "Setting remote description: " << string(description);
|
|
PLOG_VERBOSE << "Setting remote description: " << string(description);
|
|
|
|
|
|
|
|
+ if (!description.fingerprint())
|
|
|
|
+ throw std::runtime_error("Remote description is incomplete");
|
|
|
|
+
|
|
description.hintType(localDescription() ? Description::Type::Answer : Description::Type::Offer);
|
|
description.hintType(localDescription() ? Description::Type::Answer : Description::Type::Offer);
|
|
auto type = description.type();
|
|
auto type = description.type();
|
|
auto remoteCandidates = description.extractCandidates(); // Candidates will be added at the end
|
|
auto remoteCandidates = description.extractCandidates(); // Candidates will be added at the end
|
|
@@ -182,9 +185,8 @@ std::optional<string> PeerConnection::remoteAddress() const {
|
|
return iceTransport ? iceTransport->getRemoteAddress() : nullopt;
|
|
return iceTransport ? iceTransport->getRemoteAddress() : nullopt;
|
|
}
|
|
}
|
|
|
|
|
|
-shared_ptr<DataChannel> PeerConnection::createDataChannel(const string &label,
|
|
|
|
- const string &protocol,
|
|
|
|
- const Reliability &reliability) {
|
|
|
|
|
|
+shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, string protocol,
|
|
|
|
+ Reliability reliability) {
|
|
// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
|
|
// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
|
|
// setup:passive. [...] Thus, setup:active is RECOMMENDED.
|
|
// setup:passive. [...] Thus, setup:active is RECOMMENDED.
|
|
// See https://tools.ietf.org/html/rfc5763#section-5
|
|
// See https://tools.ietf.org/html/rfc5763#section-5
|
|
@@ -192,7 +194,8 @@ shared_ptr<DataChannel> PeerConnection::createDataChannel(const string &label,
|
|
auto iceTransport = std::atomic_load(&mIceTransport);
|
|
auto iceTransport = std::atomic_load(&mIceTransport);
|
|
auto role = iceTransport ? iceTransport->role() : Description::Role::Passive;
|
|
auto role = iceTransport ? iceTransport->role() : Description::Role::Passive;
|
|
|
|
|
|
- auto channel = emplaceDataChannel(role, label, protocol, reliability);
|
|
|
|
|
|
+ auto channel =
|
|
|
|
+ emplaceDataChannel(role, std::move(label), std::move(protocol), std::move(reliability));
|
|
|
|
|
|
if (!iceTransport) {
|
|
if (!iceTransport) {
|
|
// RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
|
|
// RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
|
|
@@ -214,12 +217,11 @@ void PeerConnection::onDataChannel(
|
|
mDataChannelCallback = callback;
|
|
mDataChannelCallback = callback;
|
|
}
|
|
}
|
|
|
|
|
|
-void PeerConnection::onLocalDescription(
|
|
|
|
- std::function<void(const Description &description)> callback) {
|
|
|
|
|
|
+void PeerConnection::onLocalDescription(std::function<void(Description description)> callback) {
|
|
mLocalDescriptionCallback = callback;
|
|
mLocalDescriptionCallback = callback;
|
|
}
|
|
}
|
|
|
|
|
|
-void PeerConnection::onLocalCandidate(std::function<void(const Candidate &candidate)> callback) {
|
|
|
|
|
|
+void PeerConnection::onLocalCandidate(std::function<void(Candidate candidate)> callback) {
|
|
mLocalCandidateCallback = callback;
|
|
mLocalCandidateCallback = callback;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -237,35 +239,17 @@ bool PeerConnection::hasMedia() const {
|
|
return (local && local->hasMedia()) || (remote && remote->hasMedia());
|
|
return (local && local->hasMedia()) || (remote && remote->hasMedia());
|
|
}
|
|
}
|
|
|
|
|
|
-void PeerConnection::sendMedia(const binary &packet) {
|
|
|
|
- outgoingMedia(make_message(packet.begin(), packet.end(), Message::Binary));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void PeerConnection::sendMedia(const byte *packet, size_t size) {
|
|
|
|
- outgoingMedia(make_message(packet, packet + size, Message::Binary));
|
|
|
|
-}
|
|
|
|
|
|
+std::shared_ptr<Track> PeerConnection::createTrack(Description::Media description) {
|
|
|
|
+ if (localDescription())
|
|
|
|
+ throw std::logic_error("Tracks must be created before local description");
|
|
|
|
|
|
-void PeerConnection::sendMedia(message_ptr ptr) {
|
|
|
|
- outgoingMedia(std::move(ptr));
|
|
|
|
|
|
+ auto track = std::make_shared<Track>(std::move(description));
|
|
|
|
+ mTracks.emplace(std::make_pair(track->mid(), track));
|
|
|
|
+ return track;
|
|
}
|
|
}
|
|
|
|
|
|
-void PeerConnection::onMedia(const std::function<void(rtc::message_ptr)>& callback) {
|
|
|
|
- mMediaCallback = callback;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void PeerConnection::outgoingMedia([[maybe_unused]] message_ptr message) {
|
|
|
|
- if (!hasMedia())
|
|
|
|
- throw std::runtime_error("PeerConnection has no media support");
|
|
|
|
-
|
|
|
|
-#if RTC_ENABLE_MEDIA
|
|
|
|
- auto transport = std::atomic_load(&mDtlsTransport);
|
|
|
|
- if (!transport)
|
|
|
|
- throw std::runtime_error("PeerConnection is not open");
|
|
|
|
-
|
|
|
|
- std::dynamic_pointer_cast<DtlsSrtpTransport>(transport)->sendMedia(message);
|
|
|
|
-#else
|
|
|
|
- PLOG_WARNING << "Ignoring sent media (not compiled with SRTP support)";
|
|
|
|
-#endif
|
|
|
|
|
|
+void PeerConnection::onTrack(std::function<void(std::shared_ptr<Track>)> callback) {
|
|
|
|
+ mTrackCallback = callback;
|
|
}
|
|
}
|
|
|
|
|
|
shared_ptr<IceTransport> PeerConnection::initIceTransport(Description::Role role) {
|
|
shared_ptr<IceTransport> PeerConnection::initIceTransport(Description::Role role) {
|
|
@@ -346,7 +330,8 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
|
|
|
|
|
|
switch (state) {
|
|
switch (state) {
|
|
case DtlsTransport::State::Connected:
|
|
case DtlsTransport::State::Connected:
|
|
- initSctpTransport();
|
|
|
|
|
|
+ initSctpTransport();
|
|
|
|
+ openTracks();
|
|
break;
|
|
break;
|
|
case DtlsTransport::State::Failed:
|
|
case DtlsTransport::State::Failed:
|
|
changeState(State::Failed);
|
|
changeState(State::Failed);
|
|
@@ -529,8 +514,16 @@ void PeerConnection::forwardMessage(message_ptr message) {
|
|
}
|
|
}
|
|
|
|
|
|
void PeerConnection::forwardMedia(message_ptr message) {
|
|
void PeerConnection::forwardMedia(message_ptr message) {
|
|
- if (message)
|
|
|
|
- mMediaCallback(message);
|
|
|
|
|
|
+ if (!message)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ string mid;
|
|
|
|
+ // TODO: stream (PT) to mid
|
|
|
|
+
|
|
|
|
+ std::shared_lock lock(mTracksMutex); // read-only
|
|
|
|
+ if (auto it = mTracks.find(mid); it != mTracks.end())
|
|
|
|
+ if (auto track = it->second.lock())
|
|
|
|
+ track->incoming(message);
|
|
}
|
|
}
|
|
|
|
|
|
void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) {
|
|
void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) {
|
|
@@ -538,10 +531,9 @@ void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) {
|
|
channel->triggerBufferedAmount(amount);
|
|
channel->triggerBufferedAmount(amount);
|
|
}
|
|
}
|
|
|
|
|
|
-shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role role,
|
|
|
|
- const string &label,
|
|
|
|
- const string &protocol,
|
|
|
|
- const Reliability &reliability) {
|
|
|
|
|
|
+shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role role, string label,
|
|
|
|
+ string protocol,
|
|
|
|
+ Reliability reliability) {
|
|
// The active side must use streams with even identifiers, whereas the passive side must use
|
|
// The active side must use streams with even identifiers, whereas the passive side must use
|
|
// streams with odd identifiers.
|
|
// streams with odd identifiers.
|
|
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09#section-6
|
|
// See https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09#section-6
|
|
@@ -552,8 +544,8 @@ shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role rol
|
|
if (stream >= 65535)
|
|
if (stream >= 65535)
|
|
throw std::runtime_error("Too many DataChannels");
|
|
throw std::runtime_error("Too many DataChannels");
|
|
}
|
|
}
|
|
- auto channel =
|
|
|
|
- std::make_shared<DataChannel>(shared_from_this(), stream, label, protocol, reliability);
|
|
|
|
|
|
+ auto channel = std::make_shared<DataChannel>(shared_from_this(), stream, std::move(label),
|
|
|
|
+ std::move(protocol), std::move(reliability));
|
|
mDataChannels.emplace(std::make_pair(stream, channel));
|
|
mDataChannels.emplace(std::make_pair(stream, channel));
|
|
return channel;
|
|
return channel;
|
|
}
|
|
}
|
|
@@ -602,6 +594,21 @@ void PeerConnection::openDataChannels() {
|
|
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->open(transport); });
|
|
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->open(transport); });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void PeerConnection::openTracks() {
|
|
|
|
+#if RTC_ENABLE_MEDIA
|
|
|
|
+ if (!hasMedia())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (auto transport = std::atomic_load(&mDtlsTransport)) {
|
|
|
|
+ auto srtpTransport = std::reinterpret_pointer_cast<DtlsSrtpTransport>(transport);
|
|
|
|
+ std::shared_lock lock(mTracksMutex); // read-only
|
|
|
|
+ for (auto it = mTracks.begin(); it != mTracks.end(); ++it)
|
|
|
|
+ if (auto track = it->second.lock())
|
|
|
|
+ track->open(srtpTransport);
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
void PeerConnection::closeDataChannels() {
|
|
void PeerConnection::closeDataChannels() {
|
|
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->close(); });
|
|
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->close(); });
|
|
}
|
|
}
|
|
@@ -618,20 +625,19 @@ void PeerConnection::processLocalDescription(Description description) {
|
|
remoteSctpPort = remote->sctpPort();
|
|
remoteSctpPort = remote->sctpPort();
|
|
}
|
|
}
|
|
|
|
|
|
- auto certificate = mCertificate.get(); // wait for certificate if not ready
|
|
|
|
|
|
+ if (remoteDataMid)
|
|
|
|
+ description.setDataMid(*remoteDataMid);
|
|
|
|
|
|
- {
|
|
|
|
- std::lock_guard lock(mLocalDescriptionMutex);
|
|
|
|
- mLocalDescription.emplace(std::move(description));
|
|
|
|
- if (remoteDataMid)
|
|
|
|
- mLocalDescription->setDataMid(*remoteDataMid);
|
|
|
|
-
|
|
|
|
- mLocalDescription->setFingerprint(certificate->fingerprint());
|
|
|
|
- mLocalDescription->setSctpPort(remoteSctpPort.value_or(DEFAULT_SCTP_PORT));
|
|
|
|
- mLocalDescription->setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
|
|
|
|
- }
|
|
|
|
|
|
+ description.setSctpPort(remoteSctpPort.value_or(DEFAULT_SCTP_PORT));
|
|
|
|
+ description.setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
|
|
|
|
+ description.setFingerprint(mCertificate.get()->fingerprint()); // wait for certificate
|
|
|
|
|
|
- mProcessor->enqueue([this]() { mLocalDescriptionCallback(*mLocalDescription); });
|
|
|
|
|
|
+ std::lock_guard lock(mLocalDescriptionMutex);
|
|
|
|
+ mLocalDescription.emplace(std::move(description));
|
|
|
|
+
|
|
|
|
+ mProcessor->enqueue([this, description = *mLocalDescription]() {
|
|
|
|
+ mLocalDescriptionCallback(std::move(description));
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
void PeerConnection::processLocalCandidate(Candidate candidate) {
|
|
void PeerConnection::processLocalCandidate(Candidate candidate) {
|
|
@@ -641,8 +647,9 @@ void PeerConnection::processLocalCandidate(Candidate candidate) {
|
|
|
|
|
|
mLocalDescription->addCandidate(candidate);
|
|
mLocalDescription->addCandidate(candidate);
|
|
|
|
|
|
- mProcessor->enqueue(
|
|
|
|
- [this, candidate = std::move(candidate)]() { mLocalCandidateCallback(candidate); });
|
|
|
|
|
|
+ mProcessor->enqueue([this, candidate = std::move(candidate)]() {
|
|
|
|
+ mLocalCandidateCallback(std::move(candidate));
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
|
|
void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
|
|
@@ -654,6 +661,14 @@ void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
|
|
[this, dataChannel = std::move(dataChannel)]() { mDataChannelCallback(dataChannel); });
|
|
[this, dataChannel = std::move(dataChannel)]() { mDataChannelCallback(dataChannel); });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void PeerConnection::triggerTrack(std::weak_ptr<Track> weakTrack) {
|
|
|
|
+ auto track = weakTrack.lock();
|
|
|
|
+ if (!track)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ mProcessor->enqueue([this, track = std::move(track)]() { mTrackCallback(track); });
|
|
|
|
+}
|
|
|
|
+
|
|
bool PeerConnection::changeState(State state) {
|
|
bool PeerConnection::changeState(State state) {
|
|
State current;
|
|
State current;
|
|
do {
|
|
do {
|