mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 10:07:58 +02:00
Android: Make audioInputStateChanged watcher work so it can restart input audio if it stops without a reason. Implement a mechanism that counts last reads in an interval and restart input audio in case of low reads -in these cases (happens particularly on Huawei) there is no call to the audioInputStateChanged method- (Android only)
This commit is contained in:
parent
8b2e8706ff
commit
21f1c0e275
2 changed files with 57 additions and 3 deletions
|
@ -52,11 +52,21 @@
|
||||||
|
|
||||||
#include "AudioClient.h"
|
#include "AudioClient.h"
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
const int AudioClient::MIN_BUFFER_FRAMES = 20;
|
||||||
|
#else
|
||||||
const int AudioClient::MIN_BUFFER_FRAMES = 1;
|
const int AudioClient::MIN_BUFFER_FRAMES = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
const int AudioClient::MAX_BUFFER_FRAMES = 20;
|
const int AudioClient::MAX_BUFFER_FRAMES = 20;
|
||||||
|
|
||||||
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
|
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
static const int CHECK_INPUT_READS_MSECS = 2000;
|
||||||
|
static const int MIN_READS_TO_CONSIDER_INPUT_ALIVE = 100;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; };
|
static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; };
|
||||||
static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; };
|
static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; };
|
||||||
|
|
||||||
|
@ -197,6 +207,9 @@ AudioClient::AudioClient() :
|
||||||
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
||||||
_stats(&_receivedAudioStream),
|
_stats(&_receivedAudioStream),
|
||||||
_positionGetter(DEFAULT_POSITION_GETTER),
|
_positionGetter(DEFAULT_POSITION_GETTER),
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
_checkInputTimer(this),
|
||||||
|
#endif
|
||||||
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
||||||
// avoid putting a lock in the device callback
|
// avoid putting a lock in the device callback
|
||||||
assert(_localSamplesAvailable.is_lock_free());
|
assert(_localSamplesAvailable.is_lock_free());
|
||||||
|
@ -278,6 +291,9 @@ void AudioClient::cleanupBeforeQuit() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
_shouldRestartInputSetup = false;
|
||||||
|
#endif
|
||||||
stop();
|
stop();
|
||||||
_checkDevicesTimer->stop();
|
_checkDevicesTimer->stop();
|
||||||
_checkPeakValuesTimer->stop();
|
_checkPeakValuesTimer->stop();
|
||||||
|
@ -622,6 +638,12 @@ void AudioClient::start() {
|
||||||
qCDebug(audioclient) << "Unable to set up audio output because of a problem with output format.";
|
qCDebug(audioclient) << "Unable to set up audio output because of a problem with output format.";
|
||||||
qCDebug(audioclient) << "The closest format available is" << outputDeviceInfo.nearestFormat(_desiredOutputFormat);
|
qCDebug(audioclient) << "The closest format available is" << outputDeviceInfo.nearestFormat(_desiredOutputFormat);
|
||||||
}
|
}
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
connect(&_checkInputTimer, &QTimer::timeout, [this] {
|
||||||
|
checkInputTimeout();
|
||||||
|
});
|
||||||
|
_checkInputTimer.start(CHECK_INPUT_READS_MSECS);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::stop() {
|
void AudioClient::stop() {
|
||||||
|
@ -631,6 +653,9 @@ void AudioClient::stop() {
|
||||||
|
|
||||||
qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down";
|
qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down";
|
||||||
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
|
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
_checkInputTimer.stop();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
@ -1090,6 +1115,10 @@ void AudioClient::handleMicAudioInput() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
_inputReadsSinceLastCheck++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// input samples required to produce exactly NETWORK_FRAME_SAMPLES of output
|
// input samples required to produce exactly NETWORK_FRAME_SAMPLES of output
|
||||||
const int inputSamplesRequired = (_inputToNetworkResampler ?
|
const int inputSamplesRequired = (_inputToNetworkResampler ?
|
||||||
_inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) :
|
_inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) :
|
||||||
|
@ -1425,6 +1454,10 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
// NOTE: device start() uses the Qt internal device list
|
// NOTE: device start() uses the Qt internal device list
|
||||||
Lock lock(_deviceMutex);
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
_shouldRestartInputSetup = false; // avoid a double call to _audioInput->start() from audioInputStateChanged
|
||||||
|
#endif
|
||||||
|
|
||||||
// cleanup any previously initialized device
|
// cleanup any previously initialized device
|
||||||
if (_audioInput) {
|
if (_audioInput) {
|
||||||
// The call to stop() causes _inputDevice to be destructed.
|
// The call to stop() causes _inputDevice to be destructed.
|
||||||
|
@ -1505,7 +1538,10 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
if (_audioInput) {
|
if (_audioInput) {
|
||||||
connect(_audioInput, SIGNAL(stateChanged(QAudio::State)), this, SLOT(audioInputStateChanged(QAudio::State)));
|
_shouldRestartInputSetup = true;
|
||||||
|
connect(_audioInput, &QAudioInput::stateChanged, [this](QAudio::State state) {
|
||||||
|
audioInputStateChanged(state);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_inputDevice = _audioInput->start();
|
_inputDevice = _audioInput->start();
|
||||||
|
@ -1553,10 +1589,11 @@ void AudioClient::audioInputStateChanged(QAudio::State state) {
|
||||||
if (!_audioInput) {
|
if (!_audioInput) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Stopped on purpose
|
// Stopped on purpose
|
||||||
if (_shouldRestartInputSetup) {
|
if (_shouldRestartInputSetup) {
|
||||||
Lock lock(_deviceMutex);
|
Lock lock(_deviceMutex);
|
||||||
_inputDevice = _audioInput->start();
|
_inputDevice = _audioInput->start();
|
||||||
|
qCDebug(audioclient) << "[AUDIO-WA] Restarted _audioInput";
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
if (_inputDevice) {
|
if (_inputDevice) {
|
||||||
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput()));
|
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput()));
|
||||||
|
@ -1569,6 +1606,18 @@ void AudioClient::audioInputStateChanged(QAudio::State state) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioClient::checkInputTimeout() {
|
||||||
|
if (_audioInput && _inputReadsSinceLastCheck < MIN_READS_TO_CONSIDER_INPUT_ALIVE) {
|
||||||
|
qCDebug(audioclient) << "[AUDIO-WA] No input in last second _inputReadsSinceLastCheck" << _inputReadsSinceLastCheck;
|
||||||
|
// this is a weird issue happening at low level in android
|
||||||
|
// it simply stops sending us mic data
|
||||||
|
_audioInput->stop();
|
||||||
|
} else {
|
||||||
|
//qCDebug(audioclient) << "[AUDIO-WA] ok _inputReadsSinceLastCheck " << _inputReadsSinceLastCheck;
|
||||||
|
_inputReadsSinceLastCheck = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AudioClient::outputNotify() {
|
void AudioClient::outputNotify() {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <QtMultimedia/QAudio>
|
#include <QtMultimedia/QAudio>
|
||||||
#include <QtMultimedia/QAudioFormat>
|
#include <QtMultimedia/QAudioFormat>
|
||||||
#include <QtMultimedia/QAudioInput>
|
#include <QtMultimedia/QAudioInput>
|
||||||
|
|
||||||
#include <AbstractAudioInterface.h>
|
#include <AbstractAudioInterface.h>
|
||||||
#include <AudioEffectOptions.h>
|
#include <AudioEffectOptions.h>
|
||||||
#include <AudioStreamStats.h>
|
#include <AudioStreamStats.h>
|
||||||
|
@ -185,6 +184,7 @@ public slots:
|
||||||
void handleMicAudioInput();
|
void handleMicAudioInput();
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
void audioInputStateChanged(QAudio::State state);
|
void audioInputStateChanged(QAudio::State state);
|
||||||
|
void checkInputTimeout();
|
||||||
#endif
|
#endif
|
||||||
void handleDummyAudioInput();
|
void handleDummyAudioInput();
|
||||||
void handleRecordedAudioInput(const QByteArray& audio);
|
void handleRecordedAudioInput(const QByteArray& audio);
|
||||||
|
@ -276,6 +276,11 @@ private:
|
||||||
float azimuthForSource(const glm::vec3& relativePosition);
|
float azimuthForSource(const glm::vec3& relativePosition);
|
||||||
float gainForSource(float distance, float volume);
|
float gainForSource(float distance, float volume);
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
QTimer _checkInputTimer;
|
||||||
|
long _inputReadsSinceLastCheck = 0l;
|
||||||
|
#endif
|
||||||
|
|
||||||
class Gate {
|
class Gate {
|
||||||
public:
|
public:
|
||||||
Gate(AudioClient* audioClient);
|
Gate(AudioClient* audioClient);
|
||||||
|
|
Loading…
Reference in a new issue