Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add createOffer() and createAnswer() #1320

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ Initiates the handshake process. Following this call, the local description call
Arguments:

- `pc`: the Peer Connection identifier
- `type` (optional): type of the description ("offer", "answer", "pranswer", or "rollback") or NULL for autodetection.
- `type` (optional): type of the description ("offer", "answer", "pranswer", or "rollback") or NULL for automatic (recommended).

Warning: This function expects the optional type for the local description and not an SDP description. It is not possible to set an existing SDP description.

#### rtcSetRemoteDescription

Expand All @@ -220,7 +222,7 @@ Sets the remote description received from the remote peer by the user's method o
Arguments:

- `pc`: the Peer Connection identifier
- `type` (optional): type of the description ("offer", "answer", "pranswer", or "rollback") or NULL for autodetection.
- `type` (optional): type of the description ("offer", "answer", "pranswer", or "rollback") or NULL for automatic (not recommended).

If the remote description is an offer and `disableAutoNegotiation` was not set in `rtcConfiguration`, the library will automatically answer by calling `rtcSetLocalDescription` internally. Otherwise, the user must call it to answer the remote description.

Expand Down
3 changes: 2 additions & 1 deletion include/rtc/description.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ class RTC_CPP_EXPORT Description {
bool ended() const;

void hintType(Type type);
void setFingerprint(CertificateFingerprint f);
void addIceOption(string option);
void removeIceOption(const string &option);
void setIceAttribute(string ufrag, string pwd);
void setFingerprint(CertificateFingerprint f);

std::vector<string> attributes() const;
void addAttribute(string attr);
Expand Down
6 changes: 5 additions & 1 deletion include/rtc/peerconnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,13 @@ class RTC_CPP_EXPORT PeerConnection final : CheshireCat<impl::PeerConnection> {
bool getSelectedCandidatePair(Candidate *local, Candidate *remote);

void setLocalDescription(Description::Type type = Description::Type::Unspec, LocalDescriptionInit init = {});
void gatherLocalCandidates(std::vector<IceServer> additionalIceServers = {});
void setRemoteDescription(Description description);
void addRemoteCandidate(Candidate candidate);
void gatherLocalCandidates(std::vector<IceServer> additionalIceServers = {});

// For specific use cases only
Description createOffer();
Description createAnswer();

void setMediaHandler(shared_ptr<MediaHandler> handler);
shared_ptr<MediaHandler> getMediaHandler();
Expand Down
6 changes: 5 additions & 1 deletion include/rtc/rtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ RTC_C_EXPORT int rtcSetIceStateChangeCallback(int pc, rtcIceStateChangeCallbackF
RTC_C_EXPORT int rtcSetGatheringStateChangeCallback(int pc, rtcGatheringStateCallbackFunc cb);
RTC_C_EXPORT int rtcSetSignalingStateChangeCallback(int pc, rtcSignalingStateCallbackFunc cb);

RTC_C_EXPORT int rtcSetLocalDescription(int pc, const char *type);
RTC_C_EXPORT int rtcSetLocalDescription(int pc, const char *type); // type may be NULL
RTC_C_EXPORT int rtcSetRemoteDescription(int pc, const char *sdp, const char *type);
RTC_C_EXPORT int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid);

Expand All @@ -221,6 +221,10 @@ RTC_C_EXPORT int rtcGetRemoteDescription(int pc, char *buffer, int size);
RTC_C_EXPORT int rtcGetLocalDescriptionType(int pc, char *buffer, int size);
RTC_C_EXPORT int rtcGetRemoteDescriptionType(int pc, char *buffer, int size);

// For specific use cases only
RTC_C_EXPORT int rtcCreateOffer(int pc, char *buffer, int size);
RTC_C_EXPORT int rtcCreateAnswer(int pc, char *buffer, int size);

RTC_C_EXPORT int rtcGetLocalAddress(int pc, char *buffer, int size);
RTC_C_EXPORT int rtcGetRemoteAddress(int pc, char *buffer, int size);

Expand Down
18 changes: 18 additions & 0 deletions src/capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,24 @@ int rtcGetRemoteDescriptionType(int pc, char *buffer, int size) {
});
}

int rtcCreateOffer(int pc, char *buffer, int size) {
return wrap([&] {
auto peerConnection = getPeerConnection(pc);

auto desc = peerConnection->createOffer();
return copyAndReturn(string(desc), buffer, size);
});
}

int rtcCreateAnswer(int pc, char *buffer, int size) {
return wrap([&] {
auto peerConnection = getPeerConnection(pc);

auto desc = peerConnection->createAnswer();
return copyAndReturn(string(desc), buffer, size);
});
}

int rtcGetLocalAddress(int pc, char *buffer, int size) {
return wrap([&] {
auto peerConnection = getPeerConnection(pc);
Expand Down
25 changes: 15 additions & 10 deletions src/description.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ void Description::hintType(Type type) {
mType = type;
}

void Description::addIceOption(string option) {
if (std::find(mIceOptions.begin(), mIceOptions.end(), option) == mIceOptions.end())
mIceOptions.emplace_back(std::move(option));
}

void Description::removeIceOption(const string &option) {
mIceOptions.erase(std::remove(mIceOptions.begin(), mIceOptions.end(), option),
mIceOptions.end());
}

void Description::setIceAttribute(string ufrag, string pwd) {
mIceUfrag = std::move(ufrag);
mIcePwd = std::move(pwd);
}

void Description::setFingerprint(CertificateFingerprint f) {
if (!f.isValid())
throw std::invalid_argument("Invalid " +
Expand All @@ -227,16 +242,6 @@ void Description::setFingerprint(CertificateFingerprint f) {
mFingerprint = std::move(f);
}

void Description::addIceOption(string option) {
if (std::find(mIceOptions.begin(), mIceOptions.end(), option) == mIceOptions.end())
mIceOptions.emplace_back(std::move(option));
}

void Description::removeIceOption(const string &option) {
mIceOptions.erase(std::remove(mIceOptions.begin(), mIceOptions.end(), option),
mIceOptions.end());
}

std::vector<string> Description::Entry::attributes() const { return mAttributes; }

void Description::Entry::addAttribute(string attr) {
Expand Down
141 changes: 67 additions & 74 deletions src/impl/peerconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
PLOG_VERBOSE << "Remote description looks valid";
}

void PeerConnection::processLocalDescription(Description description) {
void PeerConnection::populateLocalDescription(Description &description) const {
const uint16_t localSctpPort = DEFAULT_SCTP_PORT;
const size_t localMaxMessageSize =
config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
Expand All @@ -935,7 +935,7 @@ void PeerConnection::processLocalDescription(Description description) {

if (auto remote = remoteDescription()) {
// Reciprocate remote description
for (int i = 0; i < remote->mediaCount(); ++i)
for (int i = 0; i < remote->mediaCount(); ++i) {
std::visit( // reciprocate each media
rtc::overloaded{
[&](Description::Application *remoteApp) {
Expand All @@ -950,78 +950,46 @@ void PeerConnection::processLocalDescription(Description description) {
<< app.mid() << "\"";

description.addMedia(std::move(app));
return;
}

auto reciprocated = remoteApp->reciprocate();
reciprocated.hintSctpPort(localSctpPort);
reciprocated.setMaxMessageSize(localMaxMessageSize);
} else {
auto reciprocated = remoteApp->reciprocate();
reciprocated.hintSctpPort(localSctpPort);
reciprocated.setMaxMessageSize(localMaxMessageSize);

PLOG_DEBUG << "Reciprocating application in local description, mid=\""
<< reciprocated.mid() << "\"";
PLOG_DEBUG << "Reciprocating application in local description, mid=\""
<< reciprocated.mid() << "\"";

description.addMedia(std::move(reciprocated));
description.addMedia(std::move(reciprocated));
}
},
[&](Description::Media *remoteMedia) {
std::unique_lock lock(mTracksMutex); // we may emplace a track
if (auto it = mTracks.find(remoteMedia->mid()); it != mTracks.end()) {
// Prefer local description
if (auto track = it->second.lock()) {
auto media = track->description();

PLOG_DEBUG << "Adding media to local description, mid=\""
<< media.mid() << "\", removed=" << std::boolalpha
<< media.isRemoved();

description.addMedia(std::move(media));

} else {
auto reciprocated = remoteMedia->reciprocate();
reciprocated.markRemoved();
std::shared_lock lock(mTracksMutex);
auto it = mTracks.find(remoteMedia->mid());
auto track = it != mTracks.end() ? it->second.lock() : nullptr;
if(track) {
// Prefer local description
auto media = track->description();

PLOG_DEBUG << "Adding media to local description, mid=\""
<< reciprocated.mid()
<< "\", removed=true (track is destroyed)";

description.addMedia(std::move(reciprocated));
}
return;
}

auto reciprocated = remoteMedia->reciprocate();
#if !RTC_ENABLE_MEDIA
if (!reciprocated.isRemoved()) {
// No media support, mark as removed
PLOG_WARNING << "Rejecting track (not compiled with media support)";
reciprocated.markRemoved();
}
#endif
PLOG_DEBUG << "Adding media to local description, mid=\""
<< media.mid() << "\", removed=" << std::boolalpha
<< media.isRemoved();

PLOG_DEBUG << "Reciprocating media in local description, mid=\""
<< reciprocated.mid() << "\", removed=" << std::boolalpha
<< reciprocated.isRemoved();
description.addMedia(std::move(media));

// Create incoming track
auto track =
std::make_shared<Track>(weak_from_this(), std::move(reciprocated));
mTracks.emplace(std::make_pair(track->mid(), track));
mTrackLines.emplace_back(track);
triggerTrack(track); // The user may modify the track description
} else {
auto reciprocated = remoteMedia->reciprocate();
reciprocated.markRemoved();

auto handler = getMediaHandler();
if (handler)
handler->media(track->description());
PLOG_DEBUG << "Adding media to local description, mid=\""
<< reciprocated.mid()
<< "\", removed=true (track is destroyed)";

if (track->description().isRemoved())
track->close();

description.addMedia(track->description());
description.addMedia(std::move(reciprocated));
}
},
},
remote->media(i));

// We need to update the SSRC cache for newly-created incoming tracks
updateTrackSsrcCache(*remote);
}
}

if (description.type() == Description::Type::Offer) {
Expand Down Expand Up @@ -1061,22 +1029,18 @@ void PeerConnection::processLocalDescription(Description description) {
description.addMedia(std::move(app));
}
}

// There might be no media at this point, for instance if the user deleted tracks
if (description.mediaCount() == 0)
throw std::runtime_error("No DataChannel or Track to negotiate");
}

// Set local fingerprint (wait for certificate if necessary)
description.setFingerprint(mCertificate.get()->fingerprint());
}

void PeerConnection::processLocalDescription(Description description) {
PLOG_VERBOSE << "Issuing local description: " << description;

if (description.mediaCount() == 0)
throw std::logic_error("Local description has no media line");

updateTrackSsrcCache(description);

{
// Set as local description
std::lock_guard lock(mLocalDescriptionMutex);
Expand All @@ -1093,11 +1057,6 @@ void PeerConnection::processLocalDescription(Description description) {

mProcessor.enqueue(&PeerConnection::trigger<Description>, shared_from_this(),
&localDescriptionCallback, std::move(description));

// Reciprocated tracks might need to be open
if (auto dtlsTransport = std::atomic_load(&mDtlsTransport);
dtlsTransport && dtlsTransport->state() == Transport::State::Connected)
mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this());
}

void PeerConnection::processLocalCandidate(Candidate candidate) {
Expand All @@ -1121,6 +1080,40 @@ void PeerConnection::processLocalCandidate(Candidate candidate) {
}

void PeerConnection::processRemoteDescription(Description description) {
// Create tracks from remote description
for (int i = 0; i < description.mediaCount(); ++i) {
if (std::holds_alternative<Description::Media *>(description.media(i))) {
auto remoteMedia = std::get<Description::Media *>(description.media(i));
std::unique_lock lock(mTracksMutex); // we may emplace a track
if (auto it = mTracks.find(remoteMedia->mid()); it != mTracks.end())
continue;

PLOG_DEBUG << "New remote track, mid=\"" << remoteMedia->mid() << "\"";

auto reciprocated = remoteMedia->reciprocate();
#if !RTC_ENABLE_MEDIA
if (!reciprocated.isRemoved()) {
// No media support, mark as removed
PLOG_WARNING << "Rejecting track (not compiled with media support)";
reciprocated.markRemoved();
}
#endif

// Create incoming track
auto track = std::make_shared<Track>(weak_from_this(), std::move(reciprocated));
mTracks.emplace(std::make_pair(track->mid(), track));
mTrackLines.emplace_back(track);
triggerTrack(track); // The user may modify the track description

auto handler = getMediaHandler();
if (handler)
handler->media(track->description());

if (track->description().isRemoved())
track->close();
}
}

// Update the SSRC cache for existing tracks
updateTrackSsrcCache(description);

Expand All @@ -1146,9 +1139,9 @@ void PeerConnection::processRemoteDescription(Description description) {
mProcessor.enqueue(&PeerConnection::remoteCloseDataChannels, shared_from_this());
}

// Reciprocated tracks might need to be open
if (dtlsTransport && dtlsTransport->state() == Transport::State::Connected)
mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this());

}

void PeerConnection::processRemoteCandidate(Candidate candidate) {
Expand Down Expand Up @@ -1238,7 +1231,7 @@ void PeerConnection::setMediaHandler(shared_ptr<MediaHandler> handler) {
mMediaHandler = handler;
}

shared_ptr<MediaHandler> PeerConnection::getMediaHandler() {
shared_ptr<MediaHandler> PeerConnection::getMediaHandler() const {
std::shared_lock lock(mMediaHandlerMutex);
return mMediaHandler;
}
Expand Down
3 changes: 2 additions & 1 deletion src/impl/peerconnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
void closeTracks();

void validateRemoteDescription(const Description &description);
void populateLocalDescription(Description &description) const;
void processLocalDescription(Description description);
void processLocalCandidate(Candidate candidate);
void processRemoteDescription(Description description);
Expand All @@ -84,7 +85,7 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
bool negotiationNeeded() const;

void setMediaHandler(shared_ptr<MediaHandler> handler);
shared_ptr<MediaHandler> getMediaHandler();
shared_ptr<MediaHandler> getMediaHandler() const;

void triggerDataChannel(weak_ptr<DataChannel> weakDataChannel);
void triggerTrack(weak_ptr<Track> weakTrack);
Expand Down
Loading
Loading