Skip to content

Commit ba0c318

Browse files
committed
Optimize headset audio
This cleans up the call flow audio, inserts some more silence and delays sending of certain teams display HID commands that led to a cut-off for end-call and congestion tones.
1 parent 0bd24b8 commit ba0c318

10 files changed

Lines changed: 181 additions & 32 deletions

src/media/AudioManager.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,37 @@ void AudioManager::setPlaybackAudioVolume(qreal volume)
528528
}
529529
}
530530
}
531+
532+
void AudioManager::acquireDevice()
533+
{
534+
if (++m_acquireRefCount > 1) {
535+
return;
536+
}
537+
538+
if (m_playbackAudioPort) {
539+
m_playbackAudioPort->acquire();
540+
}
541+
542+
if (m_captureAudioPort) {
543+
m_captureAudioPort->acquire();
544+
}
545+
}
546+
547+
void AudioManager::releaseDevice()
548+
{
549+
if (m_acquireRefCount == 0) {
550+
return;
551+
}
552+
553+
if (--m_acquireRefCount > 0) {
554+
return;
555+
}
556+
557+
if (m_playbackAudioPort) {
558+
m_playbackAudioPort->release();
559+
}
560+
561+
if (m_captureAudioPort) {
562+
m_captureAudioPort->release();
563+
}
564+
}

src/media/AudioManager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class AudioManager : public QObject
6767
void *userdata);
6868
#endif
6969

70+
void acquireDevice();
71+
void releaseDevice();
72+
7073
pj::AudioMedia &getPlaybackDevMedia() const;
7174
pj::AudioMedia &getCaptureDevMedia() const;
7275

@@ -139,6 +142,8 @@ private Q_SLOTS:
139142
unsigned m_captureDeviceId = 0;
140143
unsigned m_currentAudioProfile = 0;
141144

145+
int m_acquireRefCount = 0;
146+
142147
QTimer m_updateDebouncer;
143148
QList<SIPAudioDevice *> m_devices;
144149

src/media/AudioPort.cpp

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ using namespace std::chrono_literals;
1313

1414
AudioPort::AudioPort(QAudioDevice device) : m_device(device)
1515
{
16-
m_idleTimer.setInterval(1s);
16+
m_idleTimer.setInterval(10s);
1717
connect(&m_idleTimer, &QTimer::timeout, this, &AudioPort::stopIO);
1818

1919
connect(this, &AudioPort::startIdleTimer, this,
@@ -168,6 +168,11 @@ void AudioPort::startSinkIO()
168168
{
169169
m_idleTimer.stop();
170170

171+
if (m_isDraining && !m_sink.isNull()) {
172+
m_isDraining = false;
173+
return;
174+
}
175+
171176
if (!m_sink.isNull()) {
172177
stopSinkIO();
173178
}
@@ -191,17 +196,25 @@ void AudioPort::startSinkIO()
191196
void AudioPort::stopSinkIO()
192197
{
193198
m_idleTimer.stop();
199+
if (m_sink.isNull() || m_isDraining) {
200+
return;
201+
}
194202

195-
if (m_sink) {
196-
writeSilenceMS(SILENCE_BUFFER_MS);
203+
writeSilenceMS(SILENCE_BUFFER_MS);
197204

198-
m_sink->stop();
199-
m_sink->deleteLater();
200-
m_sink = nullptr;
201-
m_io = nullptr;
202-
}
205+
m_isDraining = true;
206+
QTimer::singleShot(SILENCE_BUFFER_MS + 200, this, [this]() {
207+
m_isDraining = false;
203208

204-
Q_EMIT audioSinkChanged();
209+
if (m_sink) {
210+
m_sink->stop();
211+
m_sink->deleteLater();
212+
m_sink = nullptr;
213+
m_io = nullptr;
214+
}
215+
216+
Q_EMIT audioSinkChanged();
217+
});
205218
}
206219

207220
void AudioPort::startSourceIO()
@@ -267,6 +280,11 @@ void AudioPort::onFrameRequested(pj::MediaFrame &frame)
267280
return;
268281
}
269282

283+
if (m_isWarmingUp) {
284+
m_isWarmingUp = false;
285+
QObject::disconnect(m_warmUpDrain);
286+
}
287+
270288
auto bytes = m_io->read(frame.size);
271289

272290
if (!m_isMuted) {
@@ -297,8 +315,50 @@ void AudioPort::onFrameReceived(pj::MediaFrame &frame)
297315
return;
298316
}
299317

318+
m_isWarmingUp = false;
319+
300320
m_io->write(reinterpret_cast<char *>(frame.buf.data()), frame.size);
301321

302322
// Auto destroy sink after timeout
303323
Q_EMIT startIdleTimer();
304324
}
325+
326+
void AudioPort::acquire()
327+
{
328+
if (m_device.mode() == QAudioDevice::Mode::Input) {
329+
if (m_source.isNull()) {
330+
startSourceIO();
331+
}
332+
} else {
333+
if (m_sink.isNull()) {
334+
startSinkIO();
335+
}
336+
}
337+
338+
m_isWarmingUp = true;
339+
340+
if (m_device.mode() == QAudioDevice::Mode::Input && !m_io.isNull()) {
341+
QObject::disconnect(m_warmUpDrain);
342+
343+
m_warmUpDrain = connect(m_io.data(), &QIODevice::readyRead, this, [this]() {
344+
if (m_isWarmingUp && !m_io.isNull()) {
345+
m_io->readAll();
346+
}
347+
});
348+
}
349+
}
350+
351+
void AudioPort::release()
352+
{
353+
if (!m_isWarmingUp) {
354+
return;
355+
}
356+
357+
m_isWarmingUp = false;
358+
359+
QObject::disconnect(m_warmUpDrain);
360+
361+
if (!m_idleTimer.isActive()) {
362+
stopIO();
363+
}
364+
}

src/media/AudioPort.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class AudioPort : public QObject, public pj::AudioMediaPort
2424
QString getDeviceID() const;
2525
QString getSystemDeviceID() const;
2626

27+
void acquire();
28+
void release();
29+
2730
void setAudioDevice(QAudioDevice device);
2831
QAudioDevice audioDevice() { return m_device; }
2932

@@ -32,15 +35,15 @@ class AudioPort : public QObject, public pj::AudioMediaPort
3235

3336
qreal sourceLevel() const { return m_sourceAudioLevel; }
3437

38+
void writeSilenceMS(unsigned milliseconds);
39+
3540
Q_SIGNALS:
3641
void startIdleTimer();
3742
void audioSourceChanged();
3843
void audioSinkChanged();
3944
void sourceLevelChanged(qreal level);
4045

4146
private:
42-
void writeSilenceMS(unsigned milliseconds);
43-
4447
void startIO();
4548
void stopIO();
4649

@@ -55,6 +58,9 @@ class AudioPort : public QObject, public pj::AudioMediaPort
5558
void setSourceAudioLevel(qreal level);
5659

5760
bool m_isMuted = false;
61+
bool m_isDraining = false;
62+
bool m_isWarmingUp = false;
63+
5864
QAudioDevice m_device;
5965

6066
QPointer<QIODevice> m_io;
@@ -67,4 +73,6 @@ class AudioPort : public QObject, public pj::AudioMediaPort
6773
pj::MediaFormatAudio m_pj_fmt;
6874

6975
QAudioFormat m_audioFormat;
76+
77+
QMetaObject::Connection m_warmUpDrain;
7078
};

src/sip/RingTone.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "RingTone.h"
22
#include "AudioManager.h"
3-
#include "ReadOnlyConfdSettings.h"
3+
#include "AudioPort.h"
44

55
RingTone::RingTone(quint16 frequency1, quint16 frequency2, QList<QPair<quint16, quint16>> intervals,
66
qint8 loopIndex, QObject *parent)
@@ -40,10 +40,17 @@ void RingTone::start()
4040
m_isPlaying = true;
4141
m_currentIndex = 0;
4242

43+
AudioManager::instance().acquireDevice();
44+
4345
if (m_stopTimer.isActive()) {
4446
m_stopTimer.stop();
4547
}
4648

49+
// Bridge gap between previous audio source (mostly the call)
50+
if (auto *port = dynamic_cast<AudioPort *>(&m_mediaSink)) {
51+
port->writeSilenceMS(120);
52+
}
53+
4754
m_toneGen.startTransmit(m_mediaSink);
4855
playNextTone();
4956
}
@@ -55,20 +62,23 @@ void RingTone::stop()
5562
if (!m_isPlaying) {
5663
return;
5764
}
65+
5866
if (m_loopTimer.isActive()) {
5967
m_loopTimer.stop();
6068
}
69+
6170
m_currentIndex = 0;
6271
m_isPlaying = false;
6372
m_toneGen.stop();
6473
m_toneGen.stopTransmit(m_mediaSink);
6574

75+
AudioManager::instance().releaseDevice();
76+
6677
Q_EMIT ready();
6778
}
6879

6980
void RingTone::playNextTone()
7081
{
71-
7282
// Create and play tone
7383
const auto &tuple = m_intervals.at(m_currentIndex);
7484

@@ -92,16 +102,22 @@ void RingTone::playNextTone()
92102
if (m_repeatTimes > 0) {
93103
--m_repeatTimes;
94104
} else if (m_repeatTimes == 0) {
95-
stop();
105+
scheduleStop(tuple.first + tuple.second);
96106
return;
97107
}
98108
} else {
99-
// No loop - stop the tone
100-
m_stopTimer.setInterval(tuple.first + tuple.second);
101-
m_stopTimer.start();
109+
scheduleStop(tuple.first + tuple.second);
102110
return;
103111
}
104112
}
105113

106114
m_loopTimer.start(tuple.first + tuple.second);
107115
}
116+
117+
void RingTone::scheduleStop(unsigned delay)
118+
{
119+
static constexpr unsigned PIPELINE_GRACE_MS = 400;
120+
121+
m_stopTimer.setInterval(delay + PIPELINE_GRACE_MS);
122+
m_stopTimer.start();
123+
}

src/sip/RingTone.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ private Q_SLOTS:
6060
void playNextTone();
6161

6262
private:
63+
void scheduleStop(unsigned delay);
64+
6365
bool m_isPlaying = false;
6466
pj::ToneGenerator m_toneGen;
6567
pj::AudioMedia &m_mediaSink;

src/sip/SIPAccount.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ void SIPAccount::removeCall(SIPCall *call)
857857
{
858858
if (call) {
859859
m_calls.removeAll(call);
860-
delete call;
860+
call->deleteLater();
861861
}
862862
}
863863

src/sip/SIPCall.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ SIPCall::SIPCall(SIPAccount *account, int callId, const QString &contactId, bool
7979
}
8080
}
8181

82+
AudioManager::instance().acquireDevice();
83+
8284
// Setup rtt timeout
8385
m_rttTimeoutTimer.setSingleShot(true);
8486
m_rttTimeoutTimer.setInterval(6s);
@@ -96,6 +98,8 @@ SIPCall::SIPCall(SIPAccount *account, int callId, const QString &contactId, bool
9698

9799
SIPCall::~SIPCall()
98100
{
101+
AudioManager::instance().releaseDevice();
102+
99103
if (m_isEmergencyCall) {
100104
Q_EMIT ViewHelper::instance().hideEmergency();
101105
}
@@ -286,13 +290,14 @@ void SIPCall::onCallState(pj::OnCallStateParam &prm)
286290

287291
if (m_isEstablished) {
288292
ringToneFactory.endTone()->start();
289-
}
290-
if (!m_incoming) {
291-
if (statusCode == PJSIP_SC_BUSY_HERE) {
292-
ringToneFactory.busyTone()->start(5);
293-
} else if (static_cast<int>(statusCode) >= 400
294-
&& static_cast<int>(statusCode) < 700) {
295-
ringToneFactory.congestionTone()->start(5);
293+
} else {
294+
if (!m_incoming) {
295+
if (statusCode == PJSIP_SC_BUSY_HERE) {
296+
ringToneFactory.busyTone()->start(5);
297+
} else if (static_cast<int>(statusCode) >= 400
298+
&& static_cast<int>(statusCode) < 700) {
299+
ringToneFactory.congestionTone()->start(5);
300+
}
296301
}
297302
}
298303
}

0 commit comments

Comments
 (0)