2015-05-26 11:19:57 -04:00
|
|
|
/****************************************************************
|
|
|
|
* RetroShare is distributed under the following license:
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
****************************************************************/
|
|
|
|
|
|
|
|
/*VOIP*/
|
|
|
|
#include "gui/VOIPToasterNotify.h"
|
|
|
|
#include "gui/VOIPToasterItem.h"
|
|
|
|
|
|
|
|
/*retroshare-gui*/
|
|
|
|
#include "gui/settings/rsharesettings.h"
|
|
|
|
#include "gui/toaster/ToasterItem.h"
|
|
|
|
|
|
|
|
/*libretroshare*/
|
|
|
|
#include "retroshare/rspeers.h"
|
|
|
|
|
|
|
|
VOIPToasterNotify::VOIPToasterNotify(RsVOIP *VOIP, VOIPNotify *notify, QObject *parent)
|
|
|
|
: ToasterNotify(parent), mVOIP(VOIP), mVOIPNotify(notify)
|
|
|
|
{
|
|
|
|
mMutex = new QMutex();
|
|
|
|
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipAcceptReceived(const RsPeerId&)), this, SLOT(voipAcceptReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipBandwidthInfoReceived(const RsPeerId&, int)), this, SLOT(voipBandwidthInfoReceived(RsPeerId&, int)), Qt::QueuedConnection);
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipDataReceived(const RsPeerId&)), this, SLOT(voipDataReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipHangUpReceived(const RsPeerId&)), this, SLOT(voipHangUpReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipInvitationReceived(const RsPeerId&)), this, SLOT(voipInvitationReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
#endif
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipAudioCallReceived(const RsPeerId&)), this, SLOT(voipAudioCallReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
connect(mVOIPNotify, SIGNAL(voipVideoCallReceived(const RsPeerId&)), this, SLOT(voipVideoCallReceived(const RsPeerId&)), Qt::QueuedConnection);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOIPToasterNotify::~VOIPToasterNotify()
|
|
|
|
{
|
|
|
|
delete(mMutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VOIPToasterNotify::hasSettings(QString &mainName, QMap<QString, QString> &tagAndTexts)
|
|
|
|
{
|
|
|
|
mainName = tr("VOIP");
|
|
|
|
//gAndTexts.insert("Tag" , tr("Text"));
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
tagAndTexts.insert("Accept" , tr("Accept"));
|
|
|
|
tagAndTexts.insert("BandwidthInfo", tr("Bandwidth Information"));
|
|
|
|
tagAndTexts.insert("Data" , tr("Audio or Video Data"));
|
|
|
|
tagAndTexts.insert("HangUp" , tr("HangUp"));
|
|
|
|
tagAndTexts.insert("Invitation" , tr("Invitation"));
|
|
|
|
#endif
|
|
|
|
tagAndTexts.insert("AudioCall" , tr("Audio Call"));
|
|
|
|
tagAndTexts.insert("VideoCall" , tr("Video Call"));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VOIPToasterNotify::notifyEnabled(QString tag)
|
|
|
|
{
|
|
|
|
return Settings->valueFromGroup("VOIP", QString("ToasterNotifyEnable").append(tag), false).toBool();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::setNotifyEnabled(QString tag, bool enabled)
|
|
|
|
{
|
|
|
|
Settings->setValueToGroup("VOIP", QString("ToasterNotifyEnable").append(tag), enabled);
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
/* remove pending Toaster items */
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
if(tag == "Accept") mPendingToasterAccept.clear();
|
|
|
|
if(tag == "BandwidthInfo") mPendingToasterBandwidthInfo.clear();
|
|
|
|
if(tag == "Data") mPendingToasterData.clear();
|
|
|
|
if(tag == "HangUp") mPendingToasterHangUp.clear();
|
|
|
|
if(tag == "Invitation") mPendingToasterInvitation.clear();
|
|
|
|
#endif
|
|
|
|
if(tag == "AudioCall") mPendingToasterAudioCall.clear();
|
|
|
|
if(tag == "VideoCall") mPendingToasterVideoCall.clear();
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ToasterItem *VOIPToasterNotify::toasterItem()
|
|
|
|
{
|
|
|
|
ToasterItem *toasterItem = NULL;
|
|
|
|
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
if (!mPendingToasterAccept.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterAccept.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::Accept);
|
|
|
|
toasterItem= new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedAccept(ToasterItem*)));
|
|
|
|
mToasterAccept.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
if (!mPendingToasterBandwidthInfo.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterBandwidthInfo.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::BandwidthInfo);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedBandwidthInfo(ToasterItem*)));
|
|
|
|
mToasterBandwidthInfo.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
if (!mPendingToasterData.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterData.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::Data);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
toasterItem->timeToLive = 10000;
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedData(ToasterItem*)));
|
|
|
|
mToasterData.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
if (!mPendingToasterHangUp.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterHangUp.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::HangUp);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedHangUp(ToasterItem*)));
|
|
|
|
mToasterHangUp.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
if (!mPendingToasterInvitation.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterInvitation.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::Invitation);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedInvitation(ToasterItem*)));
|
|
|
|
mToasterInvitation.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!mPendingToasterAudioCall.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterAudioCall.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::AudioCall);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedAudioCall(ToasterItem*)));
|
|
|
|
mToasterAudioCall.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
if (!mPendingToasterVideoCall.empty() && !toasterItem) {
|
|
|
|
mMutex->lock();
|
|
|
|
ToasterItemData toasterItemData = mPendingToasterVideoCall.takeFirst();
|
|
|
|
VOIPToasterItem *voipToasterItem = new VOIPToasterItem(toasterItemData.mPeerId, toasterItemData.mMsg, VOIPToasterItem::VideoCall);
|
|
|
|
toasterItem = new ToasterItem(voipToasterItem);
|
|
|
|
connect(toasterItem, SIGNAL(toasterItemDestroyed(ToasterItem*)), this, SLOT(toasterItemDestroyedVideoCall(ToasterItem*)));
|
|
|
|
mToasterVideoCall.insert(toasterItemData.mPeerId, toasterItem);
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
return toasterItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
ToasterItem* VOIPToasterNotify::testToasterItem(QString tag)
|
|
|
|
{
|
|
|
|
ToasterItem* toaster = NULL;
|
|
|
|
RsPeerId ownId = rsPeers->getOwnId();
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
if (tag == "Accept") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP Accept"), VOIPToasterItem::Accept));
|
|
|
|
if (tag == "BandwidthInfo") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP BandwidthInfo"), VOIPToasterItem::BandwidthInfo));
|
|
|
|
if (tag == "Data") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP Data"), VOIPToasterItem::Data));
|
|
|
|
if (tag == "HangUp") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP HangUp"), VOIPToasterItem::HangUp));
|
|
|
|
if (tag == "Invitation") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP Invitation"), VOIPToasterItem::Invitation));
|
|
|
|
#endif
|
|
|
|
if (tag == "AudioCall") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP Audio Call"), VOIPToasterItem::AudioCall));
|
|
|
|
if (tag == "VideoCall") toaster = new ToasterItem(new VOIPToasterItem(ownId, tr("Test VOIP Video Call"), VOIPToasterItem::VideoCall));
|
|
|
|
|
|
|
|
return toaster;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
void VOIPToasterNotify::voipAcceptReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("Accept")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterAccept.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
|
|
|
toasterItemData.mMsg = tr("Accept received from this peer.");
|
|
|
|
|
|
|
|
mPendingToasterAccept.push_back(toasterItemData);
|
|
|
|
mToasterAccept.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipBandwidthInfoReceived(const RsPeerId &peer_id,int bytes_per_sec)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("BandwidthInfo")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterBandwidthInfo.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
|
|
|
toasterItemData.mMsg = tr("Bandwidth Info received from this peer:%1").arg(bytes_per_sec);
|
|
|
|
|
|
|
|
mPendingToasterBandwidthInfo.push_back(toasterItemData);
|
|
|
|
mToasterBandwidthInfo.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipDataReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("Data")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterData.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
|
|
|
toasterItemData.mMsg = tr("Audio or Video Data received from this peer.");
|
|
|
|
|
|
|
|
mPendingToasterData.push_back(toasterItemData);
|
|
|
|
mToasterData.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipHangUpReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("HangUp")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterHangUp.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
|
|
|
toasterItemData.mMsg = tr("HangUp received from this peer.");
|
|
|
|
|
|
|
|
mPendingToasterHangUp.push_back(toasterItemData);
|
|
|
|
mToasterHangUp.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipInvitationReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("Invitation")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterInvitation.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
|
|
|
toasterItemData.mMsg = tr("Invitation received from this peer.");
|
|
|
|
|
|
|
|
mPendingToasterInvitation.push_back(toasterItemData);
|
|
|
|
mToasterInvitation.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipAudioCallReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("AudioCall")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterAudioCall.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
2015-05-28 09:59:20 -04:00
|
|
|
toasterItemData.mMsg = QString::fromUtf8(rsPeers->getPeerName(toasterItemData.mPeerId).c_str()) + " " + tr("calling");
|
2015-05-26 11:19:57 -04:00
|
|
|
|
|
|
|
mPendingToasterAudioCall.push_back(toasterItemData);
|
|
|
|
mToasterAudioCall.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::voipVideoCallReceived(const RsPeerId &peer_id)
|
|
|
|
{
|
|
|
|
if (peer_id.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!notifyEnabled("VideoCall")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->lock();
|
|
|
|
|
|
|
|
if (!mToasterVideoCall.contains(peer_id)){
|
|
|
|
ToasterItemData toasterItemData;
|
|
|
|
toasterItemData.mPeerId = peer_id;
|
2015-05-28 09:59:20 -04:00
|
|
|
toasterItemData.mMsg = QString::fromUtf8(rsPeers->getPeerName(toasterItemData.mPeerId).c_str()) + " " + tr("calling");
|
2015-05-26 11:19:57 -04:00
|
|
|
|
|
|
|
mPendingToasterVideoCall.push_back(toasterItemData);
|
|
|
|
mToasterVideoCall.insert(peer_id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VOIPTOASTERNOTIFY_ALL
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedAccept(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterAccept.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterAccept.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedBandwidthInfo(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterBandwidthInfo.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterBandwidthInfo.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedData(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterData.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterData.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedHangUp(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterHangUp.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterHangUp.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedInvitation(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterInvitation.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterInvitation.remove(key);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedAudioCall(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterAudioCall.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterAudioCall.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VOIPToasterNotify::toasterItemDestroyedVideoCall(ToasterItem *toasterItem)
|
|
|
|
{
|
|
|
|
RsPeerId key = mToasterVideoCall.key(toasterItem, RsPeerId());
|
|
|
|
if (!key.isNull()) mToasterVideoCall.remove(key);
|
|
|
|
}
|
|
|
|
|