|
|
|
@ -8,6 +8,7 @@ extern "C" { |
|
|
|
#include "debug_config.h" |
|
|
|
#include "debug_config.h" |
|
|
|
} |
|
|
|
} |
|
|
|
#include <cstring> |
|
|
|
#include <cstring> |
|
|
|
|
|
|
|
#include <QCoreApplication> |
|
|
|
|
|
|
|
|
|
|
|
CallAudioEngine* CallAudioEngine::instance() { |
|
|
|
CallAudioEngine* CallAudioEngine::instance() { |
|
|
|
static auto* engine = new CallAudioEngine(); |
|
|
|
static auto* engine = new CallAudioEngine(); |
|
|
|
@ -32,7 +33,9 @@ CallAudioEngine::CallAudioEngine() { |
|
|
|
|
|
|
|
|
|
|
|
int CallAudioEngine::start(quint64 callId) { |
|
|
|
int CallAudioEngine::start(quint64 callId) { |
|
|
|
if (m_active && m_callId == callId && !m_ending) return 0; |
|
|
|
if (m_active && m_callId == callId && !m_ending) return 0; |
|
|
|
|
|
|
|
if (m_capture.closing()) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "CallAudio: previous microphone is still closing"); return -1; } |
|
|
|
stop(); |
|
|
|
stop(); |
|
|
|
|
|
|
|
m_captureError.clear(); emit captureErrorChanged(); |
|
|
|
if (!m_microphone.acquire()) { |
|
|
|
if (!m_microphone.acquire()) { |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CALL, "CallAudio: microphone owned by another operation"); return -1; |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CALL, "CallAudio: microphone owned by another operation"); return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -82,9 +85,20 @@ bool CallAudioEngine::openCapture() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CallAudioEngine::recoverDevices() { |
|
|
|
void CallAudioEngine::recoverDevices() { |
|
|
|
if (!m_active) return; |
|
|
|
if (!m_active) { |
|
|
|
|
|
|
|
if (!m_capture.closing()) { m_microphone.release(); m_recoveryTimer.stop(); } |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
auto* manager = SoundManager::instance(); |
|
|
|
auto* manager = SoundManager::instance(); |
|
|
|
if (!m_outputAttached && manager->context()) m_outputAttached = manager->attachVoice(&m_voice, m_playbackId); |
|
|
|
if (!m_outputAttached && manager->context()) m_outputAttached = manager->attachVoice(&m_voice, m_playbackId); |
|
|
|
|
|
|
|
if (!m_ending && m_captureError.isEmpty() && m_capture.captureTimedOut()) { |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "CallAudio: microphone has no PCM for 1000ms call=%016llx; disabling capture", |
|
|
|
|
|
|
|
(unsigned long long)m_callId.load()); |
|
|
|
|
|
|
|
m_captureError = QCoreApplication::translate("ChatGui", "The microphone is not delivering audio. Select another microphone or restart."); |
|
|
|
|
|
|
|
m_capture.closeAsync(); m_voice.stopCapture(); call_audio_reset_io(m_callId.load(), 0); |
|
|
|
|
|
|
|
emit captureErrorChanged(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!m_captureError.isEmpty() || m_capture.closing()) return; |
|
|
|
if (!m_ending && ((m_capture.initialized() && !m_voice.captureRunning()) || m_capture.needsRecovery())) { |
|
|
|
if (!m_ending && ((m_capture.initialized() && !m_voice.captureRunning()) || m_capture.needsRecovery())) { |
|
|
|
m_capture.close(); m_voice.stopCapture(); |
|
|
|
m_capture.close(); m_voice.stopCapture(); |
|
|
|
call_audio_reset_io(m_callId.load(), 0); m_capture.retryLater(); |
|
|
|
call_audio_reset_io(m_callId.load(), 0); m_capture.retryLater(); |
|
|
|
@ -115,14 +129,15 @@ void CallAudioEngine::setPlaybackDevice(const QString& id) { |
|
|
|
void CallAudioEngine::setCaptureDevice(const QString& id) { |
|
|
|
void CallAudioEngine::setCaptureDevice(const QString& id) { |
|
|
|
if (id == m_captureId) return; |
|
|
|
if (id == m_captureId) return; |
|
|
|
m_captureId = id; |
|
|
|
m_captureId = id; |
|
|
|
m_capture.close(); m_voice.stopCapture(); m_capture.retryNow(); |
|
|
|
m_capture.closeAsync(); m_voice.stopCapture(); m_capture.retryNow(); |
|
|
|
|
|
|
|
m_captureError.clear(); emit captureErrorChanged(); |
|
|
|
if (m_active) { call_audio_reset_io(m_callId.load(), 0); recoverDevices(); } |
|
|
|
if (m_active) { call_audio_reset_io(m_callId.load(), 0); recoverDevices(); } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CallAudioEngine::beginEnd(quint64 callId) { |
|
|
|
void CallAudioEngine::beginEnd(quint64 callId) { |
|
|
|
if (!m_active || m_callId != callId || m_ending) return; |
|
|
|
if (!m_active || m_callId != callId || m_ending) return; |
|
|
|
m_ending = true; |
|
|
|
m_ending = true; |
|
|
|
m_capture.close(); m_voice.stopCapture(); |
|
|
|
m_capture.closeAsync(); m_voice.stopCapture(); |
|
|
|
call_audio_begin_end(callId); |
|
|
|
call_audio_begin_end(callId); |
|
|
|
uint64_t generation = m_generation; |
|
|
|
uint64_t generation = m_generation; |
|
|
|
QTimer::singleShot(500, this, [this, generation]() { if (m_generation == generation) stop(); }); |
|
|
|
QTimer::singleShot(500, this, [this, generation]() { if (m_generation == generation) stop(); }); |
|
|
|
@ -130,10 +145,12 @@ void CallAudioEngine::beginEnd(quint64 callId) { |
|
|
|
|
|
|
|
|
|
|
|
void CallAudioEngine::stop() { |
|
|
|
void CallAudioEngine::stop() { |
|
|
|
++m_generation; |
|
|
|
++m_generation; |
|
|
|
m_recoveryTimer.stop(); |
|
|
|
|
|
|
|
m_active = false; |
|
|
|
m_active = false; |
|
|
|
pauseDevices(); m_voice.stop(); |
|
|
|
m_capture.closeAsync(); m_voice.stopCapture(); |
|
|
|
m_microphone.release(); |
|
|
|
SoundManager::instance()->detachVoice(&m_voice); m_outputAttached = false; |
|
|
|
|
|
|
|
m_voice.stop(); |
|
|
|
|
|
|
|
if (m_capture.closing()) m_recoveryTimer.start(); |
|
|
|
|
|
|
|
else { m_microphone.release(); m_recoveryTimer.stop(); } |
|
|
|
uint64_t id = m_callId.exchange(0); |
|
|
|
uint64_t id = m_callId.exchange(0); |
|
|
|
if (id) call_audio_release(id); |
|
|
|
if (id) call_audio_release(id); |
|
|
|
m_muted = false; |
|
|
|
m_muted = false; |
|
|
|
|