1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
/*
(c) Copyright 2012 - 2026 Anton Sviridenko
https://picapica.im
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "callsettings.h"
#include "settings.h"
#include "globals.h"
const CallCodecInfo kCallVideoCodecs[] =
{
{ "h264", "H.264" },
{ "hevc", "H.265/HEVC" },
{ "vp9", "VP9" }
};
const int kCallVideoCodecCount = sizeof(kCallVideoCodecs) / sizeof(kCallVideoCodecs[0]);
const CallCodecInfo kCallAudioCodecs[] =
{
{ "opus", "Opus" },
{ "adpcm_g722", "G.722" },
{ "pcm_alaw", "G.711 A-law" }
};
const int kCallAudioCodecCount = sizeof(kCallAudioCodecs) / sizeof(kCallAudioCodecs[0]);
int callAudioSampleRate(const QString &codec)
{
// G.722 is a 16kHz codec by definition - it subband-codes a 7kHz audio
// bandwidth and there is no other rate to run it at.
if (codec == QLatin1String("adpcm_g722"))
return 16000;
// A-law is the telephone network's codec and 8kHz is what it is for.
// Running it at anything else would only spend twice the bandwidth on a
// codec chosen for costing as little as possible.
if (codec == QLatin1String("pcm_alaw"))
return 8000;
// Opus, and anything unrecognised: 16kHz rather than 48kHz because it is
// what the echo canceller wants. AEC3 does its filtering in the 0-8kHz
// band whatever it is handed; at 48kHz it splits the signal into four
// bands, cancels in the lowest and gates the rest, which is more work for
// a result that is no better on speech.
//
// Costs nothing worth having for speech: Opus codes this as wideband, an
// 8kHz audio bandwidth, which is well past telephone quality and past
// where voice intelligibility stops improving.
//
// Note that this is the capture direction only. Playback follows whatever
// the peer announced in its own 0x74 message (see
// AudioVideoCallController::incoming_audio_params()), so a call with a
// peer that picked a different codec or rate keeps working.
return 16000;
}
bool callAudioBitrateAdjustable(const QString &codec)
{
// Opus is the only one of the three with a rate control worth the name;
// the other two are fixed bits per sample.
return codec == QLatin1String("opus") || codec.isEmpty();
}
int callAudioFixedBitrateKbps(const QString &codec)
{
// G.722 is 4 bits per sample at 16kHz, A-law 8 bits per sample at 8kHz -
// 64 kbit/s either way, which is no coincidence.
if (codec == QLatin1String("adpcm_g722"))
return 16000 * 4 / 1000;
if (codec == QLatin1String("pcm_alaw"))
return 8000 * 8 / 1000;
return kDefaultAudioBitrateKbps;
}
CallSettings CallSettings::load()
{
Settings st(config_dbname);
CallSettings cs;
cs.videoCodec = st.loadValue("call.video_codec", QLatin1String(kCallVideoCodecs[0].name)).toString();
cs.audioCodec = st.loadValue("call.audio_codec", QLatin1String(kCallAudioCodecs[0].name)).toString();
cs.videoBitrateKbps = st.loadValue("call.video_bitrate_kbps", kDefaultVideoBitrateKbps).toInt();
cs.audioBitrateKbps = st.loadValue("call.audio_bitrate_kbps", kDefaultAudioBitrateKbps).toInt();
cs.captureWidth = st.loadValue("video.capture_width", kDefaultCaptureWidth).toInt();
cs.captureHeight = st.loadValue("video.capture_height", kDefaultCaptureHeight).toInt();
cs.captureFrameRate = st.loadValue("video.capture_framerate", kDefaultCaptureFrameRate).toInt();
// Only the keys this build has checkboxes for: a database carried over
// from another platform must not switch on a path that cannot exist here.
cs.videoEncodingAcceleration = 0;
cs.videoDecodingAcceleration = 0;
#ifdef HAVE_VAAPI
if (st.loadValue("video.vaapi_encoding", 0).toBool())
cs.videoEncodingAcceleration |= VideoAccelerationVaapi;
if (st.loadValue("video.vaapi_decoding", 0).toBool())
cs.videoDecodingAcceleration |= VideoAccelerationVaapi;
#endif
#ifdef HAVE_D3D12VA
if (st.loadValue("video.d3d12va_encoding", 0).toBool())
cs.videoEncodingAcceleration |= VideoAccelerationD3d12va;
if (st.loadValue("video.d3d12va_decoding", 0).toBool())
cs.videoDecodingAcceleration |= VideoAccelerationD3d12va;
#endif
#ifdef Q_OS_WIN
if (st.loadValue("video.mediafoundation_encoding", 0).toBool())
cs.videoEncodingAcceleration |= VideoAccelerationMediaFoundation;
if (st.loadValue("video.d3d11va_decoding", 0).toBool())
cs.videoDecodingAcceleration |= VideoAccelerationD3d11va;
if (st.loadValue("video.dxva2_decoding", 0).toBool())
cs.videoDecodingAcceleration |= VideoAccelerationDxva2;
#endif
// A stored value that makes no sense - a hand-edited database, or a
// setting written by a build that offered something this one does not -
// would otherwise be passed to the encoder and fail the call rather than
// the setting.
if (cs.videoBitrateKbps <= 0)
cs.videoBitrateKbps = kDefaultVideoBitrateKbps;
if (cs.audioBitrateKbps <= 0)
cs.audioBitrateKbps = kDefaultAudioBitrateKbps;
if (cs.captureWidth <= 0 || cs.captureHeight <= 0)
{
cs.captureWidth = kDefaultCaptureWidth;
cs.captureHeight = kDefaultCaptureHeight;
}
if (cs.captureFrameRate <= 0)
cs.captureFrameRate = kDefaultCaptureFrameRate;
return cs;
}
|