mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 01:05:34 +08:00
refs #255 move voice channel handling from CVoiceVatlib into a dedicated class CVoiceChannel
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "blackcorefreefunctions.h"
|
||||
#include "voice.h"
|
||||
#include "voice_channel.h"
|
||||
#include "simulator.h"
|
||||
#include <QThread>
|
||||
|
||||
@@ -15,10 +15,8 @@ namespace BlackCore
|
||||
// for some reasons (ask RW) these are registered twice
|
||||
qRegisterMetaType<ISimulator::Status>();
|
||||
qRegisterMetaType<ISimulator::Status>("Status");
|
||||
qRegisterMetaType<IVoice::ComUnit>();
|
||||
qRegisterMetaType<IVoice::ComUnit>("ComUnit");
|
||||
qRegisterMetaType<IVoice::ConnectionStatus>();
|
||||
qRegisterMetaType<IVoice::ConnectionStatus>("ConnectionStatus");
|
||||
qRegisterMetaType<IVoiceChannel::ConnectionStatus>();
|
||||
qRegisterMetaType<IVoiceChannel::ConnectionStatus>("ConnectionStatus");
|
||||
}
|
||||
|
||||
bool isCurrentThreadCreatingThread(QObject *toBeTested)
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
class IVoiceChannel;
|
||||
|
||||
/*!
|
||||
* Interface to a connection to a ATC voice server for use in flight simulation.
|
||||
*
|
||||
@@ -49,35 +51,9 @@ namespace BlackCore
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* \brief IVoice currently supports two different com units
|
||||
*/
|
||||
enum ComUnit
|
||||
{
|
||||
COM1 = 0, /*!< ComUnit 1 */
|
||||
COM2 /*!< ComUnit 2 */
|
||||
};
|
||||
|
||||
//! Com status
|
||||
enum ConnectionStatus
|
||||
{
|
||||
Disconnected = 0, //!< Not connected
|
||||
Disconnecting, //!< In transition to disconnected
|
||||
DisconnectedError, //!< Disconnected due to socket error
|
||||
Connecting, //!< Connection initiated but not established
|
||||
Connected, //!< Connection established
|
||||
ConnectingFailed, //!< Failed to connect
|
||||
};
|
||||
|
||||
//! Virtual destructor.
|
||||
virtual ~IVoice() {}
|
||||
|
||||
/*!
|
||||
* \brief Own aircraft's callsign
|
||||
* \param callsign
|
||||
*/
|
||||
virtual void setMyAircraftCallsign(const BlackMisc::Aviation::CCallsign &callsign) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Audio devices
|
||||
* \return
|
||||
@@ -128,6 +104,9 @@ namespace BlackCore
|
||||
*/
|
||||
virtual QString micTestResultAsString() const = 0;
|
||||
|
||||
//! Get voice channel object
|
||||
virtual IVoiceChannel *getVoiceChannel(qint32 channelIndex) const = 0;
|
||||
|
||||
public slots:
|
||||
|
||||
/*!
|
||||
@@ -150,68 +129,6 @@ namespace BlackCore
|
||||
*/
|
||||
virtual void setInputDevice(const BlackMisc::Audio::CAudioDevice &device) = 0;
|
||||
|
||||
/*!
|
||||
* Get COM1/2 voice rooms, which then allows to retrieve information
|
||||
* such as audio status etc.
|
||||
*/
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const = 0;
|
||||
|
||||
/*!
|
||||
* Get COM1/2 voice rooms, const and with no status update
|
||||
*/
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRooms() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Join voice room
|
||||
* \param comUnit COM1/2
|
||||
* \param voiceRoom
|
||||
*/
|
||||
virtual void joinVoiceRoom(const ComUnit comUnit, const BlackMisc::Audio::CVoiceRoom &voiceRoom) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Leave voice room
|
||||
* \param comUnit COM1/2
|
||||
*/
|
||||
virtual void leaveVoiceRoom(const ComUnit comUnit) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Leave all voice rooms
|
||||
*/
|
||||
virtual void leaveAllVoiceRooms() = 0;
|
||||
|
||||
/*!
|
||||
* \brief Set room output volume for COM unit
|
||||
*/
|
||||
virtual void setRoomOutputVolume(const ComUnit comUnit, const qint32 volumne) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Start transmitting
|
||||
*/
|
||||
virtual void startTransmitting(const ComUnit comUnit) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Stop transmitting
|
||||
*/
|
||||
virtual void stopTransmitting(const ComUnit comUnit) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Get voice room callsings
|
||||
* \return
|
||||
*/
|
||||
virtual BlackMisc::Aviation::CCallsignList getVoiceRoomCallsigns(const ComUnit comUnit) const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Is muted?
|
||||
*/
|
||||
virtual bool isMuted() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Switch audio output, enable or disable given COM unit.
|
||||
* \param comUnit
|
||||
* \param enable enable or disable output
|
||||
*/
|
||||
virtual void switchAudioOutput(const ComUnit comUnit, bool enable) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Enable audio loopback to route recorded voice from microphone to speakers
|
||||
* \param enable (default true)
|
||||
@@ -220,40 +137,6 @@ namespace BlackCore
|
||||
|
||||
signals:
|
||||
|
||||
//! The status of a room has changed.
|
||||
void connectionStatusChanged(ComUnit comUnit, ConnectionStatus oldStatus, ConnectionStatus newStatus);
|
||||
|
||||
// Signals about users joining and leaving
|
||||
/*!
|
||||
* \brief User with callsign joined room
|
||||
*/
|
||||
void userJoinedRoom(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
/*!
|
||||
* \brief User with callsign left room
|
||||
*/
|
||||
void userLeftRoom(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
// Audio signals
|
||||
/*!
|
||||
* \brief Audio for given unit started
|
||||
*/
|
||||
void audioStarted(const ComUnit comUnit);
|
||||
|
||||
/*!
|
||||
* \brief Audio for given unit stopped
|
||||
*/
|
||||
void audioStopped(const ComUnit comUnit);
|
||||
|
||||
/*!
|
||||
* \brief Audio started
|
||||
*/
|
||||
void globalAudioStarted();
|
||||
|
||||
/*!
|
||||
* \brief Audio stopped
|
||||
*/
|
||||
void globalAudioStopped();
|
||||
|
||||
// Test signals
|
||||
/*!
|
||||
* \brief Squelch test completed
|
||||
@@ -275,7 +158,4 @@ namespace BlackCore
|
||||
|
||||
} // namespace BlackCore
|
||||
|
||||
Q_DECLARE_METATYPE(BlackCore::IVoice::ComUnit)
|
||||
Q_DECLARE_METATYPE(BlackCore::IVoice::ConnectionStatus)
|
||||
|
||||
#endif // guard
|
||||
|
||||
121
src/blackcore/voice_channel.h
Normal file
121
src/blackcore/voice_channel.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* Copyright (C) 2014
|
||||
* swift project community / contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKCORE_VOICE_CHANNEL_H
|
||||
#define BLACKCORE_VOICE_CHANNEL_H
|
||||
|
||||
#include "voice_vatlib.h"
|
||||
#include "blackmisc/statusmessage.h"
|
||||
#include "blackmisc/voiceroomlist.h"
|
||||
#include "blackmisc/avcallsignlist.h"
|
||||
#include <QObject>
|
||||
#include <QScopedPointer>
|
||||
|
||||
//! \file
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
//! Interface to a voice channel
|
||||
class IVoiceChannel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! Com status
|
||||
enum ConnectionStatus
|
||||
{
|
||||
Disconnected = 0, //!< Not connected
|
||||
Disconnecting, //!< In transition to disconnected
|
||||
DisconnectedError, //!< Disconnected due to socket error
|
||||
Connecting, //!< Connection initiated but not established
|
||||
Connected, //!< Connection established
|
||||
ConnectingFailed, //!< Failed to connect
|
||||
};
|
||||
|
||||
//! Join voice room
|
||||
virtual void joinVoiceRoom(const BlackMisc::Audio::CVoiceRoom &voiceRoom) = 0;
|
||||
|
||||
//! Leave voice room
|
||||
virtual void leaveVoiceRoom() = 0;
|
||||
|
||||
//! Set room output volume
|
||||
virtual void setRoomOutputVolume(const qint32 volume) = 0;
|
||||
|
||||
//! Start transmitting
|
||||
virtual void startTransmitting() = 0;
|
||||
|
||||
//! Stop transmitting
|
||||
virtual void stopTransmitting() = 0;
|
||||
|
||||
//! Get voice room callsings
|
||||
virtual BlackMisc::Aviation::CCallsignList getVoiceRoomCallsigns() const = 0;
|
||||
|
||||
//! Switch audio output, enable or disable
|
||||
virtual void switchAudioOutput(bool enable) = 0;
|
||||
|
||||
//! Set own aircraft's callsign
|
||||
virtual void setMyAircraftCallsign(const BlackMisc::Aviation::CCallsign &callsign) = 0;
|
||||
|
||||
//! Get voice room
|
||||
virtual BlackMisc::Audio::CVoiceRoom getVoiceRoom() const = 0;
|
||||
|
||||
//! Get assigned room index
|
||||
virtual qint32 getRoomIndex() const = 0;
|
||||
|
||||
//! Is channel muted?
|
||||
virtual bool isMuted() const = 0;
|
||||
|
||||
//! Set channel volume
|
||||
virtual void setVolume(quint32 volume) = 0;
|
||||
|
||||
//! Get channel volume
|
||||
virtual quint32 getVolume() const = 0;
|
||||
|
||||
//! Update room status
|
||||
virtual void updateRoomStatus(Cvatlib_Voice_Simple::roomStatusUpdate roomStatus) = 0;
|
||||
|
||||
signals:
|
||||
|
||||
//! We sent a message about the status of the network connection, for the attention of the user.
|
||||
void statusMessage(const BlackMisc::CStatusMessage &message);
|
||||
|
||||
//! The status of a room has changed.
|
||||
void connectionStatusChanged(ConnectionStatus oldStatus, ConnectionStatus newStatus);
|
||||
|
||||
// Signals about users joining and leaving
|
||||
|
||||
//! User with callsign joined room
|
||||
void userJoinedRoom(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! User with callsign left room
|
||||
void userLeftRoom(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
// Audio signals
|
||||
|
||||
//! Audio for given unit started
|
||||
void audioStarted();
|
||||
|
||||
//! Audio for given unit stopped
|
||||
void audioStopped();
|
||||
|
||||
protected:
|
||||
|
||||
//! Constructor
|
||||
IVoiceChannel(QObject *parent = nullptr) : QObject(parent) {}
|
||||
|
||||
//! Destructor
|
||||
virtual ~IVoiceChannel() {}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(BlackCore::IVoiceChannel::ConnectionStatus)
|
||||
|
||||
#endif // guard
|
||||
490
src/blackcore/voice_channel_vatlib.cpp
Normal file
490
src/blackcore/voice_channel_vatlib.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
/* Copyright (C) 2014
|
||||
* swift project community / contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "voice_channel_vatlib.h"
|
||||
#include "voice_channel_vatlib_p.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Audio;
|
||||
using namespace BlackMisc::Aviation;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
// Room data hash shared between all CVoiceChannel objects
|
||||
QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> CVoiceChannelVatlibPrivate::m_sharedRoomData;
|
||||
|
||||
// Static list of available rooms
|
||||
QList<qint32> CVoiceChannelVatlibPrivate::m_availableRooms = {0, 1};
|
||||
|
||||
// Constructor
|
||||
// Don't set the QObject parent. It will conflict with @QSharedPointer@ memory management
|
||||
CVoiceChannelVatlibPrivate::CVoiceChannelVatlibPrivate(TVatlibPointer vatlib, CVoiceChannelVatlib *parent)
|
||||
: m_vatlib(vatlib),
|
||||
m_mutexSharedRoomData(QMutex::Recursive),
|
||||
m_mutexCallSign(QMutex::Recursive),
|
||||
m_mutexVoiceRoom(QMutex::Recursive),
|
||||
m_mutexCallsignList(QMutex::Recursive),
|
||||
q_ptr(parent)
|
||||
{
|
||||
m_roomIndex.store(InvalidRoomIndex);
|
||||
m_volume.store(100);
|
||||
m_connectionRefCount.store(0);
|
||||
m_outputEnabled.store(true);
|
||||
m_roomStatus.store(IVoiceChannel::Disconnected);
|
||||
|
||||
connect(this, &CVoiceChannelVatlibPrivate::userJoinedLeft, this, &CVoiceChannelVatlibPrivate::processUserJoinedLeft, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
CVoiceChannelVatlibPrivate::~CVoiceChannelVatlibPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::changeConnectionStatus(IVoiceChannel::ConnectionStatus newStatus)
|
||||
{
|
||||
Q_Q(CVoiceChannelVatlib);
|
||||
|
||||
m_roomStatus = newStatus;
|
||||
emit q->connectionStatusChanged(m_roomStatus, newStatus);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::switchAudioOutput(bool enable)
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(m_vatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceChannelVatlibPrivate", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(m_roomIndex), "CVoiceChannelVatlibPrivate", "Room index out of bounds!");
|
||||
|
||||
m_outputEnabled = enable;
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetOutputState(m_roomIndex, 0, enable);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::startTransmitting()
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(m_vatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceChannelVatlibPrivate", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(m_roomIndex), "CVoiceChannelVatlibPrivate", "Room index out of bounds!");
|
||||
|
||||
if (m_roomStatus != IVoiceChannel::Connected) return;
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetMicState(m_roomIndex, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::stopTransmitting()
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(m_vatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceChannelVatlibPrivate", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(m_roomIndex), "CVoiceChannelVatlibPrivate", "Room index out of bounds!");
|
||||
|
||||
if (m_roomStatus != IVoiceChannel::Connected) return;
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetMicState(m_roomIndex, false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::setRoomOutputVolume(const qint32 volume)
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(m_vatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceChannelVatlibPrivate", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(m_roomIndex), "CVoiceChannelVatlibPrivate", "Room index out of bounds!");
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetRoomVolume(m_roomIndex, volume);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
// Forward exception as signal
|
||||
void CVoiceChannelVatlibPrivate::exceptionDispatcher(const char *caller)
|
||||
{
|
||||
Q_Q(CVoiceChannelVatlib);
|
||||
|
||||
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 q->statusMessage(CStatusMessage::getErrorMessage(msg, CStatusMessage::TypeAudio));
|
||||
qDebug() << "NetworkNotConnectedException caught in " << caller << "\n" << e.what();
|
||||
}
|
||||
catch (const VatlibException &e)
|
||||
{
|
||||
msg.append("VatlibException").append(" ").append(e.what());
|
||||
emit q->statusMessage(CStatusMessage::getErrorMessage(msg, CStatusMessage::TypeAudio));
|
||||
qFatal("VatlibException caught in %s\n%s", caller, e.what());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
msg.append("std::exception").append(" ").append(e.what());
|
||||
emit q->statusMessage(CStatusMessage::getErrorMessage(msg, CStatusMessage::TypeAudio));
|
||||
qFatal("std::exception caught in %s\n%s", caller, e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
msg.append("unknown exception");
|
||||
emit q->statusMessage(CStatusMessage::getErrorMessage(msg, CStatusMessage::TypeAudio));
|
||||
qFatal("Unknown exception caught in %s", caller);
|
||||
}
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::processUserJoinedLeft()
|
||||
{
|
||||
Q_Q(CVoiceChannelVatlib);
|
||||
|
||||
try
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(m_vatlib);
|
||||
// Paranoia... clear list completely
|
||||
if (!m_vatlib->IsRoomConnected(m_roomIndex))
|
||||
{
|
||||
QMutexLocker lockCallsignList(&m_mutexCallsignList);
|
||||
m_listCallsigns.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Callbacks already completed when function GetRoomUserList returns,
|
||||
// thereafter m_voiceRoomCallsignsUpdate is filled with the latest callsigns
|
||||
|
||||
m_vatlib->GetRoomUserList(m_roomIndex, updateRoomUsers, this);
|
||||
|
||||
QMutexLocker lockCallsignList(&m_mutexCallsignList);
|
||||
// we have all current users in m_temporaryVoiceRoomCallsigns
|
||||
foreach(CCallsign callsign, m_listCallsigns)
|
||||
{
|
||||
if (!m_temporaryVoiceRoomCallsigns.contains(callsign))
|
||||
{
|
||||
// User has left
|
||||
emit q->userLeftRoom(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(CCallsign callsign, m_temporaryVoiceRoomCallsigns)
|
||||
{
|
||||
if (!m_listCallsigns.contains(callsign))
|
||||
{
|
||||
// he joined
|
||||
emit q->userJoinedRoom(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we update it with our new list
|
||||
m_listCallsigns = m_temporaryVoiceRoomCallsigns;
|
||||
m_temporaryVoiceRoomCallsigns.clear();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
CVoiceChannelVatlibPrivate *cbvar_cast_voiceChannelPrivate(void *cbvar)
|
||||
{
|
||||
return static_cast<CVoiceChannelVatlibPrivate *>(cbvar);
|
||||
}
|
||||
|
||||
/*
|
||||
* Room user received
|
||||
*/
|
||||
void CVoiceChannelVatlibPrivate::updateRoomUsers(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar)
|
||||
{
|
||||
Q_UNUSED(obj)
|
||||
|
||||
// sanity check
|
||||
QString callsign = QString(name);
|
||||
if (callsign.isEmpty()) return;
|
||||
|
||||
// add callsign
|
||||
CVoiceChannelVatlibPrivate *voiceChannelPrivate = cbvar_cast_voiceChannelPrivate(cbVar);
|
||||
|
||||
// add user
|
||||
// callsign might contain: VATSIM id, user name
|
||||
if (callsign.contains(" "))
|
||||
{
|
||||
QStringList parts = callsign.split(" ");
|
||||
callsign = parts[0];
|
||||
// I throw away VATSIM id here, maybe we could use it
|
||||
}
|
||||
|
||||
voiceChannelPrivate->addTemporaryCallsignForRoom(CCallsign(callsign));
|
||||
}
|
||||
|
||||
/*
|
||||
* Add temp.callsign for room
|
||||
*/
|
||||
void CVoiceChannelVatlibPrivate::addTemporaryCallsignForRoom(const CCallsign &callsign)
|
||||
{
|
||||
if (m_temporaryVoiceRoomCallsigns.contains(callsign)) return;
|
||||
m_temporaryVoiceRoomCallsigns.push_back(callsign);
|
||||
}
|
||||
|
||||
// Get shared room data
|
||||
QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> &CVoiceChannelVatlibPrivate::getSharedRoomData()
|
||||
{
|
||||
return m_sharedRoomData;
|
||||
}
|
||||
|
||||
// Allocate a new room
|
||||
qint32 CVoiceChannelVatlibPrivate::allocateRoom()
|
||||
{
|
||||
Q_ASSERT(!m_availableRooms.isEmpty());
|
||||
return m_availableRooms.takeFirst();
|
||||
}
|
||||
|
||||
// Constructor
|
||||
CVoiceChannelVatlib::CVoiceChannelVatlib(TVatlibPointer vatlib, QObject *parent)
|
||||
: IVoiceChannel(parent),
|
||||
d_ptr(new CVoiceChannelVatlibPrivate(vatlib, this))
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
CVoiceChannelVatlib::~CVoiceChannelVatlib()
|
||||
{
|
||||
}
|
||||
|
||||
// Join room
|
||||
void CVoiceChannelVatlib::joinVoiceRoom(const CVoiceRoom &voiceRoom)
|
||||
{
|
||||
// Find if a different channel is connected already to this voice room
|
||||
auto roomDataList = CVoiceChannelVatlibPrivate::getSharedRoomData().values();
|
||||
auto iterator = std::find_if(roomDataList.begin(), roomDataList.end(), [&](const QSharedPointer<CVoiceChannelVatlibPrivate> roomData)
|
||||
{
|
||||
return roomData->m_voiceRoom.getVoiceRoomUrl() == voiceRoom.getVoiceRoomUrl();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
// If we found an another channel
|
||||
if (iterator != roomDataList.end())
|
||||
{
|
||||
// Increase the connection reference counter
|
||||
(*iterator)->m_connectionRefCount++;
|
||||
|
||||
d_ptr = (*iterator);
|
||||
|
||||
// Assign shared room data to this channel index
|
||||
CVoiceChannelVatlibPrivate::getSharedRoomData().insert(this, *iterator);
|
||||
|
||||
// Since the room is used already, we have to simulate the state changes
|
||||
emit connectionStatusChanged(IVoiceChannel::Disconnected, IVoiceChannel::Connecting);
|
||||
emit connectionStatusChanged(IVoiceChannel::Connecting, IVoiceChannel::Connected);
|
||||
emit d_ptr->userJoinedLeft();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMutexLocker lockVoiceRoom(&d_ptr->m_mutexVoiceRoom);
|
||||
// No one else is using this voice room, so prepare to join
|
||||
d_ptr->m_voiceRoom = voiceRoom;
|
||||
d_ptr->m_roomIndex = d_ptr->allocateRoom();
|
||||
d_ptr->m_roomStatus = IVoiceChannel::Disconnected;
|
||||
|
||||
std::lock_guard<TVatlibPointer> locker(d_ptr->m_vatlib);
|
||||
QMutexLocker lockerCallsign(&d_ptr->m_mutexCallSign);
|
||||
bool jr = d_ptr->m_vatlib->JoinRoom(d_ptr->m_roomIndex, d_ptr->m_callsign.toQString().toLatin1().constData(),
|
||||
d_ptr->m_voiceRoom.getVoiceRoomUrl().toLatin1().constData());
|
||||
if (!jr) qWarning() << "Could not join voice room";
|
||||
CVoiceChannelVatlibPrivate::m_sharedRoomData.insert(this, d_ptr);
|
||||
++d_ptr->m_connectionRefCount;
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
d_ptr->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
// Leave room
|
||||
void CVoiceChannelVatlib::leaveVoiceRoom()
|
||||
{
|
||||
// If this room is not connected, there is nothing to do
|
||||
if (d_ptr->m_roomStatus == IVoiceChannel::Disconnecting || d_ptr->m_roomStatus == IVoiceChannel::Disconnected) return;
|
||||
|
||||
// Decrease the connection reference counter
|
||||
--d_ptr->m_connectionRefCount;
|
||||
|
||||
// If this was the last channel, connected to the room, leave it.
|
||||
if (d_ptr->m_connectionRefCount == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
qDebug() << "Leaving voice room!";
|
||||
if(d_ptr->m_vatlib->IsRoomConnected(d_ptr->m_roomIndex))
|
||||
{
|
||||
std::lock_guard<TVatlibPointer> locker(d_ptr->m_vatlib);
|
||||
d_ptr->m_vatlib->LeaveRoom(d_ptr->m_roomIndex);
|
||||
d_ptr->m_availableRooms.append(d_ptr->m_roomIndex);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
d_ptr->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to assign a private class
|
||||
// This automatically clears callsign list etc.
|
||||
TVatlibPointer vatlib = d_ptr->m_vatlib;
|
||||
d_ptr.reset(new CVoiceChannelVatlibPrivate(vatlib, this));
|
||||
CVoiceChannelVatlibPrivate::getSharedRoomData().insert(this, d_ptr);
|
||||
|
||||
// Simulate the state change
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::Disconnecting);
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
// Set room volume
|
||||
void CVoiceChannelVatlib::setRoomOutputVolume(const qint32 volume)
|
||||
{
|
||||
d_ptr->setRoomOutputVolume(volume);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::startTransmitting()
|
||||
{
|
||||
d_ptr->startTransmitting();
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::stopTransmitting()
|
||||
{
|
||||
d_ptr->stopTransmitting();
|
||||
}
|
||||
|
||||
CCallsignList CVoiceChannelVatlib::getVoiceRoomCallsigns() const
|
||||
{
|
||||
QMutexLocker lockCallsignList(&d_ptr->m_mutexCallsignList);
|
||||
return d_ptr->m_listCallsigns;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::switchAudioOutput(bool enable)
|
||||
{
|
||||
d_ptr->switchAudioOutput(enable);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setMyAircraftCallsign(const CCallsign &callsign)
|
||||
{
|
||||
QMutexLocker lockerCallsign(&d_ptr->m_mutexCallSign);
|
||||
d_ptr->m_callsign = callsign;
|
||||
}
|
||||
|
||||
BlackMisc::Audio::CVoiceRoom CVoiceChannelVatlib::getVoiceRoom() const
|
||||
{
|
||||
QMutexLocker lockVoiceRoom(&d_ptr->m_mutexVoiceRoom);
|
||||
return d_ptr->m_voiceRoom;
|
||||
}
|
||||
|
||||
qint32 CVoiceChannelVatlib::getRoomIndex() const
|
||||
{
|
||||
return d_ptr->m_roomIndex;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::updateRoomStatus(Cvatlib_Voice_Simple::roomStatusUpdate roomStatus)
|
||||
{
|
||||
switch (roomStatus)
|
||||
{
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_JoinSuccess:
|
||||
{
|
||||
QMutexLocker lockVoiceRoom(&d_ptr->m_mutexVoiceRoom);
|
||||
d_ptr->m_voiceRoom.setConnected(true);
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::Connected);
|
||||
bool isOutputEnabled = d_ptr->m_outputEnabled;
|
||||
switchAudioOutput(isOutputEnabled);
|
||||
emit d_ptr->userJoinedLeft();
|
||||
break;
|
||||
}
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_JoinFail:
|
||||
{
|
||||
QMutexLocker lockVoiceRoom(&d_ptr->m_mutexVoiceRoom);
|
||||
d_ptr->m_voiceRoom.setConnected(false);
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::ConnectingFailed);
|
||||
break;
|
||||
}
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_UnexpectedDisconnectOrKicked:
|
||||
d_ptr->m_voiceRoom.setConnected(false);
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::DisconnectedError);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_LeaveComplete:
|
||||
{
|
||||
// Instead of clearing and resetting all internals, we just assign a new default room data
|
||||
// The former one will be deallocated automatically.
|
||||
TVatlibPointer vatlib = d_ptr->m_vatlib;
|
||||
d_ptr.reset(new CVoiceChannelVatlibPrivate(vatlib, this));
|
||||
CVoiceChannelVatlibPrivate::getSharedRoomData().insert(this, d_ptr);
|
||||
d_ptr->changeConnectionStatus(IVoiceChannel::Disconnected);
|
||||
break;
|
||||
}
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_UserJoinsLeaves:
|
||||
// FIXME: We cannot call GetRoomUserList because vatlib is not reentrent safe.
|
||||
emit d_ptr->userJoinedLeft();
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_AudioStarted:
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_AudioStopped:
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_RoomAudioStarted:
|
||||
emit audioStarted();
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_RoomAudioStopped:
|
||||
emit audioStopped();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CVoiceChannelVatlib::isMuted() const
|
||||
{
|
||||
return !d_ptr->m_outputEnabled;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setVolume(quint32 volume)
|
||||
{
|
||||
d_ptr->m_volume.store(volume);
|
||||
Q_ASSERT_X(d_ptr->m_vatlib->IsValid() && d_ptr->m_vatlib->IsSetup(), "CVoiceChannelVatlibPrivate", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(d_ptr->m_vatlib->IsRoomValid(d_ptr->m_roomIndex.load()), "CVoiceChannelVatlibPrivate", "Room index out of bounds!");
|
||||
|
||||
d_ptr->m_vatlib->SetOutputVolume(d_ptr->m_roomIndex.load(), volume);
|
||||
}
|
||||
|
||||
quint32 CVoiceChannelVatlib::getVolume() const
|
||||
{
|
||||
return d_ptr->m_volume.load();
|
||||
}
|
||||
}
|
||||
87
src/blackcore/voice_channel_vatlib.h
Normal file
87
src/blackcore/voice_channel_vatlib.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* Copyright (C) 2014
|
||||
* swift project community / contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKCORE_VOICE_CHANNEL_VATLIB_H
|
||||
#define BLACKCORE_VOICE_CHANNEL_VATLIB_H
|
||||
|
||||
#include "voice_channel.h"
|
||||
#include "voice_vatlib.h"
|
||||
#include "blackmisc/statusmessage.h"
|
||||
#include "blackmisc/voiceroomlist.h"
|
||||
#include "blackmisc/avcallsignlist.h"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
//! \file
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
class CVoiceChannelVatlibPrivate;
|
||||
|
||||
//! Class implementing the voice channel interface
|
||||
class CVoiceChannelVatlib : public IVoiceChannel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! Default constructor
|
||||
CVoiceChannelVatlib(TVatlibPointer vatlib, QObject *parent = nullptr);
|
||||
|
||||
//! Destructor
|
||||
virtual ~CVoiceChannelVatlib();
|
||||
|
||||
//! \copydoc IVoiceChannel::joinVoiceRoom
|
||||
virtual void joinVoiceRoom(const BlackMisc::Audio::CVoiceRoom &voiceRoom) override;
|
||||
|
||||
//! \copydoc IVoiceChannel::leaveVoiceRoom
|
||||
virtual void leaveVoiceRoom() override;
|
||||
|
||||
//! \copydoc IVoiceChannel::setRoomOutputVolume
|
||||
virtual void setRoomOutputVolume(const qint32 volume) override;
|
||||
|
||||
//! \copydoc IVoiceChannel::startTransmitting
|
||||
virtual void startTransmitting() override;
|
||||
|
||||
//! \copydoc IVoiceChannel::stopTransmitting
|
||||
virtual void stopTransmitting() override;
|
||||
|
||||
//! \copydoc IVoiceChannel::getVoiceRoomCallsigns
|
||||
virtual BlackMisc::Aviation::CCallsignList getVoiceRoomCallsigns() const override;
|
||||
|
||||
//! \copydoc IVoiceChannel::switchAudioOutput
|
||||
virtual void switchAudioOutput(bool enable) override;
|
||||
|
||||
//! \copydoc IVoiceChannel::setMyAircraftCallsign
|
||||
virtual void setMyAircraftCallsign(const BlackMisc::Aviation::CCallsign &callsign) override;
|
||||
|
||||
//! \copydoc IVoiceChannel::getVoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getVoiceRoom() const override;
|
||||
|
||||
//! \copydoc IVoiceChannel::getRoomIndex
|
||||
virtual qint32 getRoomIndex() const override;
|
||||
|
||||
//! \copydoc IVoiceChannel::isMuted
|
||||
virtual bool isMuted() const override;
|
||||
|
||||
//! Set channel volume
|
||||
virtual void setVolume(quint32 volume) override;
|
||||
|
||||
//! Get channel volume
|
||||
virtual quint32 getVolume() const override;
|
||||
|
||||
//! \copydoc IVoiceChannel::updateRoomStatus
|
||||
virtual void updateRoomStatus(Cvatlib_Voice_Simple::roomStatusUpdate roomStatus) override;
|
||||
|
||||
private:
|
||||
QSharedPointer<CVoiceChannelVatlibPrivate> d_ptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
112
src/blackcore/voice_channel_vatlib_p.h
Normal file
112
src/blackcore/voice_channel_vatlib_p.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* Copyright (C) 2014
|
||||
* swift project community / contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKCORE_VOICE_CHANNEL_P_H
|
||||
#define BLACKCORE_VOICE_CHANNEL_P_H
|
||||
|
||||
#include "voice_channel_vatlib.h"
|
||||
#include "blackmisc/voiceroom.h"
|
||||
#include "blackmisc/avcallsign.h"
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <atomic>
|
||||
|
||||
//! \file
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
// Inhibit doxygen warnings about missing documentation
|
||||
//! \cond PRIVATE
|
||||
|
||||
// Private Implementation of CVoiceChannelVatlib
|
||||
class CVoiceChannelVatlibPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
// Default constructor
|
||||
CVoiceChannelVatlibPrivate(TVatlibPointer vatlib, CVoiceChannelVatlib *parent);
|
||||
|
||||
// Destructor
|
||||
~CVoiceChannelVatlibPrivate();
|
||||
|
||||
// Enable or disable channel audio output
|
||||
void switchAudioOutput(bool enable);
|
||||
|
||||
// Start transmitting
|
||||
void startTransmitting();
|
||||
|
||||
// Stop transmitting
|
||||
void stopTransmitting();
|
||||
|
||||
// Set room output volume
|
||||
void setRoomOutputVolume(const qint32 volume);
|
||||
|
||||
// FIXME Move into free function
|
||||
void exceptionDispatcher(const char *caller);
|
||||
|
||||
// Update connected room users
|
||||
static void updateRoomUsers(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar);
|
||||
|
||||
public slots:
|
||||
|
||||
// Process user joined/left signals
|
||||
void processUserJoinedLeft();
|
||||
|
||||
signals:
|
||||
|
||||
// Signal when user has joined or left
|
||||
void userJoinedLeft();
|
||||
|
||||
public:
|
||||
|
||||
// Add a callsign temporarily. This is used for the getUserList callback
|
||||
void addTemporaryCallsignForRoom(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
// Get shared room data for this channel
|
||||
static QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> &getSharedRoomData();
|
||||
|
||||
TVatlibPointer m_vatlib; // Shared pointer to vatlib object
|
||||
BlackMisc::Aviation::CCallsign m_callsign; // Own callsign
|
||||
std::atomic<qint32> m_roomIndex; // Room index
|
||||
BlackMisc::Audio::CVoiceRoom m_voiceRoom; // Voice Room
|
||||
std::atomic<qint32> m_volume; // Room volume
|
||||
std::atomic<quint16> m_connectionRefCount; // Connection reference couting
|
||||
std::atomic<bool> m_outputEnabled; // Is room output enabled?
|
||||
BlackMisc::Aviation::CCallsignList m_listCallsigns; // Callsigns connected to room
|
||||
std::atomic<IVoiceChannel::ConnectionStatus> m_roomStatus; // Room connection status
|
||||
|
||||
// Mutexes
|
||||
QMutex m_mutexSharedRoomData;
|
||||
QMutex m_mutexCallSign;
|
||||
QMutex m_mutexVoiceRoom;
|
||||
QMutex m_mutexCallsignList;
|
||||
|
||||
BlackMisc::Aviation::CCallsignList m_temporaryVoiceRoomCallsigns; // temp. storage of voice rooms during update
|
||||
|
||||
static QList<qint32> m_availableRooms; // Static list of not used room indexes
|
||||
static QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> m_sharedRoomData;
|
||||
const static qint32 InvalidRoomIndex = -1; // Invalid room index
|
||||
|
||||
CVoiceChannelVatlib * const q_ptr = nullptr;
|
||||
Q_DECLARE_PUBLIC(CVoiceChannelVatlib)
|
||||
|
||||
private:
|
||||
|
||||
// Change room connection status
|
||||
void changeConnectionStatus(IVoiceChannel::ConnectionStatus newStatus);
|
||||
|
||||
// Allocate a not used room identified by its index
|
||||
qint32 allocateRoom();
|
||||
};
|
||||
//! \endcond
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
@@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "voice_vatlib.h"
|
||||
#include "voice_channel_vatlib.h"
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
@@ -24,8 +25,6 @@ namespace BlackCore
|
||||
// m_audioOutput(nullptr), // removed #227
|
||||
m_inputSquelch(-1),
|
||||
m_micTestResult(Cvatlib_Voice_Simple::agc_Ok),
|
||||
m_isAudioLoopbackEnabled(false),
|
||||
m_temporaryUserRoomIndex(CVoiceVatlib::InvalidRoomIndex),
|
||||
m_lockCurrentOutputDevice(QMutex::Recursive),
|
||||
m_lockCurrentInputDevice(QMutex::Recursive),
|
||||
m_lockDeviceList(QMutex::Recursive)
|
||||
@@ -39,15 +38,15 @@ namespace BlackCore
|
||||
m_vatlib->GetInputDevices(onInputHardwareDeviceReceived, this);
|
||||
m_vatlib->GetOutputDevices(onOutputHardwareDeviceReceived, this);
|
||||
|
||||
connect(this, &CVoiceVatlib::userJoinedLeft, this, &CVoiceVatlib::onUserJoinedLeft, Qt::QueuedConnection);
|
||||
|
||||
this->m_vatlibRooms.push_back(CVoiceRoom()); // COM1
|
||||
this->m_vatlibRooms.push_back(CVoiceRoom()); // COM2
|
||||
this->m_outputEnabled.insert(COM1, true);
|
||||
this->m_outputEnabled.insert(COM2, true);
|
||||
this->m_currentInputDevice = this->defaultAudioInputDevice();
|
||||
this->m_currentOutputDevice = this->defaultAudioOutputDevice();
|
||||
// this->m_audioOutput->setVolume(1.0); // make sure the overall sound is not muted
|
||||
|
||||
for (int ii = 0; ii < 2; ++ii)
|
||||
{
|
||||
IVoiceChannel *channel = new CVoiceChannelVatlib(m_vatlib, this);
|
||||
Q_ASSERT(channel);
|
||||
m_hashChannelIndex.insert(ii, channel);
|
||||
}
|
||||
|
||||
// do processing
|
||||
this->startTimer(10);
|
||||
@@ -170,61 +169,6 @@ namespace BlackCore
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get voice rooms, with the latest status updated
|
||||
*/
|
||||
BlackMisc::Audio::CVoiceRoomList CVoiceVatlib::getComVoiceRoomsWithAudioStatus() const
|
||||
{
|
||||
QReadLocker lockForReading(&m_lockVoiceRooms);
|
||||
Q_ASSERT_X(m_vatlibRooms.size() == 2, "CVoiceVatlib", "Wrong numer of COM voice rooms");
|
||||
|
||||
if (!m_vatlib->IsValid() || !m_vatlib->IsSetup()) return CVoiceRoomList::twoEmptyRooms();
|
||||
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
// valid state, update
|
||||
CVoiceRoom com1 = this->m_vatlibRooms[0];
|
||||
CVoiceRoom com2 = this->m_vatlibRooms[1];
|
||||
com1.setConnected(m_vatlib->IsRoomConnected(static_cast<qint32>(COM1)));
|
||||
com2.setConnected(m_vatlib->IsRoomConnected(static_cast<qint32>(COM2)));
|
||||
com1.setAudioPlaying(com1.isConnected() ? m_vatlib->IsAudioPlaying(static_cast<qint32>(COM1)) : false);
|
||||
com2.setAudioPlaying(com2.isConnected() ? m_vatlib->IsAudioPlaying(static_cast<qint32>(COM2)) : false);
|
||||
CVoiceRoomList voiceRooms;
|
||||
voiceRooms.push_back(com1);
|
||||
voiceRooms.push_back(com2);
|
||||
return voiceRooms;
|
||||
}
|
||||
|
||||
/*
|
||||
* Voice room callsigns
|
||||
*/
|
||||
CCallsignList CVoiceVatlib::getVoiceRoomCallsigns(const IVoice::ComUnit comUnit) const
|
||||
{
|
||||
QReadLocker lockForReading(&m_lockCallsigns);
|
||||
CCallsignList callsigns;
|
||||
if (!this->m_vatlibRoomCallsigns.contains(comUnit)) return callsigns;
|
||||
return this->m_vatlibRoomCallsigns[comUnit];
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable audio
|
||||
*/
|
||||
void CVoiceVatlib::switchAudioOutput(const ComUnit comUnit, bool enable)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
try
|
||||
{
|
||||
m_vatlib->SetOutputState(static_cast<qint32>(comUnit), 0, enable);
|
||||
QWriteLocker lockForWriting(&m_lockOutputEnabled);
|
||||
this->m_outputEnabled[comUnit] = enable;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void CVoiceVatlib::enableAudioLoopback(bool enable)
|
||||
{
|
||||
if (enable == m_isAudioLoopbackEnabled)
|
||||
@@ -334,203 +278,35 @@ namespace BlackCore
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callsign
|
||||
*/
|
||||
void CVoiceVatlib::setMyAircraftCallsign(const BlackMisc::Aviation::CCallsign &callsign)
|
||||
IVoiceChannel *CVoiceVatlib::getVoiceChannel(qint32 channelIndex) const
|
||||
{
|
||||
QWriteLocker lockForWriting(&m_lockMyCallsign);
|
||||
m_aircraftCallsign = callsign;
|
||||
IVoiceChannel *channel = m_hashChannelIndex.value(channelIndex, nullptr);
|
||||
Q_ASSERT(channel);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/*
|
||||
* Voice room
|
||||
* Handle PTT
|
||||
*/
|
||||
void CVoiceVatlib::joinVoiceRoom(const ComUnit comUnit, const BlackMisc::Audio::CVoiceRoom &voiceRoom)
|
||||
void CVoiceVatlib::handlePushToTalk(bool value)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
if (!voiceRoom.isValid())
|
||||
qDebug() << "PTT";
|
||||
if (!this->m_vatlib) return;
|
||||
|
||||
if (value) qDebug() << "Start transmitting...";
|
||||
else qDebug() << "Stop transmitting...";
|
||||
|
||||
// FIXME: Set only once channel to active for transmitting
|
||||
if (value)
|
||||
{
|
||||
qDebug() << "Error: Cannot join invalid voice room.";
|
||||
return;
|
||||
getVoiceChannel(0)->startTransmitting();
|
||||
getVoiceChannel(1)->startTransmitting();
|
||||
}
|
||||
|
||||
try
|
||||
else
|
||||
{
|
||||
// only connect, if not yet connected
|
||||
if (this->m_vatlib->IsRoomConnected(static_cast<qint32>(comUnit))) return;
|
||||
changeConnectionStatus(comUnit, Connecting);
|
||||
QString serverSpec = voiceRoom.getVoiceRoomUrl();
|
||||
QReadLocker lockForReading(&m_lockMyCallsign);
|
||||
bool jr = m_vatlib->JoinRoom(static_cast<qint32>(comUnit), m_aircraftCallsign.toQString().toLatin1().constData(), serverSpec.toLatin1().constData());
|
||||
if (jr)
|
||||
{
|
||||
// do not(!) set as connected right now, this will be done in "status changed"
|
||||
// when room really is connected
|
||||
this->setVoiceRoomForUnit(comUnit, voiceRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("Could not join voice room");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave a room
|
||||
*/
|
||||
void CVoiceVatlib::leaveVoiceRoom(const ComUnit comUnit)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
|
||||
try
|
||||
{
|
||||
// update "meta" object for room
|
||||
this->setVoiceRoomForUnit(comUnit, CVoiceRoom()); // an empty voice room is easier to detect
|
||||
|
||||
// only leave is room is physically connected
|
||||
if (this->m_vatlib->IsRoomConnected(static_cast<qint32>(comUnit)))
|
||||
{
|
||||
m_vatlib->LeaveRoom(static_cast<qint32>(comUnit));
|
||||
this->m_vatlibRoomCallsigns[comUnit] = CCallsignList(); // empty list for this room
|
||||
changeConnectionStatus(comUnit, Disconnecting);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave all voice rooms
|
||||
*/
|
||||
void CVoiceVatlib::leaveAllVoiceRooms()
|
||||
{
|
||||
this->leaveVoiceRoom(COM1);
|
||||
this->leaveVoiceRoom(COM2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Room output volume as per COM unit
|
||||
*/
|
||||
void CVoiceVatlib::setRoomOutputVolume(const ComUnit comUnit, const qint32 volume)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetRoomVolume(static_cast<qint32>(comUnit), volume);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start transmitting
|
||||
*/
|
||||
void CVoiceVatlib::startTransmitting(const ComUnit comUnit)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
|
||||
try
|
||||
{
|
||||
m_vatlib->SetMicState(static_cast<qint32>(comUnit), true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start transmitting
|
||||
*/
|
||||
void CVoiceVatlib::stopTransmitting(const ComUnit comUnit)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_vatlib->IsRoomValid(static_cast<qint32>(comUnit)), "CVoiceVatlib", "Room index out of bounds!");
|
||||
try
|
||||
{
|
||||
m_vatlib->SetMicState(static_cast<qint32>(comUnit), false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change room status
|
||||
*/
|
||||
void CVoiceVatlib::changeRoomStatus(ComUnit comUnit, Cvatlib_Voice_Simple::roomStatusUpdate roomStatus)
|
||||
{
|
||||
qDebug() << comUnit << roomStatus; // KB_REMOVE
|
||||
CVoiceRoom vr = this->voiceRoomForUnit(comUnit);
|
||||
switch (roomStatus)
|
||||
{
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_JoinSuccess:
|
||||
{
|
||||
m_lockOutputEnabled.lockForRead();
|
||||
bool isOutputEnabled = this->m_outputEnabled[comUnit];
|
||||
m_lockOutputEnabled.unlock();
|
||||
switchAudioOutput(comUnit, isOutputEnabled);
|
||||
vr.setConnected(true);
|
||||
this->setVoiceRoomForUnit(comUnit, vr);
|
||||
changeConnectionStatus(comUnit, Connected);
|
||||
emit userJoinedLeft(comUnit);
|
||||
break;
|
||||
}
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_JoinFail:
|
||||
vr.setConnected(false);
|
||||
this->setVoiceRoomForUnit(comUnit, vr);
|
||||
changeConnectionStatus(comUnit, ConnectingFailed);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_UnexpectedDisconnectOrKicked:
|
||||
vr.setConnected(false);
|
||||
this->setVoiceRoomForUnit(comUnit, vr);
|
||||
changeConnectionStatus(comUnit, DisconnectedError);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_LeaveComplete:
|
||||
m_lockCallsigns.lockForWrite();
|
||||
m_voiceRoomCallsigns.clear();
|
||||
m_lockCallsigns.unlock();
|
||||
changeConnectionStatus(comUnit, Disconnected);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_UserJoinsLeaves:
|
||||
// FIXME: We cannot call GetRoomUserList because vatlib is not reentrent safe.
|
||||
emit userJoinedLeft(comUnit);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_RoomAudioStarted:
|
||||
emit audioStarted(comUnit);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_RoomAudioStopped:
|
||||
emit audioStopped(comUnit);
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_AudioStarted:
|
||||
emit globalAudioStarted();
|
||||
break;
|
||||
case Cvatlib_Voice_Simple::roomStatusUpdate_AudioStopped:
|
||||
emit globalAudioStopped();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
getVoiceChannel(0)->stopTransmitting();
|
||||
getVoiceChannel(1)->stopTransmitting();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,62 +364,6 @@ namespace BlackCore
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* User joined / left room
|
||||
*/
|
||||
void CVoiceVatlib::onUserJoinedLeft(const ComUnit comUnit)
|
||||
{
|
||||
QMutexLocker lockerVatlib(&m_mutexVatlib);
|
||||
Q_ASSERT_X(m_vatlib->IsValid() && m_vatlib->IsSetup(), "CVoiceVatlib", "Cvatlib_Voice_Simple invalid or not setup!");
|
||||
Q_ASSERT_X(m_temporaryUserRoomIndex == CVoiceVatlib::InvalidRoomIndex, "CVoiceClientVatlib::onUserJoinedLeft", "Cannot list users for two rooms in parallel!");
|
||||
try
|
||||
{
|
||||
// Paranoia... clear list completely
|
||||
if (!m_vatlib->IsRoomConnected(static_cast<qint32>(comUnit)))
|
||||
{
|
||||
this->m_voiceRoomCallsigns[comUnit] = CCallsignList();
|
||||
this->m_temporaryVoiceRoomCallsigns.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the room index for the slot (called in static callback)
|
||||
m_temporaryUserRoomIndex = static_cast<qint32>(comUnit);
|
||||
|
||||
// Callbacks already completed when function GetRoomUserList returns,
|
||||
// thereafter m_voiceRoomCallsignsUpdate is filled with the latest callsigns
|
||||
m_vatlib->GetRoomUserList(static_cast<qint32>(comUnit), onRoomUserReceived, this);
|
||||
m_temporaryUserRoomIndex = CVoiceVatlib::InvalidRoomIndex; // reset
|
||||
|
||||
// we have all current users in m_temporaryVoiceRoomCallsigns
|
||||
foreach(CCallsign callsign, m_voiceRoomCallsigns.value(comUnit))
|
||||
{
|
||||
if (!m_temporaryVoiceRoomCallsigns.contains(callsign))
|
||||
{
|
||||
// User has left
|
||||
emit userLeftRoom(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
QWriteLocker lockForWriting(&m_lockCallsigns);
|
||||
foreach(CCallsign callsign, m_temporaryVoiceRoomCallsigns)
|
||||
{
|
||||
if (!m_voiceRoomCallsigns.value(comUnit).contains(callsign))
|
||||
{
|
||||
// he joined
|
||||
emit userJoinedRoom(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we update it with our new list
|
||||
this->m_voiceRoomCallsigns[comUnit] = this->m_temporaryVoiceRoomCallsigns;
|
||||
this->m_temporaryVoiceRoomCallsigns.clear();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
this->exceptionDispatcher(Q_FUNC_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************** * * * * * * * * * * * * * * * * * * * ************************************/
|
||||
/********************************** shimlib callbacks ************************************/
|
||||
/********************************** * * * * * * * * * * * * * * * * * * * ************************************/
|
||||
@@ -664,36 +384,8 @@ namespace BlackCore
|
||||
void CVoiceVatlib::onRoomStatusUpdate(Cvatlib_Voice_Simple *obj, Cvatlib_Voice_Simple::roomStatusUpdate upd, qint32 roomIndex, void *cbVar)
|
||||
{
|
||||
Q_UNUSED(obj)
|
||||
ComUnit comUnit = static_cast<ComUnit>(roomIndex);
|
||||
CVoiceVatlib *voiceClientVatlib = cbvar_cast_voice(cbVar);
|
||||
voiceClientVatlib->changeRoomStatus(comUnit, upd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Room user received
|
||||
*/
|
||||
void CVoiceVatlib::onRoomUserReceived(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar)
|
||||
{
|
||||
Q_UNUSED(obj)
|
||||
|
||||
// sanity check
|
||||
QString callsign = QString(name);
|
||||
if (callsign.isEmpty()) return;
|
||||
|
||||
// add callsign
|
||||
CVoiceVatlib *voiceClientVatlib = cbvar_cast_voice(cbVar);
|
||||
ComUnit comUnit = static_cast<ComUnit>(voiceClientVatlib->temporaryUserRoomIndex());
|
||||
|
||||
// add user
|
||||
// callsign might contain: VATSIM id, user name
|
||||
if (callsign.contains(" "))
|
||||
{
|
||||
QStringList parts = callsign.split(" ");
|
||||
callsign = parts[0];
|
||||
// I throw away VATSIM id here, maybe we could use it
|
||||
}
|
||||
|
||||
voiceClientVatlib->addTemporaryCallsignForRoom(comUnit, CCallsign(callsign));
|
||||
CVoiceVatlib *vatlibRoom = cbvar_cast_voice(cbVar);
|
||||
vatlibRoom->onRoomStatusUpdate(roomIndex, upd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -718,33 +410,6 @@ namespace BlackCore
|
||||
cbvar_cast_voice(cbVar)->m_devices.push_back(outputDevice);
|
||||
}
|
||||
|
||||
/*
|
||||
* COM unit to Voice room
|
||||
*/
|
||||
CVoiceRoom CVoiceVatlib::voiceRoomForUnit(const IVoice::ComUnit comUnit) const
|
||||
{
|
||||
QReadLocker lockForReading(&m_lockVoiceRooms);
|
||||
return (comUnit == COM1) ? this->m_voiceRooms[0] : this->m_voiceRooms[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Voice room for respectice COM unit
|
||||
*/
|
||||
void CVoiceVatlib::setVoiceRoomForUnit(const IVoice::ComUnit comUnit, const CVoiceRoom &voiceRoom)
|
||||
{
|
||||
QWriteLocker lockForWriting(&m_lockVoiceRooms);
|
||||
this->m_voiceRooms[comUnit == COM1 ? 0 : 1] = voiceRoom;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add temp.callsign for room
|
||||
*/
|
||||
void CVoiceVatlib::addTemporaryCallsignForRoom(const ComUnit /** comUnit **/, const CCallsign &callsign)
|
||||
{
|
||||
if (m_temporaryVoiceRoomCallsigns.contains(callsign)) return;
|
||||
m_temporaryVoiceRoomCallsigns.push_back(callsign);
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward exception as signal
|
||||
*/
|
||||
@@ -783,26 +448,21 @@ namespace BlackCore
|
||||
}
|
||||
}
|
||||
|
||||
// Change voice room status and emit signal
|
||||
void CVoiceVatlib::changeConnectionStatus(ComUnit comUnit, ConnectionStatus newStatus)
|
||||
void CVoiceVatlib::onRoomStatusUpdate(qint32 roomIndex, Cvatlib_Voice_Simple::roomStatusUpdate roomStatus)
|
||||
{
|
||||
QWriteLocker lockForWriting(&m_lockConnectionStatus);
|
||||
ConnectionStatus currentStatus = m_connectionStatus.value(comUnit);
|
||||
if (newStatus != currentStatus)
|
||||
QList<IVoiceChannel *> voiceChannels = m_hashChannelIndex.values();
|
||||
auto iterator = std::find_if(voiceChannels.begin(), voiceChannels.end(), [&](const IVoiceChannel * voiceChannel)
|
||||
{
|
||||
if (newStatus == Connected)
|
||||
{
|
||||
CVoiceRoom vr = this->voiceRoomForUnit(comUnit);
|
||||
vr.setConnected(true);
|
||||
this->setVoiceRoomForUnit(comUnit, vr);
|
||||
}
|
||||
return voiceChannel->getRoomIndex() == roomIndex;
|
||||
});
|
||||
|
||||
// disconnecting the voice room will already be
|
||||
// set in leave voice room
|
||||
|
||||
m_connectionStatus.insert(comUnit, newStatus);
|
||||
emit connectionStatusChanged(comUnit, currentStatus, newStatus);
|
||||
if (iterator == voiceChannels.end())
|
||||
{
|
||||
qWarning() << "Unknown room index";
|
||||
return;
|
||||
}
|
||||
|
||||
(*iterator)->updateRoomStatus(roomStatus);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -101,40 +101,8 @@ namespace BlackCore
|
||||
//! \copydoc IVoice::micTestResultAsString
|
||||
virtual QString micTestResultAsString() const override;
|
||||
|
||||
public slots:
|
||||
//! \copydoc IVoice::setMyAircraftCallsign()
|
||||
virtual void setMyAircraftCallsign(const BlackMisc::Aviation::CCallsign &callsign) override;
|
||||
|
||||
//! \copydoc IVoice::joinVoiceRoom()
|
||||
virtual void joinVoiceRoom(const ComUnit comUnit, const BlackMisc::Audio::CVoiceRoom &voiceRoom) override;
|
||||
|
||||
//! \copydoc IVoice::leaveVoiceRoom()
|
||||
virtual void leaveVoiceRoom(const ComUnit comUnit) override;
|
||||
|
||||
//! \copydoc IVoice::leaveAllVoiceRooms()
|
||||
virtual void leaveAllVoiceRooms() override;
|
||||
|
||||
//! \copydoc IVoice::setRoomOutputVolume()
|
||||
virtual void setRoomOutputVolume(const ComUnit comUnit, const qint32 volumne) override;
|
||||
|
||||
//! \copydoc IVoice::startTransmitting()
|
||||
virtual void startTransmitting(const ComUnit comUnit) override;
|
||||
|
||||
//! \copydoc IVoice::stopTransmitting()
|
||||
virtual void stopTransmitting(const ComUnit comUnit) override;
|
||||
|
||||
//! \copydoc IVoice::getComVoiceRoomsWithAudioStatus()
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const override;
|
||||
|
||||
//! \copydoc IVoice::getComVoiceRooms()
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRooms() const override
|
||||
{
|
||||
QReadLocker lockForReading(&m_lockVoiceRooms);
|
||||
return this->m_voiceRooms;
|
||||
}
|
||||
|
||||
//! \copydoc IVoice::getVoiceRoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getVoiceRoomCallsigns(const ComUnit comUnit) const override;
|
||||
//! \copydoc IVoice::getVoiceChannel
|
||||
virtual IVoiceChannel *getVoiceChannel(qint32 channelIndex) const override;
|
||||
|
||||
//! \copydoc IVoice::setInputDevice
|
||||
virtual void setInputDevice(const BlackMisc::Audio::CAudioDevice &device) override;
|
||||
@@ -148,58 +116,15 @@ namespace BlackCore
|
||||
//! \copydoc IVoice::getCurrentOutputDevice()
|
||||
virtual BlackMisc::Audio::CAudioDevice getCurrentOutputDevice() const override;
|
||||
|
||||
//! \copydoc IVoice::switchAudioOutput
|
||||
virtual void switchAudioOutput(const ComUnit comUnit, bool enable) override;
|
||||
|
||||
//! \copydoc IVoice::enableAudioLoopback
|
||||
virtual void enableAudioLoopback(bool enable = true) override;
|
||||
|
||||
//! \copydoc IVoice::isMuted
|
||||
virtual bool isMuted() const override
|
||||
{
|
||||
QReadLocker lockForReading(&m_lockOutputEnabled);
|
||||
if (this->m_outputEnabled.isEmpty()) return false;
|
||||
bool enabled = this->m_outputEnabled[COM1] || this->m_outputEnabled[COM2];
|
||||
return !enabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Starts or stops voice transmission
|
||||
* \param value
|
||||
*/
|
||||
void handlePushToTalk(bool value = false);
|
||||
|
||||
/************************************************
|
||||
* NON API METHODS:
|
||||
* The following methods are not part of the
|
||||
* public API. They are needed for internal
|
||||
* workflow.
|
||||
* *********************************************/
|
||||
|
||||
/*!
|
||||
* \brief Voice room index
|
||||
* \return
|
||||
*/
|
||||
qint32 temporaryUserRoomIndex() const
|
||||
{
|
||||
return m_temporaryUserRoomIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Room status update, used in callback
|
||||
* \param comUnit
|
||||
* \param roomStatus
|
||||
*/
|
||||
void changeRoomStatus(ComUnit comUnit, Cvatlib_Voice_Simple::roomStatusUpdate roomStatus);
|
||||
|
||||
signals:
|
||||
|
||||
/*!
|
||||
* \brief User joined or left
|
||||
* \param comUnit
|
||||
*/
|
||||
void userJoinedLeft(const ComUnit comUnit);
|
||||
|
||||
protected: // QObject overrides
|
||||
|
||||
/*!
|
||||
@@ -212,48 +137,25 @@ namespace BlackCore
|
||||
void onEndFindSquelch();
|
||||
void onEndMicTest();
|
||||
|
||||
/*!
|
||||
* \brief User (identified by callsign) joined or left voice room
|
||||
*/
|
||||
void onUserJoinedLeft(const ComUnit comUnit);
|
||||
|
||||
private:
|
||||
|
||||
// shimlib callbacks
|
||||
static void onRoomStatusUpdate(Cvatlib_Voice_Simple *obj, Cvatlib_Voice_Simple::roomStatusUpdate upd, qint32 roomIndex, void *cbVar);
|
||||
static void onRoomUserReceived(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar);
|
||||
static void onInputHardwareDeviceReceived(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar);
|
||||
static void onOutputHardwareDeviceReceived(Cvatlib_Voice_Simple *obj, const char *name, void *cbVar);
|
||||
|
||||
BlackMisc::Audio::CVoiceRoom voiceRoomForUnit(const ComUnit comUnit) const;
|
||||
void setVoiceRoomForUnit(const IVoice::ComUnit comUnit, const BlackMisc::Audio::CVoiceRoom &voiceRoom);
|
||||
void addTemporaryCallsignForRoom(const ComUnit comUnit, const BlackMisc::Aviation::CCallsign &callsign);
|
||||
void removeUserFromRoom(const ComUnit comUnit, const QString &callsign);
|
||||
void exceptionDispatcher(const char *caller);
|
||||
void enableAudio(const ComUnit comUnit);
|
||||
void changeConnectionStatus(ComUnit comUnit, ConnectionStatus newStatus);
|
||||
void onRoomStatusUpdate(qint32 roomIndex, Cvatlib_Voice_Simple::roomStatusUpdate roomStatus);
|
||||
|
||||
TVatlibPointer m_vatlib;
|
||||
// QScopedPointer<QAudioOutput> m_audioOutput; #227
|
||||
BlackMisc::Aviation::CCallsign m_aircraftCallsign; /*!< own callsign to join voice rooms */
|
||||
BlackMisc::Audio::CVoiceRoomList m_voiceRooms;
|
||||
BlackMisc::Audio::CAudioDeviceList m_devices; /*!< in and output devices */
|
||||
BlackMisc::Audio::CAudioDevice m_currentOutputDevice;
|
||||
BlackMisc::Audio::CAudioDevice m_currentInputDevice;
|
||||
std::atomic<float> m_inputSquelch;
|
||||
std::atomic<Cvatlib_Voice_Simple::agc> m_micTestResult;
|
||||
QMap <ComUnit, BlackMisc::Aviation::CCallsignList> m_voiceRoomCallsigns; /*!< voice room callsigns */
|
||||
BlackMisc::Aviation::CCallsignList m_temporaryVoiceRoomCallsigns; /*!< temp. storage of voice rooms during update */
|
||||
QMap<ComUnit, bool> m_outputEnabled; /*!< output enabled, basically a mute flag */
|
||||
QMap<ComUnit, ConnectionStatus> m_connectionStatus; /*!< holds connection status for each com unit */
|
||||
QHash<qint32, IVoiceChannel *> m_hashChannelIndex;
|
||||
bool m_isAudioLoopbackEnabled; /*!< A flag whether audio loopback is enabled or not */
|
||||
|
||||
// Need to keep the roomIndex?
|
||||
// KB: I would remove this approach, it is potentially unsafe
|
||||
// Maybe just use 2 "wrapper" callbacks, which then set explicitly the voice room (it is only 2 methods)
|
||||
qint32 m_temporaryUserRoomIndex; /*!< temp. storage of voice room, in order to retrieve it in static callback */
|
||||
const static qint32 InvalidRoomIndex = -1; /*! marks invalid room */
|
||||
|
||||
// Thread serialization
|
||||
mutable QMutex m_lockCurrentOutputDevice;
|
||||
mutable QMutex m_lockCurrentInputDevice;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/* Copyright (C) 2013 VATSIM Community / authors
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "voice_vatlib.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace BlackMisc::Audio;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
/*
|
||||
* Handle PTT
|
||||
*/
|
||||
void CVoiceVatlib::handlePushToTalk(bool value)
|
||||
{
|
||||
qDebug() << "PTT";
|
||||
if (!this->m_voice) return;
|
||||
CVoiceRoomList rooms = this->getComVoiceRoomsWithAudioStatus();
|
||||
CVoiceRoom room1 = rooms[0];
|
||||
CVoiceRoom room2 = rooms[1];
|
||||
|
||||
if (value) qDebug() << "Start transmitting...";
|
||||
else qDebug() << "Stop transmitting...";
|
||||
|
||||
if (room1.isConnected())
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
this->startTransmitting(IVoice::COM1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->stopTransmitting(IVoice::COM1);
|
||||
}
|
||||
}
|
||||
if (room2.isConnected())
|
||||
{
|
||||
if (value)
|
||||
this->startTransmitting(IVoice::COM2);
|
||||
else
|
||||
this->stopTransmitting(IVoice::COM2);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user