From 7292e265fbac3f608f620701619154a52437a40e Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Sat, 30 Nov 2013 15:48:33 +0100 Subject: [PATCH] Added squelch and mic tests refs #36 refs #81 --- src/blackcore/voiceclient.h | 36 +++-- src/blackcore/voiceclient_vatlib.cpp | 195 ++++++++++++++++++++++++--- src/blackcore/voiceclient_vatlib.h | 49 ++++++- 3 files changed, 249 insertions(+), 31 deletions(-) diff --git a/src/blackcore/voiceclient.h b/src/blackcore/voiceclient.h index 9f7394eec..23e3dba8a 100644 --- a/src/blackcore/voiceclient.h +++ b/src/blackcore/voiceclient.h @@ -21,6 +21,9 @@ namespace BlackCore { + /*! + * Interface to a connection to a ATC voice server for use in flight simulation. + */ class IVoiceClient : public QObject { @@ -54,17 +57,25 @@ namespace BlackCore virtual bool isConnected(const uint32_t comUnit) = 0; - // The following methods should be called everytime you receive a update signal. - // Reason: - // We cannot say when the device and user lists are completed. Instead information is cached internally - // and signals emitted in case of a change. This way other objects can listen to this signals and call the getter - // again. + // The following method should be called everytime you receive a user update signal virtual void roomUserList(const uint32_t comUnit) = 0; - virtual const QList & audioInputDevices(const uint32_t comUnit) const = 0; - virtual const QList & audioOutputDevices(const uint32_t comUnit) const = 0; - virtual void setInputDevice(const uint32_t comUnit, BlackMisc::Voice::CInputAudioDevice &device) = 0; - virtual void setOutputDevice(const uint32_t comUnit, BlackMisc::Voice::COutputAudioDevice &device) = 0; + // Hardware devices + virtual const QList & audioInputDevices() const = 0; + virtual const QList & audioOutputDevices() const = 0; + + virtual const BlackMisc::Voice::CInputAudioDevice & defaultAudioInputDevice() const = 0; + virtual const BlackMisc::Voice::COutputAudioDevice & defaultAudioOutputDevice() const = 0; + + virtual void setInputDevice(const BlackMisc::Voice::CInputAudioDevice &device) = 0; + virtual void setOutputDevice(const BlackMisc::Voice::COutputAudioDevice &device) = 0; + + // Mic tests + + virtual void runSquelchTest() = 0; + virtual void runMicTest() = 0; + + virtual float inputSquelch() const = 0; virtual const BlackMisc::Voice::CVoiceRoom &voiceRoom (const uint32_t comUnit) = 0; @@ -86,6 +97,13 @@ namespace BlackCore void audioStarted(const uint32_t comUnit); void audioStopped(const uint32_t comUnit); + // Test signals + void squelchTestFinished(); + void micTestFinished(); + + // non protocol related signals + void exception(const QString &message, bool fatal = false); // let remote places know there was an exception + public slots: }; diff --git a/src/blackcore/voiceclient_vatlib.cpp b/src/blackcore/voiceclient_vatlib.cpp index e41e16052..edd3aa32d 100644 --- a/src/blackcore/voiceclient_vatlib.cpp +++ b/src/blackcore/voiceclient_vatlib.cpp @@ -6,21 +6,33 @@ #include "voiceclient_vatlib.h" #include +#include namespace BlackCore { CVoiceClientVatlib::CVoiceClientVatlib(QObject *parent) : IVoiceClient(parent), - m_voice(Create_Cvatlib_Voice_Simple()) + m_voice(Create_Cvatlib_Voice_Simple()), + m_inputSquelch(-1) { - m_voice->Setup(true, 3290, 2, 1, onRoomStatusUpdate, this); - m_voice->GetInputDevices(onInputHardwareDeviceReceived, this); - m_voice->GetOutputDevices(onOutputHardwareDeviceReceived, this); + try + { + m_voice->Setup(true, 3290, 2, 1, onRoomStatusUpdate, this); + m_voice->GetInputDevices(onInputHardwareDeviceReceived, this); + m_voice->GetOutputDevices(onOutputHardwareDeviceReceived, this); + + // TODO: read audio device settings here and init with the same devices + // If not settings are there or it is the first run, use the default one + setInputDevice(defaultAudioInputDevice()); + setOutputDevice(defaultAudioOutputDevice()); + + startTimer(100); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } } CVoiceClientVatlib::~CVoiceClientVatlib() { - } void CVoiceClientVatlib::setCallsign(const BlackMisc::Aviation::CCallsign &callsign) @@ -38,54 +50,131 @@ namespace BlackCore } - void CVoiceClientVatlib::setVolume(const uint32_t comIndex, const uint32_t volumne) + void CVoiceClientVatlib::setVolume(const uint32_t comUnit, const uint32_t volumne) { } - void CVoiceClientVatlib::startTransmitting(const uint32_t comIndex) + void CVoiceClientVatlib::startTransmitting(const uint32_t comUnit) { } - void CVoiceClientVatlib::stopTransmitting(const uint32_t comIndex) + void CVoiceClientVatlib::stopTransmitting(const uint32_t comUnit) { } - bool CVoiceClientVatlib::isReceiving(const uint32_t comIndex) + bool CVoiceClientVatlib::isReceiving(const uint32_t comUnit) { } - bool CVoiceClientVatlib::isConnected(const uint32_t comIndex) + bool CVoiceClientVatlib::isConnected(const uint32_t comUnit) { } - void CVoiceClientVatlib::roomUserList(const uint32_t comIndex) + void CVoiceClientVatlib::roomUserList(const uint32_t comUnit) { } - const QList &CVoiceClientVatlib::audioInputDevices(const uint32_t comIndex) const + const QList &CVoiceClientVatlib::audioInputDevices() const { return m_inputDevices; } - const QList &CVoiceClientVatlib::audioOutputDevices(const uint32_t comIndex) const + const QList &CVoiceClientVatlib::audioOutputDevices() const { return m_outputDevices; } - void CVoiceClientVatlib::setInputDevice(const uint32_t comUnit, BlackMisc::Voice::CInputAudioDevice &device) + const BlackMisc::Voice::CInputAudioDevice & CVoiceClientVatlib::defaultAudioInputDevice() const { - + foreach(BlackMisc::Voice::CInputAudioDevice inputDevice, m_inputDevices) + { + if(inputDevice.name().contains("[default]", Qt::CaseInsensitive)) + return inputDevice; + } + return BlackMisc::Voice::CInputAudioDevice(); } - void CVoiceClientVatlib::setOutputDevice(const uint32_t comUnit, BlackMisc::Voice::COutputAudioDevice &device) + const BlackMisc::Voice::COutputAudioDevice & CVoiceClientVatlib::defaultAudioOutputDevice() const { + foreach(BlackMisc::Voice::COutputAudioDevice outputDevice, m_outputDevices) + { + if(outputDevice.name().contains("[default]", Qt::CaseInsensitive)) + return outputDevice; + } + return BlackMisc::Voice::COutputAudioDevice(); + } + void CVoiceClientVatlib::setInputDevice(const BlackMisc::Voice::CInputAudioDevice &device) + { + if (!device.isValid()) + return; + + try + { + if( !m_voice->SetInputDevice(device.index())) + { + qWarning() << "SetInputDevice() failed"; + } + if (!m_voice->IsInputDeviceAlive()) + { + qWarning() << "Input device hit a fatal error"; + } + } + catch (...) { exceptionDispatcher(Q_FUNC_INFO); } + } + + void CVoiceClientVatlib::setOutputDevice(const BlackMisc::Voice::COutputAudioDevice &device) + { + if (!device.isValid()) + return; + + try + { + m_voice->SetOutputDevice(0, device.index()); + + if (!m_voice->IsOutputDeviceAlive(0)) + { + qWarning() << "Input device hit a fatal error"; + } + } + catch (...) { exceptionDispatcher(Q_FUNC_INFO); } + } + + void CVoiceClientVatlib::runSquelchTest() + { + try + { + Q_ASSERT_X (m_voice->IsValid() && m_voice->IsSetup(), "CVoiceClientVatlib", "Cvatlib_Voice_Simple invalid or not setup!"); + m_voice->BeginFindSquelch(); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } + + // Start the timer only if no exception was thrown before + QTimer::singleShot(5000, this, SLOT(onEndFindSquelch())); + } + + void CVoiceClientVatlib::runMicTest() + { + try + { + Q_ASSERT_X (m_voice->IsValid() && m_voice->IsSetup(), "CVoiceClientVatlib", "Cvatlib_Voice_Simple invalid or not setup!"); + m_voice->BeginMicTest(); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } + + // Start the timer only if no exception was thrown before + QTimer::singleShot(5000, this, SLOT(onEndMicTest())); + } + + float CVoiceClientVatlib::inputSquelch() const + { + return m_inputSquelch; } const BlackMisc::Voice::CVoiceRoom &CVoiceClientVatlib::voiceRoom(const uint32_t comUnit) @@ -93,6 +182,45 @@ namespace BlackCore } + void CVoiceClientVatlib::timerEvent(QTimerEvent *) + { + try + { + Q_ASSERT_X (m_voice->IsValid() && m_voice->IsSetup(), "CVoiceClientVatlib", "Cvatlib_Voice_Simple invalid or not setup!"); + m_voice->DoProcessing(); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } + } + + void CVoiceClientVatlib::onEndFindSquelch() + { + try + { + Q_ASSERT_X (m_voice->IsValid() && m_voice->IsSetup(), "CVoiceClientVatlib", "Cvatlib_Voice_Simple invalid or not setup!"); + + m_voice->EndFindSquelch(); + + //TODO: store captured squelch + m_inputSquelch = m_voice->GetInputSquelch(); + qDebug() << m_inputSquelch; + emit squelchTestFinished(); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } + } + + void CVoiceClientVatlib::onEndMicTest() + { + try + { + Q_ASSERT_X (m_voice->IsValid() && m_voice->IsSetup(), "CVoiceClientVatlib", "Cvatlib_Voice_Simple invalid or not setup!"); + + Cvatlib_Voice_Simple::agc micTestResult = m_voice->EndMicTest(); + qDebug() << micTestResult; + emit micTestFinished(); + } + catch (...) { this->exceptionDispatcher(Q_FUNC_INFO); } + } + /********************************** * * * * * * * * * * * * * * * * * * * ************************************/ /********************************** shimlib callbacks ************************************/ /********************************** * * * * * * * * * * * * * * * * * * * ************************************/ @@ -124,4 +252,39 @@ namespace BlackCore cbvar_cast(cbVar)->m_outputDevices.append(outputDevice); } + void CVoiceClientVatlib::exceptionDispatcher(const char *caller) + { + QString msg("Caller: "); + msg.append(caller).append(" ").append("Exception: "); + try + { + throw; + } + catch (const NetworkNotConnectedException &e) + { + // this could be caused by a race condition during normal operation, so not an error + msg.append("NetworkNotConnectedException").append(" ").append(e.what()); + emit this->exception(msg); + qDebug() << "NetworkNotConnectedException caught in " << caller << "\n" << e.what(); + } + catch (const VatlibException &e) + { + msg.append("VatlibException").append(" ").append(e.what()); + emit this->exception(msg, true); + qFatal("VatlibException caught in %s\n%s", caller, e.what()); + } + catch (const std::exception &e) + { + msg.append("std::exception").append(" ").append(e.what()); + emit this->exception(msg, true); + qFatal("std::exception caught in %s\n%s", caller, e.what()); + } + catch (...) + { + msg.append("unknown exception"); + emit this->exception(msg, true); + qFatal("Unknown exception caught in %s", caller); + } + } + } // namespace BlackCore diff --git a/src/blackcore/voiceclient_vatlib.h b/src/blackcore/voiceclient_vatlib.h index d116e7e0e..4700f85a2 100644 --- a/src/blackcore/voiceclient_vatlib.h +++ b/src/blackcore/voiceclient_vatlib.h @@ -13,7 +13,9 @@ namespace BlackCore { - + /*! + * Vatlib implementation of the IVoiceClient interface. + */ class CVoiceClientVatlib : public IVoiceClient { Q_OBJECT @@ -32,11 +34,26 @@ namespace BlackCore virtual bool isConnected(const uint32_t comUnit); virtual void roomUserList(const uint32_t comUnit); - virtual const QList &audioInputDevices(const uint32_t comUnit) const ; - virtual const QList & audioOutputDevices(const uint32_t comUnit) const; - virtual void setInputDevice(const uint32_t comUnit, BlackMisc::Voice::CInputAudioDevice &device); - virtual void setOutputDevice(const uint32_t comUnit, BlackMisc::Voice::COutputAudioDevice &device); + // Hardware devices + // TODO: Vatlib supports multiple output devices. That basically means, you could connect + // to different voice rooms and send their audio to different devices, e.g. ATIS to loudspeakers + // and ATC to headspeakers. Is not important to implement that now, if ever. + virtual const QList & audioInputDevices() const ; + virtual const QList & audioOutputDevices() const; + + virtual const BlackMisc::Voice::CInputAudioDevice & defaultAudioInputDevice() const; + virtual const BlackMisc::Voice::COutputAudioDevice & defaultAudioOutputDevice() const; + + virtual void setInputDevice(const BlackMisc::Voice::CInputAudioDevice &device); + virtual void setOutputDevice(const BlackMisc::Voice::COutputAudioDevice &device); + + // Mic tests + virtual void runSquelchTest(); + virtual void runMicTest(); + + virtual float inputSquelch() const; + virtual const BlackMisc::Voice::CVoiceRoom &voiceRoom (const uint32_t comUnit); @@ -44,6 +61,14 @@ namespace BlackCore public slots: + protected: // QObject overrides + virtual void timerEvent(QTimerEvent *); + + private slots: + // slots for Mic tests + void onEndFindSquelch(); + void onEndMicTest(); + private: // shimlib callbacks @@ -52,11 +77,23 @@ namespace BlackCore static void onInputHardwareDeviceReceived(Cvatlib_Voice_Simple* obj, const char* name, void* cbVar); static void onOutputHardwareDeviceReceived(Cvatlib_Voice_Simple* obj, const char* name, void* cbVar); - QScopedPointer m_voice; + void exceptionDispatcher(const char *caller); + + struct Cvatlib_Voice_Simple_Deleter + { + static inline void cleanup(Cvatlib_Voice_Simple *pointer) + { + pointer->Destroy(); + } + }; + + QScopedPointer m_voice; BlackMisc::Aviation::CCallsign m_callsign; QMap m_voiceRoomMap; QList m_inputDevices; QList m_outputDevices; + + float m_inputSquelch; }; } // namespace BlackCore