mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-18 02:55:46 +00:00
refactoring, increased bitrate, reduced buffers
This commit is contained in:
parent
10595a13e9
commit
a94ff667b0
@ -38,6 +38,7 @@
|
|||||||
#include "uslibs/ring.h"
|
#include "uslibs/ring.h"
|
||||||
#include "uslibs/threading.h"
|
#include "uslibs/threading.h"
|
||||||
|
|
||||||
|
#include "rtp.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
|
||||||
@ -49,14 +50,13 @@
|
|||||||
// - https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
|
// - https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
|
||||||
// #define _HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
|
// #define _HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
|
||||||
#define _HZ_TO_FRAMES(_hz) ((_hz) / 50) // 20ms
|
#define _HZ_TO_FRAMES(_hz) ((_hz) / 50) // 20ms
|
||||||
#define _HZ_TO_BUF16(_hz) (_HZ_TO_FRAMES(_hz) * 2) // One stereo frame = (16bit L) + (16bit R)
|
#define _HZ_TO_BUF16(_hz) (_HZ_TO_FRAMES(_hz) * US_RTP_OPUS_CH) // ... * 2: One stereo frame = (16bit L) + (16bit R)
|
||||||
#define _HZ_TO_BUF8(_hz) (_HZ_TO_BUF16(_hz) * sizeof(s16))
|
#define _HZ_TO_BUF8(_hz) (_HZ_TO_BUF16(_hz) * sizeof(s16))
|
||||||
|
|
||||||
#define _MIN_PCM_HZ 8000
|
#define _MIN_PCM_HZ 8000
|
||||||
#define _MAX_PCM_HZ 192000
|
#define _MAX_PCM_HZ 192000
|
||||||
#define _MAX_BUF16 _HZ_TO_BUF16(_MAX_PCM_HZ)
|
#define _MAX_BUF16 _HZ_TO_BUF16(_MAX_PCM_HZ)
|
||||||
#define _MAX_BUF8 _HZ_TO_BUF8(_MAX_PCM_HZ)
|
#define _MAX_BUF8 _HZ_TO_BUF8(_MAX_PCM_HZ)
|
||||||
#define _ENCODER_INPUT_HZ 48000
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -64,7 +64,7 @@ typedef struct {
|
|||||||
} _pcm_buffer_s;
|
} _pcm_buffer_s;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 data[_MAX_BUF8]; // Worst case
|
u8 data[US_RTP_PAYLOAD_SIZE];
|
||||||
uz used;
|
uz used;
|
||||||
u64 pts;
|
u64 pts;
|
||||||
} _enc_buffer_s;
|
} _enc_buffer_s;
|
||||||
@ -117,7 +117,7 @@ us_acap_s *us_acap_init(const char *name, uint pcm_hz) {
|
|||||||
|
|
||||||
SET_PARAM("Can't initialize PCM params", snd_pcm_hw_params_any);
|
SET_PARAM("Can't initialize PCM params", snd_pcm_hw_params_any);
|
||||||
SET_PARAM("Can't set PCM access type", snd_pcm_hw_params_set_access, SND_PCM_ACCESS_RW_INTERLEAVED);
|
SET_PARAM("Can't set PCM access type", snd_pcm_hw_params_set_access, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
SET_PARAM("Can't set PCM channels numbre", snd_pcm_hw_params_set_channels, 2);
|
SET_PARAM("Can't set PCM channels number", snd_pcm_hw_params_set_channels, US_RTP_OPUS_CH);
|
||||||
SET_PARAM("Can't set PCM sampling format", snd_pcm_hw_params_set_format, SND_PCM_FORMAT_S16_LE);
|
SET_PARAM("Can't set PCM sampling format", snd_pcm_hw_params_set_format, SND_PCM_FORMAT_S16_LE);
|
||||||
SET_PARAM("Can't set PCM sampling rate", snd_pcm_hw_params_set_rate_near, &acap->pcm_hz, 0);
|
SET_PARAM("Can't set PCM sampling rate", snd_pcm_hw_params_set_rate_near, &acap->pcm_hz, 0);
|
||||||
if (acap->pcm_hz < _MIN_PCM_HZ || acap->pcm_hz > _MAX_PCM_HZ) {
|
if (acap->pcm_hz < _MIN_PCM_HZ || acap->pcm_hz > _MAX_PCM_HZ) {
|
||||||
@ -132,8 +132,8 @@ us_acap_s *us_acap_init(const char *name, uint pcm_hz) {
|
|||||||
# undef SET_PARAM
|
# undef SET_PARAM
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acap->pcm_hz != _ENCODER_INPUT_HZ) {
|
if (acap->pcm_hz != US_RTP_OPUS_HZ) {
|
||||||
acap->res = speex_resampler_init(2, acap->pcm_hz, _ENCODER_INPUT_HZ, SPEEX_RESAMPLER_QUALITY_DESKTOP, &err);
|
acap->res = speex_resampler_init(US_RTP_OPUS_CH, acap->pcm_hz, US_RTP_OPUS_HZ, SPEEX_RESAMPLER_QUALITY_DESKTOP, &err);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
acap->res = NULL;
|
acap->res = NULL;
|
||||||
_JLOG_PERROR_RES(err, "acap", "Can't create resampler");
|
_JLOG_PERROR_RES(err, "acap", "Can't create resampler");
|
||||||
@ -143,9 +143,11 @@ us_acap_s *us_acap_init(const char *name, uint pcm_hz) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY
|
// OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY
|
||||||
acap->enc = opus_encoder_create(_ENCODER_INPUT_HZ, 2, OPUS_APPLICATION_AUDIO, &err);
|
acap->enc = opus_encoder_create(US_RTP_OPUS_HZ, US_RTP_OPUS_CH, OPUS_APPLICATION_AUDIO, &err);
|
||||||
assert(err == 0);
|
assert(err == 0);
|
||||||
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_BITRATE(48000)));
|
// https://github.com/meetecho/janus-gateway/blob/3cdd6ff/src/plugins/janus_audiobridge.c#L2272
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc7587#section-3.1.1
|
||||||
|
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_BITRATE(128000)));
|
||||||
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)));
|
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)));
|
||||||
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)));
|
assert(!opus_encoder_ctl(acap->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)));
|
||||||
// OPUS_SET_INBAND_FEC(1), OPUS_SET_PACKET_LOSS_PERC(10): see rtpa.c
|
// OPUS_SET_INBAND_FEC(1), OPUS_SET_PACKET_LOSS_PERC(10): see rtpa.c
|
||||||
@ -258,13 +260,13 @@ static void *_encoder_thread(void *v_acap) {
|
|||||||
|
|
||||||
s16 *in_ptr;
|
s16 *in_ptr;
|
||||||
if (acap->res != NULL) {
|
if (acap->res != NULL) {
|
||||||
assert(acap->pcm_hz != _ENCODER_INPUT_HZ);
|
assert(acap->pcm_hz != US_RTP_OPUS_HZ);
|
||||||
u32 in_count = acap->pcm_frames;
|
u32 in_count = acap->pcm_frames;
|
||||||
u32 out_count = _HZ_TO_FRAMES(_ENCODER_INPUT_HZ);
|
u32 out_count = _HZ_TO_FRAMES(US_RTP_OPUS_HZ);
|
||||||
speex_resampler_process_interleaved_int(acap->res, in->data, &in_count, in_res, &out_count);
|
speex_resampler_process_interleaved_int(acap->res, in->data, &in_count, in_res, &out_count);
|
||||||
in_ptr = in_res;
|
in_ptr = in_res;
|
||||||
} else {
|
} else {
|
||||||
assert(acap->pcm_hz == _ENCODER_INPUT_HZ);
|
assert(acap->pcm_hz == US_RTP_OPUS_HZ);
|
||||||
in_ptr = in->data;
|
in_ptr = in->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,14 +278,14 @@ static void *_encoder_thread(void *v_acap) {
|
|||||||
}
|
}
|
||||||
_enc_buffer_s *const out = acap->enc_ring->items[out_ri];
|
_enc_buffer_s *const out = acap->enc_ring->items[out_ri];
|
||||||
|
|
||||||
const int size = opus_encode(acap->enc, in_ptr, _HZ_TO_FRAMES(_ENCODER_INPUT_HZ), out->data, US_ARRAY_LEN(out->data));
|
const int size = opus_encode(acap->enc, in_ptr, _HZ_TO_FRAMES(US_RTP_OPUS_HZ), out->data, US_ARRAY_LEN(out->data));
|
||||||
us_ring_consumer_release(acap->pcm_ring, in_ri);
|
us_ring_consumer_release(acap->pcm_ring, in_ri);
|
||||||
|
|
||||||
if (size >= 0) {
|
if (size >= 0) {
|
||||||
out->used = size;
|
out->used = size;
|
||||||
out->pts = acap->pts;
|
out->pts = acap->pts;
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7587#section-4.2
|
// https://datatracker.ietf.org/doc/html/rfc7587#section-4.2
|
||||||
acap->pts += _HZ_TO_FRAMES(_ENCODER_INPUT_HZ);
|
acap->pts += _HZ_TO_FRAMES(US_RTP_OPUS_HZ);
|
||||||
} else {
|
} else {
|
||||||
_JLOG_PERROR_OPUS(size, "acap", "Fatal: Can't encode PCM frame to OPUS");
|
_JLOG_PERROR_OPUS(size, "acap", "Fatal: Can't encode PCM frame to OPUS");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,9 +28,13 @@
|
|||||||
// https://stackoverflow.com/questions/47635545/why-webrtc-chose-rtp-max-packet-size-to-1200-bytes
|
// https://stackoverflow.com/questions/47635545/why-webrtc-chose-rtp-max-packet-size-to-1200-bytes
|
||||||
#define US_RTP_DATAGRAM_SIZE 1200
|
#define US_RTP_DATAGRAM_SIZE 1200
|
||||||
#define US_RTP_HEADER_SIZE 12
|
#define US_RTP_HEADER_SIZE 12
|
||||||
|
#define US_RTP_PAYLOAD_SIZE (US_RTP_DATAGRAM_SIZE - US_RTP_HEADER_SIZE)
|
||||||
|
|
||||||
#define US_RTP_VIDEO_PAYLOAD 96
|
#define US_RTP_H264_PAYLOAD 96
|
||||||
#define US_RTP_AUDIO_PAYLOAD 111
|
#define US_RTP_OPUS_PAYLOAD 111
|
||||||
|
|
||||||
|
#define US_RTP_OPUS_HZ 48000
|
||||||
|
#define US_RTP_OPUS_CH 2
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@ -33,7 +33,7 @@ us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback) {
|
|||||||
us_rtpa_s *rtpa;
|
us_rtpa_s *rtpa;
|
||||||
US_CALLOC(rtpa, 1);
|
US_CALLOC(rtpa, 1);
|
||||||
rtpa->rtp = us_rtp_init();
|
rtpa->rtp = us_rtp_init();
|
||||||
us_rtp_assign(rtpa->rtp, US_RTP_AUDIO_PAYLOAD, false);
|
us_rtp_assign(rtpa->rtp, US_RTP_OPUS_PAYLOAD, false);
|
||||||
rtpa->callback = callback;
|
rtpa->callback = callback;
|
||||||
return rtpa;
|
return rtpa;
|
||||||
}
|
}
|
||||||
@ -49,14 +49,16 @@ char *us_rtpa_make_sdp(us_rtpa_s *rtpa, bool mic) {
|
|||||||
US_ASPRINTF(sdp,
|
US_ASPRINTF(sdp,
|
||||||
"m=audio 1 RTP/SAVPF %u" RN
|
"m=audio 1 RTP/SAVPF %u" RN
|
||||||
"c=IN IP4 0.0.0.0" RN
|
"c=IN IP4 0.0.0.0" RN
|
||||||
"a=rtpmap:%u OPUS/48000/2" RN
|
"a=rtpmap:%u OPUS/%u/%u" RN
|
||||||
"a=fmtp:%u sprop-stereo=1" RN // useinbandfec=1
|
"a=fmtp:%u sprop-stereo=1" RN // useinbandfec=1
|
||||||
"a=rtcp-fb:%u nack" RN
|
"a=rtcp-fb:%u nack" RN
|
||||||
"a=rtcp-fb:%u nack pli" RN
|
"a=rtcp-fb:%u nack pli" RN
|
||||||
"a=rtcp-fb:%u goog-remb" RN
|
"a=rtcp-fb:%u goog-remb" RN
|
||||||
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
|
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
|
||||||
"a=%s" RN,
|
"a=%s" RN,
|
||||||
pl, pl, pl, pl, pl, pl,
|
pl, pl,
|
||||||
|
US_RTP_OPUS_HZ, US_RTP_OPUS_CH,
|
||||||
|
pl, pl, pl, pl,
|
||||||
rtpa->rtp->ssrc,
|
rtpa->rtp->ssrc,
|
||||||
(mic ? "sendrecv" : "sendonly")
|
(mic ? "sendrecv" : "sendonly")
|
||||||
);
|
);
|
||||||
|
|||||||
@ -45,7 +45,7 @@ us_rtpv_s *us_rtpv_init(us_rtp_callback_f callback) {
|
|||||||
us_rtpv_s *rtpv;
|
us_rtpv_s *rtpv;
|
||||||
US_CALLOC(rtpv, 1);
|
US_CALLOC(rtpv, 1);
|
||||||
rtpv->rtp = us_rtp_init();
|
rtpv->rtp = us_rtp_init();
|
||||||
us_rtp_assign(rtpv->rtp, US_RTP_VIDEO_PAYLOAD, true);
|
us_rtp_assign(rtpv->rtp, US_RTP_H264_PAYLOAD, true);
|
||||||
rtpv->callback = callback;
|
rtpv->callback = callback;
|
||||||
return rtpv;
|
return rtpv;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user