From 21f1c0e2757d681d3b2af5a85b57f000c05f142a Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Sat, 13 Jan 2018 06:42:16 -0300 Subject: [PATCH 1/4] 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) --- libraries/audio-client/src/AudioClient.cpp | 53 +++++++++++++++++++++- libraries/audio-client/src/AudioClient.h | 7 ++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index af86499101..6a7648fdc3 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -52,11 +52,21 @@ #include "AudioClient.h" +#if defined(Q_OS_ANDROID) +const int AudioClient::MIN_BUFFER_FRAMES = 20; +#else const int AudioClient::MIN_BUFFER_FRAMES = 1; +#endif + const int AudioClient::MAX_BUFFER_FRAMES = 20; 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_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; }; @@ -197,6 +207,9 @@ AudioClient::AudioClient() : _audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this), _stats(&_receivedAudioStream), _positionGetter(DEFAULT_POSITION_GETTER), +#if defined(Q_OS_ANDROID) + _checkInputTimer(this), +#endif _orientationGetter(DEFAULT_ORIENTATION_GETTER) { // avoid putting a lock in the device callback assert(_localSamplesAvailable.is_lock_free()); @@ -278,6 +291,9 @@ void AudioClient::cleanupBeforeQuit() { return; } +#if defined(Q_OS_ANDROID) + _shouldRestartInputSetup = false; +#endif stop(); _checkDevicesTimer->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) << "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() { @@ -631,6 +653,9 @@ void AudioClient::stop() { qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down"; switchOutputToAudioDevice(QAudioDeviceInfo(), true); +#if defined(Q_OS_ANDROID) + _checkInputTimer.stop(); +#endif } void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer message) { @@ -1090,6 +1115,10 @@ void AudioClient::handleMicAudioInput() { return; } +#if defined(Q_OS_ANDROID) + _inputReadsSinceLastCheck++; +#endif + // input samples required to produce exactly NETWORK_FRAME_SAMPLES of output const int inputSamplesRequired = (_inputToNetworkResampler ? _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 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 if (_audioInput) { // 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 (_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 _inputDevice = _audioInput->start(); @@ -1553,10 +1589,11 @@ void AudioClient::audioInputStateChanged(QAudio::State state) { if (!_audioInput) { break; } - // Stopped on purpose + // Stopped on purpose if (_shouldRestartInputSetup) { Lock lock(_deviceMutex); _inputDevice = _audioInput->start(); + qCDebug(audioclient) << "[AUDIO-WA] Restarted _audioInput"; lock.unlock(); if (_inputDevice) { connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput())); @@ -1569,6 +1606,18 @@ void AudioClient::audioInputStateChanged(QAudio::State state) { 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 void AudioClient::outputNotify() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 0ceb9c4dc3..47c3171acd 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -26,7 +26,6 @@ #include #include #include - #include #include #include @@ -185,6 +184,7 @@ public slots: void handleMicAudioInput(); #if defined(Q_OS_ANDROID) void audioInputStateChanged(QAudio::State state); + void checkInputTimeout(); #endif void handleDummyAudioInput(); void handleRecordedAudioInput(const QByteArray& audio); @@ -276,6 +276,11 @@ private: float azimuthForSource(const glm::vec3& relativePosition); float gainForSource(float distance, float volume); +#ifdef Q_OS_ANDROID + QTimer _checkInputTimer; + long _inputReadsSinceLastCheck = 0l; +#endif + class Gate { public: Gate(AudioClient* audioClient); From ed1abb3a418fe22cf5a48196155926ef1693fe67 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 15 Jan 2018 18:30:32 -0300 Subject: [PATCH 2/4] Restoring adaptive audio buffer management --- libraries/audio-client/src/AudioClient.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index bb31d94337..ce72e59a24 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -52,11 +52,7 @@ #include "AudioClient.h" -#if defined(Q_OS_ANDROID) -const int AudioClient::MIN_BUFFER_FRAMES = 20; -#else const int AudioClient::MIN_BUFFER_FRAMES = 1; -#endif const int AudioClient::MAX_BUFFER_FRAMES = 20; From a91118027dad8294ca0814e1939a68ca0feae6f1 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 26 Jan 2018 18:14:43 -0300 Subject: [PATCH 3/4] Remove dead code and extra logs --- libraries/audio-client/src/AudioClient.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index ce72e59a24..4b5da3562e 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1598,7 +1598,6 @@ void AudioClient::audioInputStateChanged(QAudio::State state) { if (_shouldRestartInputSetup) { Lock lock(_deviceMutex); _inputDevice = _audioInput->start(); - qCDebug(audioclient) << "[AUDIO-WA] Restarted _audioInput"; lock.unlock(); if (_inputDevice) { connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput())); @@ -1614,12 +1613,8 @@ void AudioClient::audioInputStateChanged(QAudio::State state) { 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; } } From a2f6548d1d978d230b3586b9177107aba8a0cb11 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 12 Feb 2018 13:45:56 -0300 Subject: [PATCH 4/4] Make slot declarations non-conditional --- libraries/audio-client/src/AudioClient.cpp | 6 ++++-- libraries/audio-client/src/AudioClient.h | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 4b5da3562e..55f4292710 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1587,8 +1587,8 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInf return supportedFormat; } -#if defined(Q_OS_ANDROID) void AudioClient::audioInputStateChanged(QAudio::State state) { +#if defined(Q_OS_ANDROID) switch (state) { case QAudio::StoppedState: if (!_audioInput) { @@ -1609,16 +1609,18 @@ void AudioClient::audioInputStateChanged(QAudio::State state) { default: break; } +#endif } void AudioClient::checkInputTimeout() { +#if defined(Q_OS_ANDROID) if (_audioInput && _inputReadsSinceLastCheck < MIN_READS_TO_CONSIDER_INPUT_ALIVE) { _audioInput->stop(); } else { _inputReadsSinceLastCheck = 0; } -} #endif +} void AudioClient::outputNotify() { int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 8dd0be3fe8..3e6e83b598 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -182,10 +182,8 @@ public slots: void sendDownstreamAudioStatsPacket() { _stats.publish(); } void handleMicAudioInput(); -#if defined(Q_OS_ANDROID) void audioInputStateChanged(QAudio::State state); void checkInputTimeout(); -#endif void handleDummyAudioInput(); void handleRecordedAudioInput(const QByteArray& audio); void reset();