janus: ssrc per client

This commit is contained in:
Maxim Devaev
2026-05-31 07:11:44 +03:00
parent 9fe42b038a
commit 4dc0f73e1b
7 changed files with 55 additions and 41 deletions

View File

@@ -55,6 +55,9 @@ us_janus_client_s *us_janus_client_init(janus_callbacks *gw, janus_plugin_sessio
US_CALLOC(client, 1); US_CALLOC(client, 1);
client->gw = gw; client->gw = gw;
client->session = session; client->session = session;
client->video_ssrc = us_get_ssrc();
client->audio_ssrc = us_get_ssrc();
atomic_init(&client->transmit, false); atomic_init(&client->transmit, false);
atomic_init(&client->transmit_acap, false); atomic_init(&client->transmit_acap, false);
atomic_init(&client->transmit_aplay, false); atomic_init(&client->transmit_aplay, false);
@@ -181,6 +184,8 @@ static void *_video_or_acap_thread(void *v_client, bool video) {
atomic_load(&client->transmit) atomic_load(&client->transmit)
&& (video || atomic_load(&client->transmit_acap)) && (video || atomic_load(&client->transmit_acap))
) { ) {
us_rtp_write_ssrc(&rtp, (rtp.video ? client->video_ssrc : client->audio_ssrc));
janus_plugin_rtp packet = { janus_plugin_rtp packet = {
.video = rtp.video, .video = rtp.video,
.buffer = (char*)rtp.datagram, .buffer = (char*)rtp.datagram,

View File

@@ -37,6 +37,9 @@
typedef struct { typedef struct {
janus_callbacks *gw; janus_callbacks *gw;
janus_plugin_session *session; janus_plugin_session *session;
u32 video_ssrc;
u32 audio_ssrc;
atomic_bool transmit; atomic_bool transmit;
atomic_bool transmit_acap; atomic_bool transmit_acap;
atomic_bool transmit_aplay; atomic_bool transmit_aplay;

View File

@@ -641,14 +641,22 @@ static struct janus_plugin_result *_plugin_handle_message(
} }
{ {
char *const sdp = us_sdp_create( _LOCK_ALL;
_g_rtpv, US_LIST_ITERATE(_g_clients, client, {
(with_acap ? _g_rtpa : NULL), if (client->session == session) {
with_aplay); char *const sdp = us_sdp_create(
json_t *const offer_jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp); client->video_ssrc,
PUSH_STATUS("started", NULL, offer_jsep); client->audio_ssrc,
json_decref(offer_jsep); with_acap,
free(sdp); with_aplay);
json_t *const offer_jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp);
PUSH_STATUS("started", NULL, offer_jsep);
json_decref(offer_jsep);
free(sdp);
break;
}
});
_UNLOCK_ALL;
} }
{ {

View File

@@ -44,9 +44,11 @@ void us_rtp_destroy(us_rtp_s *rtp) {
void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video) { void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video) {
rtp->payload = payload; rtp->payload = payload;
rtp->video = video; rtp->video = video;
rtp->ssrc = us_triple_u32(us_get_now_monotonic_u64());
} }
#define WRITE_BE_U32(x_offset, x_value) \
*((u32*)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool last_header) { void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool last_header) {
u32 word0 = 0x80000000; u32 word0 = 0x80000000;
if (last_header) { if (last_header) {
@@ -56,10 +58,13 @@ void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool last_header) {
word0 |= rtp->seq; word0 |= rtp->seq;
++rtp->seq; ++rtp->seq;
# define WRITE_BE_U32(x_offset, x_value) \
*((u32*)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
WRITE_BE_U32(0, word0); WRITE_BE_U32(0, word0);
WRITE_BE_U32(4, pts); WRITE_BE_U32(4, pts);
WRITE_BE_U32(8, rtp->ssrc); WRITE_BE_U32(8, 0); // SSRC should be written separately for each client
# undef WRITE_BE_U32
} }
void us_rtp_write_ssrc(us_rtp_s *rtp, u32 ssrc) {
WRITE_BE_U32(8, ssrc);
}
#undef WRITE_BE_U32

View File

@@ -23,6 +23,7 @@
#pragma once #pragma once
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/tools.h"
// Max RTP size for WebRTC is 1200 bytes: // Max RTP size for WebRTC is 1200 bytes:
@@ -47,7 +48,6 @@
typedef struct { typedef struct {
uint payload; uint payload;
bool video; bool video;
u32 ssrc;
u16 seq; u16 seq;
u8 datagram[US_RTP_TOTAL_SIZE]; u8 datagram[US_RTP_TOTAL_SIZE];
@@ -62,8 +62,13 @@ typedef struct {
typedef void (*us_rtp_callback_f)(const us_rtp_s *rtp); typedef void (*us_rtp_callback_f)(const us_rtp_s *rtp);
static inline u32 us_get_ssrc(void) {
return us_triple_u32(us_get_now_monotonic_u64());
}
us_rtp_s *us_rtp_init(void); us_rtp_s *us_rtp_init(void);
void us_rtp_destroy(us_rtp_s *rtp); void us_rtp_destroy(us_rtp_s *rtp);
void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video); void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video);
void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool last_header); void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool last_header);
void us_rtp_write_ssrc(us_rtp_s *rtp, u32 ssrc);

View File

@@ -34,12 +34,12 @@
#include "rtpa.h" #include "rtpa.h"
char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic) { char *us_sdp_create(u32 video_ssrc, u32 audio_ssrc, bool acap, bool aplay) {
char *video_sdp; char *video_sdp;
{ {
// https://tools.ietf.org/html/rfc6184 // https://tools.ietf.org/html/rfc6184
// https://github.com/meetecho/janus-gateway/issues/2443 // https://github.com/meetecho/janus-gateway/issues/2443
const uint pl = rtpv->rtp->payload; const uint pl = US_RTP_H264_PAYLOAD;
US_ASPRINTF( US_ASPRINTF(
video_sdp, video_sdp,
"m=video 1 RTP/SAVPF %u" RN "m=video 1 RTP/SAVPF %u" RN
@@ -58,31 +58,20 @@ char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic) {
"a=extmap:3/sendonly http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time" RN "a=extmap:3/sendonly http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time" RN
"a=sendonly" RN, "a=sendonly" RN,
pl, pl, pl, pl, pl, pl, pl, pl, pl, pl, pl, pl, pl, pl,
rtpv->rtp->ssrc); video_ssrc);
} }
char *audio_sdp; char *audio_sdp;
if (rtpa == NULL) { if (acap || aplay) {
audio_sdp = us_strdup(""); const uint pl = US_RTP_OPUS_PAYLOAD;
} else {
char *dir = "";
if (rtpa != NULL || mic) { if (acap && aplay) {
uint pl; dir = "sendrecv";
u32 ssrc; } else if (acap && !aplay) {
if (rtpa != NULL) {
pl = rtpa->rtp->payload;
ssrc = rtpa->rtp->ssrc;
} else {
pl = US_RTP_OPUS_PAYLOAD;
ssrc = us_triple_u32(us_get_now_monotonic_u64());
}
char *dir = "sendrecv";
if (rtpa == NULL) {
dir = "recvonly";
} else if (!mic) {
dir = "sendonly"; dir = "sendonly";
} else if (!acap && aplay) {
dir = "recvonly";
} }
US_ASPRINTF( US_ASPRINTF(
@@ -98,8 +87,10 @@ char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic) {
pl, pl, pl, pl,
US_RTP_OPUS_HZ, US_RTP_OPUS_CH, US_RTP_OPUS_HZ, US_RTP_OPUS_CH,
pl, pl,
ssrc, audio_ssrc,
dir); dir);
} else {
audio_sdp = us_strdup("");
} }
char *sdp; char *sdp;

View File

@@ -24,8 +24,5 @@
#include "uslibs/types.h" #include "uslibs/types.h"
#include "rtpv.h"
#include "rtpa.h"
char *us_sdp_create(u32 video_ssrc, u32 audio_ssrc, bool acap, bool aplay);
char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic);