|
@@ -30,6 +30,7 @@
|
|
|
#include "dtlssrtptransport.hpp"
|
|
|
#endif
|
|
|
|
|
|
+#include <iomanip>
|
|
|
#include <thread>
|
|
|
|
|
|
namespace rtc {
|
|
@@ -100,10 +101,23 @@ void PeerConnection::setRemoteDescription(Description description) {
|
|
|
PLOG_VERBOSE << "Setting remote description: " << string(description);
|
|
|
|
|
|
if (description.mediaCount() == 0)
|
|
|
- throw std::runtime_error("Remote description has no media line");
|
|
|
+ throw std::invalid_argument("Remote description has no media line");
|
|
|
+
|
|
|
+ int activeMediaCount = 0;
|
|
|
+ for (int i = 0; i < description.mediaCount(); ++i)
|
|
|
+ std::visit( // reciprocate each media
|
|
|
+ rtc::overloaded{[&](Description::Application *) { ++activeMediaCount; },
|
|
|
+ [&](Description::Media *media) {
|
|
|
+ if (media->direction() != Description::Direction::Inactive)
|
|
|
+ ++activeMediaCount;
|
|
|
+ }},
|
|
|
+ description.media(i));
|
|
|
+
|
|
|
+ if (activeMediaCount == 0)
|
|
|
+ throw std::invalid_argument("Remote description has no active media");
|
|
|
|
|
|
if (!description.fingerprint())
|
|
|
- throw std::runtime_error("Remote description is incomplete");
|
|
|
+ throw std::invalid_argument("Remote description has no fingerprint");
|
|
|
|
|
|
description.hintType(localDescription() ? Description::Type::Answer : Description::Type::Offer);
|
|
|
auto type = description.type();
|
|
@@ -146,7 +160,7 @@ void PeerConnection::setRemoteDescription(Description description) {
|
|
|
|
|
|
for (const auto &candidate : remoteCandidates)
|
|
|
addRemoteCandidate(candidate);
|
|
|
-}
|
|
|
+ }
|
|
|
|
|
|
void PeerConnection::addRemoteCandidate(Candidate candidate) {
|
|
|
PLOG_VERBOSE << "Adding remote candidate: " << string(candidate);
|
|
@@ -185,6 +199,11 @@ std::optional<string> PeerConnection::remoteAddress() const {
|
|
|
|
|
|
shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, string protocol,
|
|
|
Reliability reliability) {
|
|
|
+ if (auto local = localDescription(); local && !local->hasApplication()) {
|
|
|
+ PLOG_ERROR << "The PeerConnection was negociated without DataChannel support.";
|
|
|
+ throw std::runtime_error("No DataChannel support on the PeerConnection");
|
|
|
+ }
|
|
|
+
|
|
|
// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
|
|
|
// setup:passive. [...] Thus, setup:active is RECOMMENDED.
|
|
|
// See https://tools.ietf.org/html/rfc5763#section-5
|
|
@@ -244,6 +263,11 @@ std::shared_ptr<Track> PeerConnection::createTrack(Description::Media descriptio
|
|
|
if (auto track = it->second.lock())
|
|
|
return track;
|
|
|
|
|
|
+#if !RTC_ENABLE_MEDIA
|
|
|
+ if (mTracks.empty()) {
|
|
|
+ PLOG_WARNING << "Tracks will be inative (not compiled with SRTP support)";
|
|
|
+ }
|
|
|
+#endif
|
|
|
auto track = std::make_shared<Track>(std::move(description));
|
|
|
mTracks.emplace(std::make_pair(track->mid(), track));
|
|
|
return track;
|
|
@@ -331,9 +355,10 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
|
|
|
|
|
|
switch (state) {
|
|
|
case DtlsTransport::State::Connected:
|
|
|
- if (auto local = localDescription())
|
|
|
- if (local->hasApplication())
|
|
|
- initSctpTransport();
|
|
|
+ if (auto local = localDescription(); local && local->hasApplication())
|
|
|
+ initSctpTransport();
|
|
|
+ else
|
|
|
+ changeState(State::Connected);
|
|
|
|
|
|
openTracks();
|
|
|
break;
|
|
@@ -410,13 +435,7 @@ shared_ptr<SctpTransport> PeerConnection::initSctpTransport() {
|
|
|
case SctpTransport::State::Failed:
|
|
|
LOG_WARNING << "SCTP transport failed";
|
|
|
remoteCloseDataChannels();
|
|
|
-#if RTC_ENABLE_MEDIA
|
|
|
- // Ignore SCTP failure if media is present
|
|
|
- if (!hasMedia())
|
|
|
- changeState(State::Failed);
|
|
|
-#else
|
|
|
changeState(State::Failed);
|
|
|
-#endif
|
|
|
break;
|
|
|
case SctpTransport::State::Disconnected:
|
|
|
remoteCloseDataChannels();
|
|
@@ -652,6 +671,11 @@ void PeerConnection::remoteCloseDataChannels() {
|
|
|
|
|
|
void PeerConnection::incomingTrack(Description::Media description) {
|
|
|
std::unique_lock lock(mTracksMutex); // we are going to emplace
|
|
|
+#if !RTC_ENABLE_MEDIA
|
|
|
+ if (mTracks.empty()) {
|
|
|
+ PLOG_WARNING << "Tracks will be inative (not compiled with SRTP support)";
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (mTracks.find(description.mid()) == mTracks.end()) {
|
|
|
auto track = std::make_shared<Track>(std::move(description));
|
|
|
mTracks.emplace(std::make_pair(track->mid(), track));
|
|
@@ -676,31 +700,40 @@ void PeerConnection::openTracks() {
|
|
|
|
|
|
|
|
|
void PeerConnection::processLocalDescription(Description description) {
|
|
|
+ int activeMediaCount = 0;
|
|
|
+
|
|
|
if (auto remote = remoteDescription()) {
|
|
|
// Reciprocate remote description
|
|
|
for (int i = 0; i < remote->mediaCount(); ++i)
|
|
|
std::visit( // reciprocate each media
|
|
|
rtc::overloaded{
|
|
|
[&](Description::Application *app) {
|
|
|
- PLOG_DEBUG << "Reciprocating application in local description, mid=\""
|
|
|
- << app->mid() << "\"";
|
|
|
auto reciprocated = app->reciprocate();
|
|
|
reciprocated.hintSctpPort(DEFAULT_SCTP_PORT);
|
|
|
reciprocated.setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
|
|
|
+ ++activeMediaCount;
|
|
|
+
|
|
|
+ PLOG_DEBUG << "Reciprocating application in local description, mid=\""
|
|
|
+ << reciprocated.mid() << "\"";
|
|
|
+
|
|
|
description.addMedia(std::move(reciprocated));
|
|
|
},
|
|
|
[&](Description::Media *media) {
|
|
|
- PLOG_DEBUG << "Reciprocating media in local description, mid=\""
|
|
|
- << media->mid() << "\"";
|
|
|
-
|
|
|
auto reciprocated = media->reciprocate();
|
|
|
#if RTC_ENABLE_MEDIA
|
|
|
if (reciprocated.direction() != Description::Direction::Inactive)
|
|
|
- incomingTrack(reciprocated);
|
|
|
+ ++activeMediaCount;
|
|
|
#else
|
|
|
// No media support, mark as inactive
|
|
|
reciprocated.setDirection(Description::Direction::Inactive);
|
|
|
#endif
|
|
|
+ incomingTrack(reciprocated);
|
|
|
+
|
|
|
+ PLOG_DEBUG
|
|
|
+ << "Reciprocating media in local description, mid=\""
|
|
|
+ << reciprocated.mid() << "\", active=" << std::boolalpha
|
|
|
+ << (reciprocated.direction() != Description::Direction::Inactive);
|
|
|
+
|
|
|
description.addMedia(std::move(reciprocated));
|
|
|
},
|
|
|
},
|
|
@@ -710,11 +743,14 @@ void PeerConnection::processLocalDescription(Description description) {
|
|
|
{
|
|
|
std::shared_lock lock(mDataChannelsMutex);
|
|
|
if (!mDataChannels.empty()) {
|
|
|
- const string mid = "data";
|
|
|
- PLOG_DEBUG << "Adding application to local description, mid=\"" << mid << "\"";
|
|
|
- Description::Application app;
|
|
|
+ Description::Application app("data");
|
|
|
app.setSctpPort(DEFAULT_SCTP_PORT);
|
|
|
app.setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
|
|
|
+ ++activeMediaCount;
|
|
|
+
|
|
|
+ PLOG_DEBUG << "Adding application to local description, mid=\"" << app.mid()
|
|
|
+ << "\"";
|
|
|
+
|
|
|
description.addMedia(std::move(app));
|
|
|
}
|
|
|
}
|
|
@@ -724,19 +760,28 @@ void PeerConnection::processLocalDescription(Description description) {
|
|
|
std::shared_lock lock(mTracksMutex);
|
|
|
for (auto it = mTracks.begin(); it != mTracks.end(); ++it) {
|
|
|
if (auto track = it->second.lock()) {
|
|
|
- PLOG_DEBUG << "Adding media to local description, mid=\"" << track->mid()
|
|
|
- << "\"";
|
|
|
auto media = track->description();
|
|
|
-#if !RTC_ENABLE_MEDIA
|
|
|
+#if RTC_ENABLE_MEDIA
|
|
|
+ if (media.direction() != Description::Direction::Inactive)
|
|
|
+ ++activeMediaCount;
|
|
|
+#else
|
|
|
// No media support, mark as inactive
|
|
|
media.setDirection(Description::Direction::Inactive);
|
|
|
#endif
|
|
|
+ PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid()
|
|
|
+ << "\", active=" << std::boolalpha
|
|
|
+ << (media.direction() != Description::Direction::Inactive);
|
|
|
+
|
|
|
description.addMedia(std::move(media));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // There must be at least one active media to negociate
|
|
|
+ if (activeMediaCount == 0)
|
|
|
+ throw std::runtime_error("Nothing to negociate");
|
|
|
+
|
|
|
// Set local fingerprint (wait for certificate if necessary)
|
|
|
description.setFingerprint(mCertificate.get()->fingerprint());
|
|
|
|