namespace { class LibSrtpInitializer { public: // Returns singleton instance of this class. Instance created on first use, // and never destroyed. static LibSrtpInitializer& Get() { static LibSrtpInitializer* const instance = new LibSrtpInitializer(); return *instance;
}
// There is only one global log handler in libsrtp so we can not resolve this // to a particular session. staticvoid LibSrtpLogHandler(srtp_log_level_t level, const char* msg, void* data); void ProhibitLibsrtpInitialization();
// These methods are responsible for initializing libsrtp (if the usage count // is incremented from 0 to 1) or deinitializing it (when decremented from 1 // to 0). // // Returns true if successful (will always be successful if already inited). bool IncrementLibsrtpUsageCountAndMaybeInit(
srtp_event_handler_func_t* event_handler); void DecrementLibsrtpUsageCountAndMaybeDeinit();
private:
LibSrtpInitializer() = default;
Mutex mutex_;
int usage_count_ RTC_GUARDED_BY(mutex_) = 0;
};
RTC_DCHECK_GE(usage_count_, 1);
if (--usage_count_ == 0) {
int err = srtp_install_log_handler(nullptr, nullptr);
if (err != srtp_err_status_ok) {
RTC_LOG(LS_ERROR) << "Failed to uninstall libsrtp log handler, err="
<< err;
}
err = srtp_shutdown();
if (err != srtp_err_status_ok) {
RTC_LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
}
}
}
} // namespace
// One more than the maximum libsrtp error code. Required by // RTC_HISTOGRAM_ENUMERATION. Keep this in sync with srtp_error_status_t defined // in srtp.h.
constexpr int kSrtpErrorCodeBoundary = 28;
bool SrtpSession::ProtectRtp(CopyOnWriteBuffer& buffer) {
RTC_DCHECK(thread_checker_.IsCurrent());
if (!session_) {
RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session"; return false;
}
// Note: the need_len differs from the libsrtp recommendatіon to ensure // SRTP_MAX_TRAILER_LEN bytes of free space after the data. WebRTC // never includes a MKI, therefore the amount of bytes added by the // srtp_protect call is known in advance and depends on the cipher suite.
size_t need_len = buffer.size() + rtp_auth_tag_len_; // NOLINT
if (buffer.capacity() < need_len) {
RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
<< buffer.capacity() << " is less than the needed "
<< need_len; return false;
}
if (dump_plain_rtp_) {
DumpPacket(buffer, /*outbound=*/true);
}
int out_len = buffer.size();
int err = srtp_protect(session_, buffer.MutableData<char>(), &out_len);
int seq_num = ParseRtpSequenceNumber(buffer);
if (err != srtp_err_status_ok) {
RTC_LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" << seq_num
<< ", err=" << err
<< ", last seqnum=" << last_send_seq_num_; return false;
}
buffer.SetSize(out_len);
last_send_seq_num_ = seq_num; returntrue;
}
bool SrtpSession::ProtectRtcp(CopyOnWriteBuffer& buffer) {
RTC_DCHECK(thread_checker_.IsCurrent());
if (!session_) {
RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session"; return false;
}
// Note: the need_len differs from the libsrtp recommendatіon to ensure // SRTP_MAX_TRAILER_LEN bytes of free space after the data. WebRTC // never includes a MKI, therefore the amount of bytes added by the // srtp_protect_rtp call is known in advance and depends on the cipher suite.
size_t need_len =
buffer.size() + sizeof(uint32_t) + rtcp_auth_tag_len_; // NOLINT
if (buffer.capacity() < need_len) {
RTC_LOG(LS_WARNING)
<< "Failed to protect SRTCP packet: The buffer capacity "
<< buffer.capacity() << " is less than the needed " << need_len; return false;
}
if (dump_plain_rtp_) {
DumpPacket(buffer, /*outbound=*/true);
}
int out_len = buffer.size();
int err = srtp_protect_rtcp(session_, buffer.MutableData<char>(), &out_len);
if (err != srtp_err_status_ok) {
RTC_LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err; return false;
}
buffer.SetSize(out_len); returntrue;
}
bool SrtpSession::UnprotectRtp(CopyOnWriteBuffer& buffer) {
RTC_DCHECK(thread_checker_.IsCurrent());
if (!session_) {
RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session"; return false;
}
int out_len = buffer.size();
int err = srtp_unprotect(session_, buffer.MutableData<char>(), &out_len);
if (err != srtp_err_status_ok) { // Limit the error logging to avoid excessive logs when there are lots of // bad packets. const int kFailureLogThrottleCount = 100;
if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
RTC_LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err
<< ", previous failure count: "
<< decryption_failure_count_;
}
++decryption_failure_count_;
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtpUnprotectError", static_cast<int>(err), kSrtpErrorCodeBoundary); return false;
}
buffer.SetSize(out_len);
if (dump_plain_rtp_) {
DumpPacket(buffer, /*outbound=*/false);
} returntrue;
}
bool SrtpSession::UnprotectRtcp(CopyOnWriteBuffer& buffer) {
RTC_DCHECK(thread_checker_.IsCurrent());
if (!session_) {
RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session"; return false;
}
int out_len = buffer.size();
int err = srtp_unprotect_rtcp(session_, buffer.MutableData<char>(), &out_len);
if (err != srtp_err_status_ok) {
RTC_LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SrtcpUnprotectError", static_cast<int>(err), kSrtpErrorCodeBoundary); return false;
}
buffer.SetSize(out_len);
if (dump_plain_rtp_) {
DumpPacket(buffer, /*outbound=*/false);
} returntrue;
}
int SrtpSession::GetSrtpOverhead() const { return rtp_auth_tag_len_;
}
bool SrtpSession::RemoveSsrcFromSession(uint32_t ssrc) {
RTC_DCHECK(session_); // libSRTP expects the SSRC to be in network byte order. return srtp_remove_stream(session_, htonl(ssrc)) == srtp_err_status_ok;
}
// This is the first time we need to actually interact with libsrtp, so // initialize it if needed.
if (LibSrtpInitializer::Get().IncrementLibsrtpUsageCountAndMaybeInit(
&SrtpSession::HandleEventThunk)) {
inited_ = true;
} else { return false;
}
void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) { // Callback will be executed from same thread that calls the "srtp_protect" // and "srtp_unprotect" functions.
SrtpSession* session = static_cast<SrtpSession*>(srtp_get_user_data(ev->session));
if (session) {
session->HandleEvent(ev);
}
}
// Logs the unencrypted packet in text2pcap format. This can then be // extracted by searching for RTP_DUMP // grep RTP_DUMP chrome_debug.log > in.txt // and converted to pcap using // text2pcap -D -u 1000,2000 -t %H:%M:%S.%f in.txt out.pcap // The resulting file can be replayed using the WebRTC video_replay tool and // be inspected in Wireshark using the RTP, VP8 and H264 dissectors. void SrtpSession::DumpPacket(const CopyOnWriteBuffer& buffer, bool outbound) {
RTC_LOG(LS_VERBOSE) << "\n"
<< Text2Pcap::DumpPacket(outbound, buffer,
TimeUTCMillis())
<< " # RTP_DUMP";
}
} // namespace webrtc
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-08-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.