void JsepTrack::NegotiateCodecs( const SdpMediaSection& remote, std::vector<JsepCodecDescription*>* codecs, std::map<std::string, std::string>* formatChanges) const { PtrVector<JsepCodecDescription> unnegotiatedCodecs; std::swap(unnegotiatedCodecs.values, *codecs); // Outer loop establishes the remote side's preference for (const std::string& fmt : remote.GetFormats()) { for (size_t i = 0; i < unnegotiatedCodecs.values.size(); ++i) { JsepCodecDescription* codec = unnegotiatedCodecs.values[i]; if (!codec || !codec->mEnabled || !codec->Matches(fmt, remote)) { continue; } std::string originalFormat = codec->mDefaultPt; if(codec->Negotiate(fmt, remote)) { codecs->push_back(codec); unnegotiatedCodecs.values[i] = nullptr; if (formatChanges) { (*formatChanges)[originalFormat] = codec->mDefaultPt; } break; } } } // Make sure strongly preferred codecs are up front, overriding the remote // side's preference. std::stable_sort(codecs->begin(), codecs->end(), CompareCodec); // TODO(bug 814227): Remove this once we're ready to put multiple codecs in an // answer if (!codecs->empty()) { for (size_t i = 1; i < codecs->size(); ++i) { delete (*codecs)[i]; (*codecs)[i] = nullptr; } codecs->resize(1); } }
void JsepTrack::NegotiateCodecs( const SdpMediaSection& remote, std::vector<JsepCodecDescription*>* codecs, std::map<std::string, std::string>* formatChanges) const { PtrVector<JsepCodecDescription> unnegotiatedCodecs; std::swap(unnegotiatedCodecs.values, *codecs); // Outer loop establishes the remote side's preference for (const std::string& fmt : remote.GetFormats()) { for (size_t i = 0; i < unnegotiatedCodecs.values.size(); ++i) { JsepCodecDescription* codec = unnegotiatedCodecs.values[i]; if (!codec || !codec->mEnabled || !codec->Matches(fmt, remote)) { continue; } std::string originalFormat = codec->mDefaultPt; if(codec->Negotiate(fmt, remote)) { codecs->push_back(codec); unnegotiatedCodecs.values[i] = nullptr; if (formatChanges) { (*formatChanges)[originalFormat] = codec->mDefaultPt; } break; } } } // Find the (potential) red codec and ulpfec codec JsepVideoCodecDescription* red = nullptr; JsepVideoCodecDescription* ulpfec = nullptr; for (auto codec : *codecs) { if (codec->mName == "red") { red = static_cast<JsepVideoCodecDescription*>(codec); } else if (codec->mName == "ulpfec") { ulpfec = static_cast<JsepVideoCodecDescription*>(codec); } } // if we have a red codec remove redundant encodings that don't exist if (red) { // Since we could have an externally specified redundant endcodings // list, we shouldn't simply rebuild the redundant encodings list // based on the current list of codecs. std::vector<uint8_t> unnegotiatedEncodings; std::swap(unnegotiatedEncodings, red->mRedundantEncodings); for (auto redundantPt : unnegotiatedEncodings) { std::string pt = std::to_string(redundantPt); for (auto codec : *codecs) { if (pt == codec->mDefaultPt) { red->mRedundantEncodings.push_back(redundantPt); break; } } } } // Video FEC is indicated by the existence of the red and ulpfec // codecs and not an attribute on the particular video codec (like in // a rtcpfb attr). If we see both red and ulpfec codecs, we enable FEC // on all the other codecs. if (red && ulpfec) { for (auto codec : *codecs) { if (codec->mName != "red" && codec->mName != "ulpfec") { JsepVideoCodecDescription* videoCodec = static_cast<JsepVideoCodecDescription*>(codec); videoCodec->EnableFec(); } } } // Make sure strongly preferred codecs are up front, overriding the remote // side's preference. std::stable_sort(codecs->begin(), codecs->end(), CompareCodec); // TODO(bug 814227): Remove this once we're ready to put multiple codecs in an // answer. For now, remove all but the first codec unless the red codec // exists, and then we include the others per RFC 5109, section 14.2. if (!codecs->empty() && !red) { for (size_t i = 1; i < codecs->size(); ++i) { delete (*codecs)[i]; (*codecs)[i] = nullptr; } codecs->resize(1); } }