mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 17:35:34 +08:00
refs #372 Move voice channel sharing into CContextAudio
Before a very complex mechanism was implemented in order to share a vatlib voice channel resource if more than one COM unit was connected to the same channel. This is now moved into CContextAudio by mapping a COM unit to a shared voice channel pointer.
This commit is contained in:
committed by
Klaus Basan
parent
33dddf795e
commit
84ac5e9972
@@ -47,6 +47,14 @@ namespace BlackCore
|
||||
IContextAudio(CRuntimeConfig::ContextMode mode, CRuntime *runtime) : CContext(mode, runtime) {}
|
||||
|
||||
public:
|
||||
|
||||
//! ComUnit number
|
||||
enum ComUnit
|
||||
{
|
||||
Com1,
|
||||
Com2
|
||||
};
|
||||
|
||||
//! \brief Interface name
|
||||
static const QString &InterfaceName()
|
||||
{
|
||||
@@ -101,19 +109,8 @@ namespace BlackCore
|
||||
//! Get voice rooms for COM1, COM2, but without latest audio status
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRooms() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief COM 1 voice room
|
||||
* \param withAudioStatus update audio status
|
||||
* \return
|
||||
*/
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom1VoiceRoom(bool withAudioStatus) const = 0;
|
||||
|
||||
/*!
|
||||
* \brief COM 2 voice room
|
||||
* \param withAudioStatus update audio status
|
||||
* \return
|
||||
*/
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom2VoiceRoom(bool withAudioStatus) const = 0;
|
||||
//! Get voice room per com unit
|
||||
virtual BlackMisc::Audio::CVoiceRoom getVoiceRoom(int comUnit, bool withAudioStatus) const = 0;
|
||||
|
||||
//! Set voice rooms
|
||||
virtual void setComVoiceRooms(const BlackMisc::Audio::CVoiceRoomList &voiceRooms) = 0;
|
||||
@@ -121,17 +118,11 @@ namespace BlackCore
|
||||
//! Leave all voice rooms
|
||||
virtual void leaveAllVoiceRooms() = 0;
|
||||
|
||||
//! COM1 room users callsigns
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom1RoomCallsigns() const = 0;
|
||||
//! Room user callsigns
|
||||
virtual BlackMisc::Aviation::CCallsignList getRoomCallsigns(int comUnit) const = 0;
|
||||
|
||||
//! COM2 room users callsigns
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom2RoomCallsigns() const = 0;
|
||||
|
||||
//! COM1 room users
|
||||
virtual BlackMisc::Network::CUserList getCom1RoomUsers() const = 0;
|
||||
|
||||
//! COM2 room users
|
||||
virtual BlackMisc::Network::CUserList getCom2RoomUsers() const = 0;
|
||||
//! Room users
|
||||
virtual BlackMisc::Network::CUserList getRoomUsers(int comUnit) const = 0;
|
||||
|
||||
//! Audio devices
|
||||
virtual BlackMisc::Audio::CAudioDeviceInfoList getAudioDevices() const = 0;
|
||||
|
||||
@@ -41,12 +41,12 @@ namespace BlackCore
|
||||
m_inputManager = CInputManager::getInstance();
|
||||
m_handlePtt = m_inputManager->registerHotkeyFunc(CHotkeyFunction::Ptt(), this, &CContextAudio::ps_setVoiceTransmission);
|
||||
|
||||
m_channelCom1 = m_voice->createVoiceChannel();
|
||||
m_channelCom1->setMyAircraftCallsign(getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
connect(m_channelCom1.get(), &IVoiceChannel::connectionStatusChanged, this, &CContextAudio::ps_com1ConnectionStatusChanged);
|
||||
m_channelCom2 = m_voice->createVoiceChannel();
|
||||
m_channelCom2->setMyAircraftCallsign(getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
connect(m_channelCom2.get(), &IVoiceChannel::connectionStatusChanged, this, &CContextAudio::ps_com2ConnectionStatusChanged);
|
||||
m_channel1 = m_voice->createVoiceChannel();
|
||||
m_channel1->setMyAircraftCallsign(getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
connect(m_channel1.data(), &IVoiceChannel::connectionStatusChanged, this, &CContextAudio::ps_connectionStatusChanged);
|
||||
m_channel2 = m_voice->createVoiceChannel();
|
||||
m_channel2->setMyAircraftCallsign(getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
connect(m_channel2.data(), &IVoiceChannel::connectionStatusChanged, this, &CContextAudio::ps_connectionStatusChanged);
|
||||
|
||||
m_voiceInputDevice = m_voice->createInputDevice();
|
||||
m_voiceOutputDevice = m_voice->createOutputDevice();
|
||||
@@ -54,17 +54,20 @@ namespace BlackCore
|
||||
m_audioMixer = m_voice->createAudioMixer();
|
||||
|
||||
m_voice->connectVoice(m_voiceInputDevice.get(), m_audioMixer.get(), IAudioMixer::InputMicrophone);
|
||||
m_voice->connectVoice(m_channelCom1.get(), m_audioMixer.get(), IAudioMixer::InputVoiceChannel1);
|
||||
m_voice->connectVoice(m_channelCom2.get(), m_audioMixer.get(), IAudioMixer::InputVoiceChannel2);
|
||||
m_voice->connectVoice(m_channel1.data(), m_audioMixer.get(), IAudioMixer::InputVoiceChannel1);
|
||||
m_voice->connectVoice(m_channel2.data(), m_audioMixer.get(), IAudioMixer::InputVoiceChannel2);
|
||||
m_voice->connectVoice(m_audioMixer.get(), IAudioMixer::OutputOutputDevice1, m_voiceOutputDevice.get());
|
||||
m_voice->connectVoice(m_audioMixer.get(), IAudioMixer::OutputVoiceChannel1, m_channelCom1.get());
|
||||
m_voice->connectVoice(m_audioMixer.get(), IAudioMixer::OutputVoiceChannel2, m_channelCom2.get());
|
||||
m_voice->connectVoice(m_audioMixer.get(), IAudioMixer::OutputVoiceChannel1, m_channel1.data());
|
||||
m_voice->connectVoice(m_audioMixer.get(), IAudioMixer::OutputVoiceChannel2, m_channel2.data());
|
||||
|
||||
m_audioMixer->makeMixerConnection(IAudioMixer::InputVoiceChannel1, IAudioMixer::OutputOutputDevice1);
|
||||
m_audioMixer->makeMixerConnection(IAudioMixer::InputVoiceChannel2, IAudioMixer::OutputOutputDevice1);
|
||||
|
||||
// 4. load sounds (init), not possible in own thread
|
||||
QTimer::singleShot(10 * 1000, this, SLOT(ps_initNotificationSounds()));
|
||||
|
||||
m_unusedVoiceChannels.push_back(m_channel1);
|
||||
m_unusedVoiceChannels.push_back(m_channel2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -88,23 +91,17 @@ namespace BlackCore
|
||||
/*
|
||||
* Voice rooms for COM
|
||||
*/
|
||||
CVoiceRoom CContextAudio::getCom1VoiceRoom(bool withAudioStatus) const
|
||||
CVoiceRoom CContextAudio::getVoiceRoom(int comUnitValue, bool withAudioStatus) const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << withAudioStatus;
|
||||
// We always have the audio status due to shared status
|
||||
return m_channelCom1->getVoiceRoom();
|
||||
}
|
||||
|
||||
/*
|
||||
* Voice rooms for COM
|
||||
*/
|
||||
CVoiceRoom CContextAudio::getCom2VoiceRoom(bool withAudioStatus) const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << withAudioStatus;
|
||||
// We always have the audio status due to shared status
|
||||
return m_channelCom2->getVoiceRoom();
|
||||
auto voiceChannel = m_voiceChannelMapping.value(static_cast<ComUnit>(comUnitValue));
|
||||
|
||||
if (voiceChannel)
|
||||
return voiceChannel->getVoiceRoom();
|
||||
else
|
||||
return CVoiceRoom();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -115,8 +112,29 @@ namespace BlackCore
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
CVoiceRoomList voiceRoomList;
|
||||
voiceRoomList.push_back(m_channelCom1->getVoiceRoom());
|
||||
voiceRoomList.push_back(m_channelCom2->getVoiceRoom());
|
||||
|
||||
auto voiceChannelCom1 = m_voiceChannelMapping.value(Com1);
|
||||
if (voiceChannelCom1)
|
||||
{
|
||||
CVoiceRoom room = voiceChannelCom1->getVoiceRoom();
|
||||
voiceRoomList.push_back(room);
|
||||
}
|
||||
else
|
||||
{
|
||||
voiceRoomList.push_back(CVoiceRoom());
|
||||
}
|
||||
|
||||
auto voiceChannelCom2 = m_voiceChannelMapping.value(Com2);
|
||||
if (voiceChannelCom2)
|
||||
{
|
||||
CVoiceRoom room = voiceChannelCom2->getVoiceRoom();
|
||||
voiceRoomList.push_back(room);
|
||||
}
|
||||
else
|
||||
{
|
||||
voiceRoomList.push_back(CVoiceRoom());
|
||||
}
|
||||
|
||||
return voiceRoomList;
|
||||
}
|
||||
|
||||
@@ -127,8 +145,11 @@ namespace BlackCore
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
m_channelCom1->leaveVoiceRoom();
|
||||
m_channelCom2->leaveVoiceRoom();
|
||||
m_voiceChannelMapping.clear();
|
||||
m_channel1->leaveVoiceRoom();
|
||||
m_channel2->leaveVoiceRoom();
|
||||
m_unusedVoiceChannels.push_back(m_channel1);
|
||||
m_unusedVoiceChannels.push_back(m_channel2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -204,9 +225,9 @@ namespace BlackCore
|
||||
|
||||
void CContextAudio::setVolumes(int com1Volume, int com2Volume)
|
||||
{
|
||||
//! \todo Fix when VATLIB 2.0 is available
|
||||
int channelV1 = static_cast<int>(m_channelCom1->getVolume());
|
||||
int channelV2 = static_cast<int>(m_channelCom2->getVolume());
|
||||
//! \todo Will be removed as part of #371.
|
||||
int channelV1 = static_cast<int>(m_channel1->getVolume());
|
||||
int channelV2 = static_cast<int>(m_channel2->getVolume());
|
||||
if (channelV1 == com1Volume && channelV2 == com2Volume) { return; }
|
||||
|
||||
bool enable1 = com1Volume > 0;
|
||||
@@ -214,8 +235,8 @@ namespace BlackCore
|
||||
bool muted = !enable1 && !enable2;
|
||||
|
||||
//! \todo m_channelCom1->setVolume here crashed, also what is correct setRoomOutputVolume or setVolume
|
||||
m_channelCom1->setVolume(com1Volume);
|
||||
m_channelCom2->setVolume(com2Volume);
|
||||
m_channel1->setVolume(com1Volume);
|
||||
m_channel2->setVolume(com2Volume);
|
||||
this->setMute(muted);
|
||||
|
||||
emit changedAudioVolumes(com1Volume, com2Volume);
|
||||
@@ -257,29 +278,86 @@ namespace BlackCore
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << newRooms;
|
||||
|
||||
CVoiceRoomList currentRooms = getComVoiceRooms();
|
||||
CVoiceRoom currentRoom1 = currentRooms[0];
|
||||
CVoiceRoom currentRoom2 = currentRooms[1];
|
||||
CVoiceRoom newRoom1 = newRooms[0];
|
||||
CVoiceRoom newRoom2 = newRooms[1];
|
||||
CVoiceRoom currentRoomCom1 = currentRooms[0];
|
||||
CVoiceRoom currentRoomCom2 = currentRooms[1];
|
||||
CVoiceRoom newRoomCom1 = newRooms[0];
|
||||
CVoiceRoom newRoomCom2 = newRooms[1];
|
||||
|
||||
bool changed = false;
|
||||
|
||||
// changed rooms? But only compare on "URL", not status as connected etc.
|
||||
if (currentRoom1.getVoiceRoomUrl() != newRoom1.getVoiceRoomUrl())
|
||||
if (currentRoomCom1.getVoiceRoomUrl() != newRoomCom1.getVoiceRoomUrl())
|
||||
{
|
||||
m_channelCom1->leaveVoiceRoom();
|
||||
if (newRoom1.isValid())
|
||||
auto oldVoiceChannel = m_voiceChannelMapping.value(Com1);
|
||||
if (oldVoiceChannel)
|
||||
{
|
||||
m_channelCom1->joinVoiceRoom(newRoom1);
|
||||
m_voiceChannelMapping.remove(Com1);
|
||||
|
||||
// If the voice channel is not used by anybody else
|
||||
if (!m_voiceChannelMapping.values().contains(oldVoiceChannel))
|
||||
{
|
||||
oldVoiceChannel->leaveVoiceRoom();
|
||||
m_unusedVoiceChannels.push_back(oldVoiceChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (newRoomCom1.isValid())
|
||||
{
|
||||
auto newVoiceChannel = getVoiceChannelBy(newRoomCom1);
|
||||
bool inUse = m_voiceChannelMapping.values().contains(newVoiceChannel);
|
||||
m_voiceChannelMapping.insert(Com1, newVoiceChannel);
|
||||
|
||||
// If the voice channel is not used by anybody else
|
||||
if (!inUse)
|
||||
{
|
||||
newVoiceChannel->joinVoiceRoom(newRoomCom1);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), true);
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (currentRoom2.getVoiceRoomUrl() != newRoom2.getVoiceRoomUrl())
|
||||
// changed rooms? But only compare on "URL", not status as connected etc.
|
||||
if (currentRoomCom2.getVoiceRoomUrl() != newRoomCom2.getVoiceRoomUrl())
|
||||
{
|
||||
m_channelCom2->leaveVoiceRoom();
|
||||
if (newRoom2.isValid())
|
||||
auto oldVoiceChannel = m_voiceChannelMapping.value(Com2);
|
||||
if (oldVoiceChannel)
|
||||
{
|
||||
m_channelCom2->joinVoiceRoom(newRoom2);
|
||||
m_voiceChannelMapping.remove(Com2);
|
||||
|
||||
// If the voice channel is not used by anybody else
|
||||
if (!m_voiceChannelMapping.values().contains(oldVoiceChannel))
|
||||
{
|
||||
oldVoiceChannel->leaveVoiceRoom();
|
||||
m_unusedVoiceChannels.push_back(oldVoiceChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (newRoomCom2.isValid())
|
||||
{
|
||||
auto newVoiceChannel = getVoiceChannelBy(newRoomCom2);
|
||||
bool inUse = m_voiceChannelMapping.values().contains(newVoiceChannel);
|
||||
m_voiceChannelMapping.insert(Com2, newVoiceChannel);
|
||||
|
||||
// If the voice channel is not used by anybody else
|
||||
if (!inUse)
|
||||
{
|
||||
newVoiceChannel->joinVoiceRoom(newRoomCom2);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), true);
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
@@ -289,48 +367,27 @@ namespace BlackCore
|
||||
Q_UNUSED(changed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Room 1 callsigns
|
||||
*/
|
||||
CCallsignList CContextAudio::getCom1RoomCallsigns() const
|
||||
CCallsignList CContextAudio::getRoomCallsigns(int comUnitValue) const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
return m_channelCom1->getVoiceRoomCallsigns();
|
||||
|
||||
auto voiceChannel = m_voiceChannelMapping.value(static_cast<ComUnit>(comUnitValue));
|
||||
if (voiceChannel)
|
||||
return voiceChannel->getVoiceRoomCallsigns();
|
||||
else
|
||||
return CCallsignList();
|
||||
}
|
||||
|
||||
/*
|
||||
* Room 2 callsigns
|
||||
*/
|
||||
CCallsignList CContextAudio::getCom2RoomCallsigns() const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
return m_channelCom2->getVoiceRoomCallsigns();
|
||||
}
|
||||
|
||||
/*
|
||||
* Room 1 users
|
||||
*/
|
||||
Network::CUserList CContextAudio::getCom1RoomUsers() const
|
||||
Network::CUserList CContextAudio::getRoomUsers(int comUnitValue) const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
Q_ASSERT(this->getRuntime());
|
||||
if (!this->getRuntime()->getIContextNetwork()) return Network::CUserList();
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
return this->getIContextNetwork()->getUsersForCallsigns(this->getCom1RoomCallsigns());
|
||||
}
|
||||
|
||||
/*
|
||||
* Room 2 users
|
||||
*/
|
||||
Network::CUserList CContextAudio::getCom2RoomUsers() const
|
||||
{
|
||||
Q_ASSERT(this->m_voice);
|
||||
Q_ASSERT(this->getRuntime());
|
||||
if (!this->getRuntime()->getIContextNetwork()) return Network::CUserList();
|
||||
CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO;
|
||||
return this->getIContextNetwork()->getUsersForCallsigns(this->getCom2RoomCallsigns());
|
||||
auto comUnit = static_cast<ComUnit>(comUnitValue);
|
||||
return this->getIContextNetwork()->getUsersForCallsigns(this->getRoomCallsigns(comUnit));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -449,20 +506,7 @@ namespace BlackCore
|
||||
qint32 v = parser.toInt(1);
|
||||
if (v >= 0 && v <= 100)
|
||||
{
|
||||
qint32 v1 = this->m_channelCom1->getVolume();
|
||||
qint32 v2 = this->m_channelCom2->getVolume();
|
||||
if (parser.commandEndsWith("1"))
|
||||
{
|
||||
this->setVolumes(v, v2);
|
||||
}
|
||||
else if (parser.commandEndsWith("2"))
|
||||
{
|
||||
this->setVolumes(v1, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setVolumes(v, v);
|
||||
}
|
||||
// TODO: vatlib volume
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -478,7 +522,7 @@ namespace BlackCore
|
||||
/*
|
||||
* Connection status changed
|
||||
*/
|
||||
void CContextAudio::ps_com1ConnectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus)
|
||||
void CContextAudio::ps_connectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus)
|
||||
{
|
||||
Q_UNUSED(oldStatus);
|
||||
|
||||
@@ -499,8 +543,8 @@ namespace BlackCore
|
||||
if (this->getIContextOwnAircraft())
|
||||
{
|
||||
// good chance to update aircraft
|
||||
m_channelCom1->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
m_channelCom2->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
m_channel1->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
m_channel2->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
}
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), false);
|
||||
break;
|
||||
@@ -509,35 +553,22 @@ namespace BlackCore
|
||||
}
|
||||
}
|
||||
|
||||
void CContextAudio::ps_com2ConnectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus)
|
||||
QSharedPointer<IVoiceChannel> CContextAudio::getVoiceChannelBy(const CVoiceRoom &voiceRoom)
|
||||
{
|
||||
Q_UNUSED(oldStatus);
|
||||
|
||||
switch (newStatus)
|
||||
QSharedPointer<IVoiceChannel> voiceChannel;
|
||||
for (const auto &channel : m_voiceChannelMapping.values())
|
||||
{
|
||||
case IVoiceChannel::Connected:
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), true);
|
||||
break;
|
||||
case IVoiceChannel::Disconnecting:
|
||||
break;
|
||||
case IVoiceChannel::Connecting:
|
||||
break;
|
||||
case IVoiceChannel::ConnectingFailed:
|
||||
case IVoiceChannel::DisconnectedError:
|
||||
qWarning() << "Voice room COM2 error";
|
||||
// intentional fall-through
|
||||
case IVoiceChannel::Disconnected:
|
||||
if (this->getIContextOwnAircraft())
|
||||
{
|
||||
// good chance to update aircraft
|
||||
m_channelCom1->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
m_channelCom2->setMyAircraftCallsign(this->getIContextOwnAircraft()->getOwnAircraft().getCallsign());
|
||||
}
|
||||
emit this->changedVoiceRooms(getComVoiceRooms(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (channel->getVoiceRoom().getVoiceRoomUrl() == voiceRoom.getVoiceRoomUrl()) voiceChannel = channel;
|
||||
}
|
||||
|
||||
// If we haven't found a valid voice channel pointer, get an unused one
|
||||
if (!voiceChannel)
|
||||
{
|
||||
Q_ASSERT(!m_unusedVoiceChannels.isEmpty());
|
||||
voiceChannel = m_unusedVoiceChannels.takeFirst();
|
||||
}
|
||||
|
||||
return voiceChannel;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -54,26 +54,17 @@ namespace BlackCore
|
||||
//! \copydoc IContextAudio::getComVoiceRoomsWithAudioStatus()
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1VoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom1VoiceRoom(bool withAudioStatus) const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2VoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom2VoiceRoom(bool withAudioStatus) const override;
|
||||
//! \copydoc IContextAudio::getVoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getVoiceRoom(int comUnitValue, bool withAudioStatus) const override;
|
||||
|
||||
//! \copydoc IContextAudio::setComVoiceRooms
|
||||
virtual void setComVoiceRooms(const BlackMisc::Audio::CVoiceRoomList &newRooms) override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1RoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom1RoomCallsigns() const override;
|
||||
//! \copydoc IContextAudio::getRoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getRoomCallsigns(int comUnitValue) const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2RoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom2RoomCallsigns() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1RoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getCom1RoomUsers() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2RoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getCom2RoomUsers() const override;
|
||||
//! \copydoc IContextAudio::getRoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getRoomUsers(int comUnitValue) const override;
|
||||
|
||||
//! \copydoc IContextAudio::leaveAllVoiceRooms
|
||||
virtual void leaveAllVoiceRooms() override;
|
||||
@@ -149,11 +140,7 @@ namespace BlackCore
|
||||
|
||||
//! \copydoc IVoice::connectionStatusChanged
|
||||
//! \sa IContextAudio::changedVoiceRooms
|
||||
void ps_com1ConnectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus);
|
||||
|
||||
//! \copydoc IVoice::connectionStatusChanged
|
||||
//! \sa IContextAudio::changedVoiceRooms
|
||||
void ps_com2ConnectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus);
|
||||
void ps_connectionStatusChanged(IVoiceChannel::ConnectionStatus oldStatus, IVoiceChannel::ConnectionStatus newStatus);
|
||||
|
||||
//! Init notification sounds
|
||||
void ps_initNotificationSounds();
|
||||
@@ -161,12 +148,15 @@ namespace BlackCore
|
||||
void ps_setVoiceTransmission(bool enable);
|
||||
|
||||
private:
|
||||
|
||||
const int MinUnmuteVolume = 20; //!< minimum volume when unmuted
|
||||
const int VoiceRoomEnabledVolume = 95; //!< voice room volume when enabled
|
||||
|
||||
//! Connection in transition
|
||||
bool inTransitionState() const;
|
||||
|
||||
QSharedPointer<IVoiceChannel> getVoiceChannelBy(const BlackMisc::Audio::CVoiceRoom &voiceRoom);
|
||||
|
||||
CInputManager *m_inputManager = nullptr;
|
||||
CInputManager::RegistrationHandle m_handlePtt;
|
||||
|
||||
@@ -174,12 +164,15 @@ namespace BlackCore
|
||||
std::unique_ptr<IAudioMixer> m_audioMixer;
|
||||
|
||||
int m_outDeviceVolume = 100;
|
||||
std::unique_ptr<IVoiceChannel> m_channelCom1;
|
||||
std::unique_ptr<IVoiceChannel> m_channelCom2;
|
||||
|
||||
// For easy access.
|
||||
QSharedPointer<IVoiceChannel> m_channel1;
|
||||
QSharedPointer<IVoiceChannel> m_channel2;
|
||||
std::unique_ptr<IAudioOutputDevice> m_voiceOutputDevice;
|
||||
std::unique_ptr<IAudioInputDevice> m_voiceInputDevice;
|
||||
|
||||
|
||||
QList<QSharedPointer<IVoiceChannel>> m_unusedVoiceChannels;
|
||||
QHash<ComUnit, QSharedPointer<IVoiceChannel>> m_voiceChannelMapping;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -64,33 +64,17 @@ namespace BlackCore
|
||||
/*
|
||||
* COM1 callsigns
|
||||
*/
|
||||
BlackMisc::Aviation::CCallsignList CContextAudioProxy::getCom1RoomCallsigns() const
|
||||
BlackMisc::Aviation::CCallsignList CContextAudioProxy::getRoomCallsigns(int comUnitValue) const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CCallsignList>(QLatin1Literal("getCom1RoomCallsigns"));
|
||||
}
|
||||
|
||||
/*
|
||||
* COM2 callsigns
|
||||
*/
|
||||
BlackMisc::Aviation::CCallsignList CContextAudioProxy::getCom2RoomCallsigns() const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CCallsignList>(QLatin1Literal("getCom2RoomCallsigns"));
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CCallsignList>(QLatin1Literal("getRoomCallsigns"), comUnitValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* COM1 users
|
||||
*/
|
||||
BlackMisc::Network::CUserList CContextAudioProxy::getCom1RoomUsers() const
|
||||
BlackMisc::Network::CUserList CContextAudioProxy::getRoomUsers(int comUnitValue) const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Network::CUserList>(QLatin1Literal("getCom1RoomUsers"));
|
||||
}
|
||||
|
||||
/*
|
||||
* COM2 users
|
||||
*/
|
||||
BlackMisc::Network::CUserList CContextAudioProxy::getCom2RoomUsers() const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Network::CUserList>(QLatin1Literal("getCom2RoomUsers"));
|
||||
return this->m_dBusInterface->callDBusRet<BlackMisc::Network::CUserList>(QLatin1Literal("getRoomUsers"), comUnitValue);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -136,17 +120,9 @@ namespace BlackCore
|
||||
/*
|
||||
* Voice room
|
||||
*/
|
||||
CVoiceRoom CContextAudioProxy::getCom1VoiceRoom(bool withAudioStatus) const
|
||||
CVoiceRoom CContextAudioProxy::getVoiceRoom(int comUnitValue, bool withAudioStatus) const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<CVoiceRoom>(QLatin1Literal("getCom1VoiceRoom"), withAudioStatus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Voice room
|
||||
*/
|
||||
CVoiceRoom CContextAudioProxy::getCom2VoiceRoom(bool withAudioStatus) const
|
||||
{
|
||||
return this->m_dBusInterface->callDBusRet<CVoiceRoom>(QLatin1Literal("getCom2VoiceRoom"), withAudioStatus);
|
||||
return this->m_dBusInterface->callDBusRet<CVoiceRoom>(QLatin1Literal("getVoiceRoom"), comUnitValue, withAudioStatus);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -57,26 +57,17 @@ namespace BlackCore
|
||||
//! \copydoc IContextAudio::getComVoiceRoomsWithAudioStatus()
|
||||
virtual BlackMisc::Audio::CVoiceRoomList getComVoiceRoomsWithAudioStatus() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1VoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom1VoiceRoom(bool withAudioStatus) const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2VoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getCom2VoiceRoom(bool withAudioStatus) const override;
|
||||
//! \copydoc IContextAudio::getVoiceRoom
|
||||
virtual BlackMisc::Audio::CVoiceRoom getVoiceRoom(int comUnitValue, bool withAudioStatus) const override;
|
||||
|
||||
//! \copydoc IContextAudio::setComVoiceRooms()
|
||||
virtual void setComVoiceRooms(const BlackMisc::Audio::CVoiceRoomList &voiceRooms) override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1RoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom1RoomCallsigns() const override;
|
||||
//! \copydoc IContextAudio::getRoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getRoomCallsigns(int comUnitValue) const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2RoomCallsigns()
|
||||
virtual BlackMisc::Aviation::CCallsignList getCom2RoomCallsigns() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom1RoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getCom1RoomUsers() const override;
|
||||
|
||||
//! \copydoc IContextAudio::getCom2RoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getCom2RoomUsers() const override;
|
||||
//! \copydoc IContextAudio::getRoomUsers()
|
||||
virtual BlackMisc::Network::CUserList getRoomUsers(int comUnitValue) const override;
|
||||
|
||||
//! \copydoc IContextAudio::leaveAllVoiceRooms
|
||||
virtual void leaveAllVoiceRooms() override;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "../blackmisc/statusmessage.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -40,7 +41,7 @@ namespace BlackCore
|
||||
virtual ~IVoice() {}
|
||||
|
||||
//! Create voice channel object
|
||||
virtual std::unique_ptr<IVoiceChannel> createVoiceChannel() = 0;
|
||||
virtual QSharedPointer<IVoiceChannel> createVoiceChannel() = 0;
|
||||
|
||||
//! Create input device object
|
||||
virtual std::unique_ptr<IAudioInputDevice> createInputDevice() = 0;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include "voice_channel_vatlib.h"
|
||||
#include "voice_channel_vatlib_p.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
|
||||
#include <mutex>
|
||||
@@ -19,42 +18,128 @@ using namespace BlackMisc::Aviation;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
// Room data hash shared between all CVoiceChannel objects
|
||||
QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> CVoiceChannelVatlibPrivate::m_sharedRoomData;
|
||||
|
||||
// Constructor
|
||||
// Don't set the QObject parent. It will conflict with @QSharedPointer@ memory management
|
||||
CVoiceChannelVatlibPrivate::CVoiceChannelVatlibPrivate(VatAudioService audioService, VatUDPAudioPort udpPort, CVoiceChannelVatlib *parent)
|
||||
: m_audioService(audioService),
|
||||
m_udpPort(udpPort),
|
||||
q_ptr(parent)
|
||||
CVoiceChannelVatlib::CVoiceChannelVatlib(VatAudioService audioService, VatUDPAudioPort udpPort, QObject *parent)
|
||||
: IVoiceChannel(parent),
|
||||
m_audioService(audioService),
|
||||
m_udpPort(udpPort)
|
||||
{
|
||||
Q_ASSERT(m_audioService);
|
||||
Q_ASSERT(m_udpPort);
|
||||
|
||||
m_connectionRefCount = 0;
|
||||
m_roomStatus = IVoiceChannel::Disconnected;
|
||||
|
||||
m_voiceChannels.push_back(parent);
|
||||
|
||||
m_voiceChannel.reset(Vat_CreateVoiceChannel(m_audioService, "", 3782, "", "", m_udpPort));
|
||||
Vat_SetConnectionChangedHandler(m_voiceChannel.data(), onRoomStatusUpdate, this);
|
||||
Vat_SetConnectionChangedHandler(m_voiceChannel.data(), roomStatusUpdate, this);
|
||||
Vat_SetClientJoinedHandler(m_voiceChannel.data(), processUserJoined, this);
|
||||
Vat_SetClientLeftHandler(m_voiceChannel.data(), processUserLeft, this);
|
||||
Vat_SetVoiceTransmissionChangedHandler(m_voiceChannel.data(), processTransmissionChange, this);
|
||||
|
||||
}
|
||||
|
||||
CVoiceChannelVatlibPrivate::~CVoiceChannelVatlibPrivate()
|
||||
CVoiceChannelVatlib::~CVoiceChannelVatlib()
|
||||
{
|
||||
Q_ASSERT(m_roomStatus == IVoiceChannel::Disconnected);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::setRoomOutputVolume(int volume)
|
||||
void CVoiceChannelVatlib::joinVoiceRoom(const CVoiceRoom &voiceRoom)
|
||||
{
|
||||
// FIXME
|
||||
Q_UNUSED(volume)
|
||||
if (m_roomStatus == IVoiceChannel::Connecting || m_roomStatus == IVoiceChannel::Connected) return;
|
||||
|
||||
// No one else is using this voice room, so prepare to join
|
||||
m_voiceRoom = voiceRoom;
|
||||
Vat_SetRoomInfo(m_voiceChannel.data(), qPrintable(voiceRoom.getHostname()), 3782,
|
||||
qPrintable(voiceRoom.getChannel()),
|
||||
qPrintable(m_callsign.toQString()));
|
||||
|
||||
CLogMessage(this).debug() << "Joining voice room " << m_voiceRoom.getVoiceRoomUrl();
|
||||
Vat_JoinRoom(m_voiceChannel.data());
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::updateRoomStatus(VatVoiceChannel /* channel */, VatConnectionStatus /** oldVatStatus **/, VatConnectionStatus newVatStatus)
|
||||
// Leave room
|
||||
void CVoiceChannelVatlib::leaveVoiceRoom()
|
||||
{
|
||||
// If this room is not connected, there is nothing to do
|
||||
if (m_roomStatus == IVoiceChannel::Disconnecting || m_roomStatus == IVoiceChannel::Disconnected) return;
|
||||
|
||||
CLogMessage(this).debug() << "Leaving voice room " << m_voiceRoom.getVoiceRoomUrl();
|
||||
Vat_DisconnectFromRoom(m_voiceChannel.data());
|
||||
m_voiceRoom = {};
|
||||
m_listCallsigns = {};
|
||||
}
|
||||
|
||||
CCallsignList CVoiceChannelVatlib::getVoiceRoomCallsigns() const
|
||||
{
|
||||
return m_listCallsigns;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setMyAircraftCallsign(const CCallsign &callsign)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
}
|
||||
|
||||
BlackMisc::Audio::CVoiceRoom CVoiceChannelVatlib::getVoiceRoom() const
|
||||
{
|
||||
return m_voiceRoom;
|
||||
}
|
||||
|
||||
bool CVoiceChannelVatlib::isMuted() const
|
||||
{
|
||||
// Remove
|
||||
return false;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setVolume(int /* volume */)
|
||||
{
|
||||
// Remove
|
||||
}
|
||||
|
||||
int CVoiceChannelVatlib::getVolume() const
|
||||
{
|
||||
// Remove
|
||||
return 100;
|
||||
}
|
||||
|
||||
VatVoiceChannel CVoiceChannelVatlib::getVoiceChannel() const
|
||||
{
|
||||
return m_voiceChannel.data();
|
||||
}
|
||||
|
||||
CCallsign CVoiceChannelVatlib::extractCallsign(const QString &name)
|
||||
{
|
||||
CCallsign callsign;
|
||||
if (name.isEmpty()) return callsign;
|
||||
|
||||
// callsign might contain: VATSIM id, user name
|
||||
if (name.contains(" "))
|
||||
{
|
||||
QStringList parts = name.split(" ");
|
||||
callsign = CCallsign(parts[0]);
|
||||
// I throw away VATSIM id here, maybe we could use it
|
||||
}
|
||||
else
|
||||
{
|
||||
callsign = CCallsign(name);
|
||||
}
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::userJoinedVoiceRoom(VatVoiceChannel, int /** id **/, const char *name)
|
||||
{
|
||||
CCallsign callsign(extractCallsign(name));
|
||||
m_listCallsigns.push_back(callsign);
|
||||
emit userJoinedRoom(callsign);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::userLeftVoiceRoom(VatVoiceChannel, int /** id **/, const char *name)
|
||||
{
|
||||
CCallsign callsign(extractCallsign(name));
|
||||
m_listCallsigns.remove(callsign);
|
||||
emit userLeftRoom(callsign);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::transmissionChanged(VatVoiceChannel, VatVoiceTransmissionStatus status)
|
||||
{
|
||||
if (status == vatVoiceStarted) emit audioStarted();
|
||||
else emit audioStopped();
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::updateRoomStatus(VatVoiceChannel /* channel */, VatConnectionStatus /** oldVatStatus **/, VatConnectionStatus newVatStatus)
|
||||
{
|
||||
IVoiceChannel::ConnectionStatus oldStatus = m_roomStatus;
|
||||
switch (newVatStatus)
|
||||
@@ -86,219 +171,35 @@ namespace BlackCore
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit q_ptr->connectionStatusChanged(oldStatus, m_roomStatus);
|
||||
emit connectionStatusChanged(oldStatus, m_roomStatus);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::userJoinedVoiceRoom(VatVoiceChannel, int /** id **/, const char *name)
|
||||
CVoiceChannelVatlib *cbvar_cast_voiceChannel(void *cbvar)
|
||||
{
|
||||
CCallsign callsign(extractCallsign(name));
|
||||
m_listCallsigns.push_back(callsign);
|
||||
|
||||
for (const auto &e : m_voiceChannels)
|
||||
emit e->userJoinedRoom(callsign);
|
||||
return static_cast<CVoiceChannelVatlib *>(cbvar);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::userLeftVoiceRoom(VatVoiceChannel, int /** id **/, const char *name)
|
||||
void CVoiceChannelVatlib::processUserJoined(VatVoiceChannel channel, int id, const char *name, void *cbVar)
|
||||
{
|
||||
CCallsign callsign(extractCallsign(name));
|
||||
m_listCallsigns.remove(callsign);
|
||||
|
||||
for (const auto &e : m_voiceChannels)
|
||||
emit e->userLeftRoom(callsign);
|
||||
auto obj = cbvar_cast_voiceChannel(cbVar);
|
||||
obj->userJoinedVoiceRoom(channel, id, name);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::transmissionChanged(VatVoiceChannel, VatVoiceTransmissionStatus status)
|
||||
void CVoiceChannelVatlib::processUserLeft(VatVoiceChannel channel, int id, const char *name, void *cbVar)
|
||||
{
|
||||
if (status == vatVoiceStarted)
|
||||
emit q_ptr->audioStarted();
|
||||
else
|
||||
emit q_ptr->audioStopped();
|
||||
auto obj = cbvar_cast_voiceChannel(cbVar);
|
||||
obj->userLeftVoiceRoom(channel, id, name);
|
||||
}
|
||||
|
||||
CVoiceChannelVatlibPrivate *cbvar_cast_voiceChannelPrivate(void *cbvar)
|
||||
void CVoiceChannelVatlib::processTransmissionChange(VatVoiceChannel channel, VatVoiceTransmissionStatus status, void *cbVar)
|
||||
{
|
||||
return static_cast<CVoiceChannelVatlibPrivate *>(cbvar);
|
||||
auto obj = cbvar_cast_voiceChannel(cbVar);
|
||||
obj->transmissionChanged(channel, status);
|
||||
}
|
||||
|
||||
CCallsign CVoiceChannelVatlibPrivate::extractCallsign(const QString &name)
|
||||
void CVoiceChannelVatlib::roomStatusUpdate(VatVoiceChannel channel, VatConnectionStatus oldStatus, VatConnectionStatus newStatus, void *cbVar)
|
||||
{
|
||||
CCallsign callsign;
|
||||
if (name.isEmpty()) return callsign;
|
||||
|
||||
// callsign might contain: VATSIM id, user name
|
||||
if (name.contains(" "))
|
||||
{
|
||||
QStringList parts = name.split(" ");
|
||||
callsign = CCallsign(parts[0]);
|
||||
// I throw away VATSIM id here, maybe we could use it
|
||||
}
|
||||
else
|
||||
{
|
||||
callsign = CCallsign(name);
|
||||
}
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::processUserJoined(VatVoiceChannel channel, int id, const char *name, void *cbVar)
|
||||
{
|
||||
CVoiceChannelVatlibPrivate *voiceChannelPrivate = cbvar_cast_voiceChannelPrivate(cbVar);
|
||||
voiceChannelPrivate->userJoinedVoiceRoom(channel, id, name);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::processUserLeft(VatVoiceChannel channel, int id, const char *name, void *cbVar)
|
||||
{
|
||||
CVoiceChannelVatlibPrivate *voiceChannelPrivate = cbvar_cast_voiceChannelPrivate(cbVar);
|
||||
voiceChannelPrivate->userLeftVoiceRoom(channel, id, name);
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlibPrivate::processTransmissionChange(VatVoiceChannel channel, VatVoiceTransmissionStatus status, void *cbVar)
|
||||
{
|
||||
CVoiceChannelVatlibPrivate *voiceChannelPrivate = cbvar_cast_voiceChannelPrivate(cbVar);
|
||||
|
||||
voiceChannelPrivate->transmissionChanged(channel, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Room status update
|
||||
*/
|
||||
void CVoiceChannelVatlibPrivate::onRoomStatusUpdate(VatVoiceChannel channel, VatConnectionStatus oldStatus, VatConnectionStatus newStatus, void *cbVar)
|
||||
{
|
||||
auto obj = cbvar_cast_voiceChannelPrivate(cbVar);
|
||||
auto obj = cbvar_cast_voiceChannel(cbVar);
|
||||
obj->updateRoomStatus(channel, oldStatus, newStatus);
|
||||
}
|
||||
|
||||
// Get shared room data
|
||||
QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> &CVoiceChannelVatlibPrivate::getSharedRoomData()
|
||||
{
|
||||
return m_sharedRoomData;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
CVoiceChannelVatlib::CVoiceChannelVatlib(VatAudioService audioService, VatUDPAudioPort udpPort, QObject *parent)
|
||||
: IVoiceChannel(parent),
|
||||
d_ptr(new CVoiceChannelVatlibPrivate(audioService, udpPort, this))
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
CVoiceChannelVatlib::~CVoiceChannelVatlib()
|
||||
{
|
||||
d_ptr->m_voiceChannels.removeAll(this);
|
||||
}
|
||||
|
||||
// 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();
|
||||
});
|
||||
|
||||
// If we found 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);
|
||||
|
||||
// Add ourselfes as listener
|
||||
d_ptr->m_voiceChannels.push_back(this);
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No one else is using this voice room, so prepare to join
|
||||
d_ptr->m_voiceRoom = voiceRoom;
|
||||
Vat_SetRoomInfo(d_ptr->m_voiceChannel.data(), qPrintable(voiceRoom.getHostname()), 3782,
|
||||
qPrintable(voiceRoom.getChannel()),
|
||||
qPrintable(d_ptr->m_callsign.toQString()));
|
||||
|
||||
d_ptr->m_roomStatus = IVoiceChannel::Disconnected;
|
||||
Vat_JoinRoom(d_ptr->m_voiceChannel.data());
|
||||
|
||||
CVoiceChannelVatlibPrivate::m_sharedRoomData.insert(this, d_ptr);
|
||||
++d_ptr->m_connectionRefCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
qDebug() << "Leaving voice room!";
|
||||
Vat_DisconnectFromRoom(d_ptr->m_voiceChannel.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
d_ptr->m_voiceChannels.removeAll(this);
|
||||
|
||||
// We need to assign a private class
|
||||
// This automatically clears callsign list etc.
|
||||
VatAudioService audioService = d_ptr->m_audioService;
|
||||
VatUDPAudioPort udpPort = d_ptr->m_udpPort;
|
||||
|
||||
d_ptr.reset(new CVoiceChannelVatlibPrivate(audioService, udpPort, this));
|
||||
CVoiceChannelVatlibPrivate::getSharedRoomData().insert(this, d_ptr);
|
||||
|
||||
// Simulate the state change
|
||||
emit connectionStatusChanged(IVoiceChannel::Connected, IVoiceChannel::Disconnecting);
|
||||
emit connectionStatusChanged(IVoiceChannel::Disconnecting, IVoiceChannel::Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignList CVoiceChannelVatlib::getVoiceRoomCallsigns() const
|
||||
{
|
||||
return d_ptr->m_listCallsigns;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setMyAircraftCallsign(const CCallsign &callsign)
|
||||
{
|
||||
d_ptr->m_callsign = callsign;
|
||||
}
|
||||
|
||||
BlackMisc::Audio::CVoiceRoom CVoiceChannelVatlib::getVoiceRoom() const
|
||||
{
|
||||
return d_ptr->m_voiceRoom;
|
||||
}
|
||||
|
||||
bool CVoiceChannelVatlib::isMuted() const
|
||||
{
|
||||
return !d_ptr->m_outputEnabled;
|
||||
}
|
||||
|
||||
void CVoiceChannelVatlib::setVolume(int volume)
|
||||
{
|
||||
d_ptr->setRoomOutputVolume(volume);
|
||||
}
|
||||
|
||||
int CVoiceChannelVatlib::getVolume() const
|
||||
{
|
||||
// FIXME
|
||||
return 100;
|
||||
}
|
||||
|
||||
VatVoiceChannel CVoiceChannelVatlib::getVoiceChannel() const
|
||||
{
|
||||
return d_ptr->m_voiceChannel.data();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,37 @@ namespace BlackCore
|
||||
VatVoiceChannel getVoiceChannel() const;
|
||||
|
||||
private:
|
||||
QSharedPointer<CVoiceChannelVatlibPrivate> d_ptr;
|
||||
|
||||
struct VatVoiceChannelDeleter
|
||||
{
|
||||
static inline void cleanup(VatProducerConsumer_tag *obj)
|
||||
{
|
||||
if (obj) Vat_DestroyVoiceChannel(obj);
|
||||
}
|
||||
};
|
||||
|
||||
BlackMisc::Aviation::CCallsign extractCallsign(const QString &name);
|
||||
|
||||
void userJoinedVoiceRoom(VatVoiceChannel, int id, const char *name);
|
||||
void userLeftVoiceRoom(VatVoiceChannel, int id, const char *name);
|
||||
void transmissionChanged(VatVoiceChannel, VatVoiceTransmissionStatus status);
|
||||
void updateRoomStatus(VatVoiceChannel channel, VatConnectionStatus /** oldStatus **/, VatConnectionStatus newStatus);
|
||||
|
||||
static void processUserJoined(VatVoiceChannel channel, int id, const char *name, void *cbVar);
|
||||
static void processUserLeft(VatVoiceChannel channel, int id, const char *name, void *cbVar);
|
||||
static void processTransmissionChange(VatVoiceChannel channel, VatVoiceTransmissionStatus status, void *cbVar);
|
||||
|
||||
static void roomStatusUpdate(VatVoiceChannel channel, VatConnectionStatus oldStatus, VatConnectionStatus newStatus, void *cbVar);
|
||||
|
||||
BlackMisc::Aviation::CCallsign m_callsign; // Own callsign
|
||||
BlackMisc::Audio::CVoiceRoom m_voiceRoom; // Voice Room
|
||||
BlackMisc::Aviation::CCallsignList m_listCallsigns; // Callsigns connected to room
|
||||
IVoiceChannel::ConnectionStatus m_roomStatus = IVoiceChannel::Disconnected; // Room connection status
|
||||
|
||||
VatAudioService m_audioService;
|
||||
VatUDPAudioPort m_udpPort;
|
||||
|
||||
QScopedPointer<VatProducerConsumer_tag, VatVoiceChannelDeleter> m_voiceChannel;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/* 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:
|
||||
|
||||
struct VatVoiceChannelDeleter
|
||||
{
|
||||
static inline void cleanup(VatProducerConsumer_tag *obj)
|
||||
{
|
||||
if (obj) Vat_DestroyVoiceChannel(obj);
|
||||
}
|
||||
};
|
||||
|
||||
// Default constructor
|
||||
CVoiceChannelVatlibPrivate(VatAudioService audioService, VatUDPAudioPort udpPort, CVoiceChannelVatlib *parent);
|
||||
|
||||
// Destructor
|
||||
~CVoiceChannelVatlibPrivate();
|
||||
|
||||
// Set room output volume
|
||||
void setRoomOutputVolume(int volume);
|
||||
|
||||
void updateRoomStatus(VatVoiceChannel channel, VatConnectionStatus /** oldStatus **/, VatConnectionStatus newStatus);
|
||||
|
||||
BlackMisc::Aviation::CCallsign extractCallsign(const QString &name);
|
||||
|
||||
static void processUserJoined(VatVoiceChannel channel, int id, const char *name, void *cbVar);
|
||||
static void processUserLeft(VatVoiceChannel channel, int id, const char *name, void *cbVar);
|
||||
static void processTransmissionChange(VatVoiceChannel channel, VatVoiceTransmissionStatus status, void *cbVar);
|
||||
|
||||
static void onRoomStatusUpdate(VatVoiceChannel channel, VatConnectionStatus oldStatus, VatConnectionStatus newStatus, void *cbVar);
|
||||
|
||||
// Get shared room data for this channel
|
||||
static QHash<CVoiceChannelVatlib * const, QSharedPointer<CVoiceChannelVatlibPrivate>> &getSharedRoomData();
|
||||
|
||||
BlackMisc::Aviation::CCallsign m_callsign; // Own callsign
|
||||
BlackMisc::Audio::CVoiceRoom m_voiceRoom; // Voice Room
|
||||
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
|
||||
QList<CVoiceChannelVatlib *> m_voiceChannels;
|
||||
|
||||
VatAudioService m_audioService;
|
||||
VatUDPAudioPort m_udpPort;
|
||||
QScopedPointer<VatProducerConsumer_tag, VatVoiceChannelDeleter> m_voiceChannel;
|
||||
|
||||
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:
|
||||
|
||||
void userJoinedVoiceRoom(VatVoiceChannel, int id, const char *name);
|
||||
void userLeftVoiceRoom(VatVoiceChannel, int id, const char *name);
|
||||
void transmissionChanged(VatVoiceChannel, VatVoiceTransmissionStatus status);
|
||||
};
|
||||
//! \endcond
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
@@ -39,9 +39,9 @@ namespace BlackCore
|
||||
*/
|
||||
CVoiceVatlib::~CVoiceVatlib() {}
|
||||
|
||||
std::unique_ptr<IVoiceChannel> CVoiceVatlib::createVoiceChannel()
|
||||
QSharedPointer<IVoiceChannel> CVoiceVatlib::createVoiceChannel()
|
||||
{
|
||||
return make_unique<CVoiceChannelVatlib>(m_audioService.data(), m_udpPort.data(), this);
|
||||
return QSharedPointer<IVoiceChannel>(new CVoiceChannelVatlib(m_audioService.data(), m_udpPort.data(), this));
|
||||
}
|
||||
|
||||
std::unique_ptr<IAudioInputDevice> CVoiceVatlib::createInputDevice()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QScopedPointer>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#ifndef NOMINMAX
|
||||
@@ -37,7 +38,7 @@ namespace BlackCore
|
||||
virtual ~CVoiceVatlib();
|
||||
|
||||
//! \copydoc IVoice::createVoiceChannel()
|
||||
virtual std::unique_ptr<IVoiceChannel> createVoiceChannel() override;
|
||||
virtual QSharedPointer<IVoiceChannel> createVoiceChannel() override;
|
||||
|
||||
//! \copydoc IVoice::createInputDevice()
|
||||
virtual std::unique_ptr<IAudioInputDevice> createInputDevice() override;
|
||||
|
||||
Reference in New Issue
Block a user