Rework audio bitrate and quality handling (#642)
This commit is contained in:
+18
-19
@@ -39,6 +39,15 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
platf::speaker::map_stereo,
|
platf::speaker::map_stereo,
|
||||||
|
96000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SAMPLE_RATE,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
platf::speaker::map_stereo,
|
||||||
|
512000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
@@ -46,6 +55,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
4,
|
4,
|
||||||
2,
|
2,
|
||||||
platf::speaker::map_surround51,
|
platf::speaker::map_surround51,
|
||||||
|
256000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
@@ -53,6 +63,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
6,
|
6,
|
||||||
0,
|
0,
|
||||||
platf::speaker::map_surround51,
|
platf::speaker::map_surround51,
|
||||||
|
1536000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
@@ -60,6 +71,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
5,
|
5,
|
||||||
3,
|
3,
|
||||||
platf::speaker::map_surround71,
|
platf::speaker::map_surround71,
|
||||||
|
450000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
@@ -67,6 +79,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
8,
|
8,
|
||||||
0,
|
0,
|
||||||
platf::speaker::map_surround71,
|
platf::speaker::map_surround71,
|
||||||
|
2048000,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,8 +87,6 @@ auto control_shared = safe::make_shared<audio_ctx_t>(start_audio_control, stop_a
|
|||||||
|
|
||||||
void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
||||||
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
|
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
|
||||||
|
|
||||||
// FIXME: Pick correct opus_stream_config_t based on config.channels
|
|
||||||
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
||||||
|
|
||||||
opus_t opus { opus_multistream_encoder_create(
|
opus_t opus { opus_multistream_encoder_create(
|
||||||
@@ -84,17 +95,15 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
|||||||
stream->streams,
|
stream->streams,
|
||||||
stream->coupledStreams,
|
stream->coupledStreams,
|
||||||
stream->mapping,
|
stream->mapping,
|
||||||
OPUS_APPLICATION_AUDIO,
|
OPUS_APPLICATION_RESTRICTED_LOWDELAY,
|
||||||
nullptr) };
|
nullptr) };
|
||||||
|
|
||||||
// For some reason, audio is crackling when the encoder is set to constant bitstream.
|
opus_multistream_encoder_ctl(opus.get(), OPUS_SET_BITRATE(stream->bitrate));
|
||||||
// We simulate a constant bitstream with OPUS_SET_BITRATE(OPUS_BITRATE_MAX) -->
|
opus_multistream_encoder_ctl(opus.get(), OPUS_SET_VBR(0));
|
||||||
// which tries to occupy as much space as possible in the packet
|
|
||||||
opus_multistream_encoder_ctl(opus.get(), OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
|
|
||||||
|
|
||||||
auto frame_size = config.packetDuration * stream->sampleRate / 1000;
|
auto frame_size = config.packetDuration * stream->sampleRate / 1000;
|
||||||
while(auto sample = samples->pop()) {
|
while(auto sample = samples->pop()) {
|
||||||
buffer_t packet { 1400 }; // 1KB
|
buffer_t packet { 1400 };
|
||||||
|
|
||||||
int bytes = opus_multistream_encode(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size());
|
int bytes = opus_multistream_encode(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size());
|
||||||
if(bytes < 0) {
|
if(bytes < 0) {
|
||||||
@@ -104,14 +113,6 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even with OPUS_SET_BITRATE(OPUS_BITRATE_MAX), silent packets are smaller than the rest
|
|
||||||
// Drop silent packets to ensure Moonlight won't complain
|
|
||||||
// A packet size of 128 seems a reasonable enough threshold
|
|
||||||
if(bytes < 128) {
|
|
||||||
BOOST_LOG(verbose) << "Dropped silent packet"sv;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
packet.fake_resize(bytes);
|
packet.fake_resize(bytes);
|
||||||
packets->raise(channel_data, std::move(packet));
|
packets->raise(channel_data, std::move(packet));
|
||||||
}
|
}
|
||||||
@@ -119,8 +120,6 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
|||||||
|
|
||||||
void capture(safe::mail_t mail, config_t config, void *channel_data) {
|
void capture(safe::mail_t mail, config_t config, void *channel_data) {
|
||||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||||
|
|
||||||
// FIXME: Pick correct opus_stream_config_t based on config.channels
|
|
||||||
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
||||||
|
|
||||||
auto ref = control_shared.ref();
|
auto ref = control_shared.ref();
|
||||||
@@ -225,7 +224,7 @@ int map_stream(int channels, bool quality) {
|
|||||||
int shift = quality ? 1 : 0;
|
int shift = quality ? 1 : 0;
|
||||||
switch(channels) {
|
switch(channels) {
|
||||||
case 2:
|
case 2:
|
||||||
return STEREO;
|
return STEREO + shift;
|
||||||
case 6:
|
case 6:
|
||||||
return SURROUND51 + shift;
|
return SURROUND51 + shift;
|
||||||
case 8:
|
case 8:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
enum stream_config_e : int {
|
enum stream_config_e : int {
|
||||||
STEREO,
|
STEREO,
|
||||||
|
HIGH_STEREO,
|
||||||
SURROUND51,
|
SURROUND51,
|
||||||
HIGH_SURROUND51,
|
HIGH_SURROUND51,
|
||||||
SURROUND71,
|
SURROUND71,
|
||||||
@@ -19,6 +20,7 @@ struct opus_stream_config_t {
|
|||||||
int streams;
|
int streams;
|
||||||
int coupledStreams;
|
int coupledStreams;
|
||||||
const std::uint8_t *mapping;
|
const std::uint8_t *mapping;
|
||||||
|
int bitrate;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern opus_stream_config_t stream_configs[MAX_STREAM_CONFIG];
|
extern opus_stream_config_t stream_configs[MAX_STREAM_CONFIG];
|
||||||
|
|||||||
@@ -646,6 +646,19 @@ void cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When using stereo audio, the audio quality is (strangely) indicated by whether the Host field
|
||||||
|
// in the RTSP message matches a local interface's IP address. Fortunately, Moonlight always sends
|
||||||
|
// 0.0.0.0 when it wants low quality, so it is easy to check without enumerating interfaces.
|
||||||
|
if(config.audio.channels == 2) {
|
||||||
|
for(auto option = req->options; option != nullptr; option = option->next) {
|
||||||
|
if("Host"sv == option->option) {
|
||||||
|
std::string_view content { option->content };
|
||||||
|
BOOST_LOG(debug) << "Found Host: "sv << content;
|
||||||
|
config.audio.flags[audio::config_t::HIGH_QUALITY] = (content.find("0.0.0.0"sv) == std::string::npos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(config.monitor.videoFormat != 0 && config::video.hevc_mode == 1) {
|
if(config.monitor.videoFormat != 0 && config::video.hevc_mode == 1) {
|
||||||
BOOST_LOG(warning) << "HEVC is disabled, yet the client requested HEVC"sv;
|
BOOST_LOG(warning) << "HEVC is disabled, yet the client requested HEVC"sv;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user