/**************************************************************** * 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. ****************************************************************/ //C++ #include //Qt #include #include #include #include //VOIP #include #include "interface/rsVOIP.h" #include "VOIPChatWidgetHolder.h" #include "VideoProcessor.h" #include "QVideoDevice.h" //retroshare GUI #include "gui/SoundManager.h" #include "util/HandleRichText.h" #include "gui/common/StatusDefs.h" #include "gui/chat/ChatWidget.h" //libretroshare #include #include #define CALL_START ":/images/call-start.png" #define CALL_STOP ":/images/call-stop.png" #define CALL_HOLD ":/images/call-hold.png" VOIPChatWidgetHolder::VOIPChatWidgetHolder(ChatWidget *chatWidget, VOIPNotify *notify) : QObject(), ChatWidgetHolder(chatWidget), mVOIPNotify(notify) { int S = QFontMetricsF(chatWidget->font()).height() ; QSize iconSize = QSize(3*S,3*S); QSize buttonSize = QSize(iconSize + QSize(3,3)); QIcon iconaudioListenToggleButton ; iconaudioListenToggleButton.addPixmap(QPixmap(":/images/audio-volume-muted.png")) ; iconaudioListenToggleButton.addPixmap(QPixmap(":/images/audio-volume-high.png"),QIcon::Normal,QIcon::On) ; iconaudioListenToggleButton.addPixmap(QPixmap(":/images/audio-volume-high.png"),QIcon::Disabled,QIcon::On) ; iconaudioListenToggleButton.addPixmap(QPixmap(":/images/audio-volume-high.png"),QIcon::Active,QIcon::On) ; iconaudioListenToggleButton.addPixmap(QPixmap(":/images/audio-volume-high.png"),QIcon::Selected,QIcon::On) ; audioListenToggleButton = new QToolButton ; audioListenToggleButton->setIcon(iconaudioListenToggleButton) ; audioListenToggleButton->setIconSize(iconSize) ; audioListenToggleButton->setMinimumSize(buttonSize) ; audioListenToggleButton->setMaximumSize(buttonSize) ; audioListenToggleButton->setCheckable(true); audioListenToggleButton->setAutoRaise(true) ; audioListenToggleButton->setText(QString()) ; audioListenToggleButton->setToolTip(tr("Mute")); audioListenToggleButton->setEnabled(false); QIcon iconaudioCaptureToggleButton ; iconaudioCaptureToggleButton.addPixmap(QPixmap(":/images/call-start.png")) ; iconaudioCaptureToggleButton.addPixmap(QPixmap(":/images/call-hold.png"),QIcon::Normal,QIcon::On) ; iconaudioCaptureToggleButton.addPixmap(QPixmap(":/images/call-hold.png"),QIcon::Disabled,QIcon::On) ; iconaudioCaptureToggleButton.addPixmap(QPixmap(":/images/call-hold.png"),QIcon::Active,QIcon::On) ; iconaudioCaptureToggleButton.addPixmap(QPixmap(":/images/call-hold.png"),QIcon::Selected,QIcon::On) ; audioCaptureToggleButton = new QToolButton ; audioCaptureToggleButton->setIcon(iconaudioCaptureToggleButton) ; audioCaptureToggleButton->setIconSize(iconSize) ; audioCaptureToggleButton->setMinimumSize(buttonSize) ; audioCaptureToggleButton->setMaximumSize(buttonSize) ; audioCaptureToggleButton->setCheckable(true) ; audioCaptureToggleButton->setAutoRaise(true) ; audioCaptureToggleButton->setText(QString()) ; audioCaptureToggleButton->setToolTip(tr("Start Call")); QIcon iconvideoCaptureToggleButton ; iconvideoCaptureToggleButton.addPixmap(QPixmap(":/images/video-icon-on.png")) ; iconvideoCaptureToggleButton.addPixmap(QPixmap(":/images/video-icon-off.png"),QIcon::Normal,QIcon::On) ; iconvideoCaptureToggleButton.addPixmap(QPixmap(":/images/video-icon-off.png"),QIcon::Disabled,QIcon::On) ; iconvideoCaptureToggleButton.addPixmap(QPixmap(":/images/video-icon-off.png"),QIcon::Active,QIcon::On) ; iconvideoCaptureToggleButton.addPixmap(QPixmap(":/images/video-icon-off.png"),QIcon::Selected,QIcon::On) ; videoCaptureToggleButton = new QToolButton ; videoCaptureToggleButton->setIcon(iconvideoCaptureToggleButton) ; videoCaptureToggleButton->setIconSize(iconSize) ; videoCaptureToggleButton->setMinimumSize(buttonSize) ; videoCaptureToggleButton->setMaximumSize(buttonSize) ; videoCaptureToggleButton->setCheckable(true) ; videoCaptureToggleButton->setAutoRaise(true) ; videoCaptureToggleButton->setText(QString()) ; videoCaptureToggleButton->setToolTip(tr("Start Video Call")); hangupButton = new QToolButton ; hangupButton->setIcon(QIcon(":/images/call-stop.png")) ; hangupButton->setIconSize(iconSize) ; hangupButton->setMinimumSize(buttonSize) ; hangupButton->setMaximumSize(buttonSize) ; hangupButton->setCheckable(false) ; hangupButton->setAutoRaise(true) ; hangupButton->setText(QString()) ; hangupButton->setToolTip(tr("Hangup Call")); hangupButton->hide(); QIcon iconhideChatTextToggleButton ; iconhideChatTextToggleButton.addPixmap(QPixmap(":/images/orange-bubble-64.png")) ; iconhideChatTextToggleButton.addPixmap(QPixmap(":/images/white-bubble-64.png"),QIcon::Normal,QIcon::On) ; iconhideChatTextToggleButton.addPixmap(QPixmap(":/images/white-bubble-64.png"),QIcon::Disabled,QIcon::On) ; iconhideChatTextToggleButton.addPixmap(QPixmap(":/images/white-bubble-64.png"),QIcon::Active,QIcon::On) ; iconhideChatTextToggleButton.addPixmap(QPixmap(":/images/white-bubble-64.png"),QIcon::Selected,QIcon::On) ; hideChatTextToggleButton = new QToolButton ; hideChatTextToggleButton->setIcon(iconhideChatTextToggleButton) ; hideChatTextToggleButton->setIconSize(iconSize) ; hideChatTextToggleButton->setMinimumSize(buttonSize) ; hideChatTextToggleButton->setMaximumSize(buttonSize) ; hideChatTextToggleButton->setCheckable(true) ; hideChatTextToggleButton->setAutoRaise(true) ; hideChatTextToggleButton->setText(QString()) ; hideChatTextToggleButton->setToolTip(tr("Hide Chat Text")); hideChatTextToggleButton->setEnabled(false) ; QIcon iconfullscreenToggleButton ; iconfullscreenToggleButton.addPixmap(QPixmap(":/images/channels32.png")) ; iconfullscreenToggleButton.addPixmap(QPixmap(":/images/folder-draft24.png"),QIcon::Normal,QIcon::On) ; iconfullscreenToggleButton.addPixmap(QPixmap(":/images/folder-draft24.png"),QIcon::Disabled,QIcon::On) ; iconfullscreenToggleButton.addPixmap(QPixmap(":/images/folder-draft24.png"),QIcon::Active,QIcon::On) ; iconfullscreenToggleButton.addPixmap(QPixmap(":/images/folder-draft24.png"),QIcon::Selected,QIcon::On) ; fullscreenToggleButton = new QToolButton ; fullscreenToggleButton->setIcon(iconfullscreenToggleButton) ; fullscreenToggleButton->setIconSize(iconSize) ; fullscreenToggleButton->setMinimumSize(buttonSize) ; fullscreenToggleButton->setMaximumSize(buttonSize) ; fullscreenToggleButton->setCheckable(true) ; fullscreenToggleButton->setAutoRaise(true) ; fullscreenToggleButton->setText(QString()) ; fullscreenToggleButton->setToolTip(tr("Fullscreen mode")); fullscreenToggleButton->setEnabled(false) ; connect(audioListenToggleButton, SIGNAL(clicked()), this , SLOT(toggleAudioListen())); connect(audioCaptureToggleButton, SIGNAL(clicked()), this , SLOT(toggleAudioCapture())); connect(videoCaptureToggleButton, SIGNAL(clicked()), this , SLOT(toggleVideoCapture())); connect(hangupButton, SIGNAL(clicked()), this , SLOT(hangupCall())); connect(hideChatTextToggleButton, SIGNAL(clicked()), this , SLOT(toggleHideChatText())); connect(fullscreenToggleButton, SIGNAL(clicked()), this , SLOT(toggleFullScreen())); mChatWidget->addTitleBarWidget(audioListenToggleButton) ; mChatWidget->addTitleBarWidget(audioCaptureToggleButton) ; mChatWidget->addTitleBarWidget(videoCaptureToggleButton) ; mChatWidget->addTitleBarWidget(hangupButton) ; mChatWidget->addTitleBarWidget(hideChatTextToggleButton) ; mChatWidget->addTitleBarWidget(fullscreenToggleButton) ; outputAudioProcessor = NULL ; outputAudioDevice = NULL ; inputAudioProcessor = NULL ; inputAudioDevice = NULL ; inputVideoDevice = new QVideoInputDevice(mChatWidget) ; // not started yet ;-) videoProcessor = new VideoProcessor ; // Make a widget with two video devices, one for echo, and one for the talking peer. videoWidget = new QWidget(mChatWidget) ; videoWidget->setLayout(new QVBoxLayout()) ; videoWidget->layout()->addWidget(outputVideoDevice = new QVideoOutputDevice(videoWidget)) ; videoWidget->layout()->addWidget(echoVideoDevice = new QVideoOutputDevice(videoWidget)) ; videoWidget->hide(); connect(inputVideoDevice, SIGNAL(networkPacketReady()), this, SLOT(sendVideoData())); echoVideoDevice->setMinimumSize(320,240) ;//4/3 outputVideoDevice->setMinimumSize(320,240) ;//4/3 echoVideoDevice->showFrameOff(); outputVideoDevice->showFrameOff(); echoVideoDevice->setStyleSheet("border: 4px solid #CCCCCC; border-radius: 4px;"); outputVideoDevice->setStyleSheet("border: 4px solid #CCCCCC; border-radius: 4px;"); /// FULLSCREEN /// fullScreenFrame = new QFrame(); outputVideoDeviceFS = new QVideoOutputDevice(fullScreenFrame); outputVideoDeviceFS->setGeometry(QRect(QPoint(0,0),fullScreenFrame->geometry().size())); outputVideoDeviceFS->showFrameOff(); echoVideoDeviceFS = new QVideoOutputDevice(fullScreenFrame); echoVideoDeviceFS->setGeometry(QRect(QPoint(fullScreenFrame->width(), fullScreenFrame->height()) - QPoint(320,240), QSize(320,240))); echoVideoDeviceFS->showFrameOff(); toolBarFS = new QFrame(fullScreenFrame); QHBoxLayout *toolBarFSLayout = new QHBoxLayout(toolBarFS); audioListenToggleButtonFS = new QToolButton(fullScreenFrame) ; audioListenToggleButtonFS->setIcon(iconaudioListenToggleButton) ; audioListenToggleButtonFS->setIconSize(iconSize) ; audioListenToggleButtonFS->setMinimumSize(buttonSize) ; audioListenToggleButtonFS->setMaximumSize(buttonSize) ; audioListenToggleButtonFS->setCheckable(true); audioListenToggleButtonFS->setAutoRaise(true) ; audioListenToggleButtonFS->setText(QString()) ; audioListenToggleButtonFS->setToolTip(tr("Mute")); audioCaptureToggleButtonFS = new QToolButton(fullScreenFrame) ; audioCaptureToggleButtonFS->setIcon(iconaudioCaptureToggleButton) ; audioCaptureToggleButtonFS->setIconSize(iconSize) ; audioCaptureToggleButtonFS->setMinimumSize(buttonSize) ; audioCaptureToggleButtonFS->setMaximumSize(buttonSize) ; audioCaptureToggleButtonFS->setCheckable(true) ; audioCaptureToggleButtonFS->setAutoRaise(true) ; audioCaptureToggleButtonFS->setText(QString()) ; audioCaptureToggleButtonFS->setToolTip(tr("Start Call")); videoCaptureToggleButtonFS = new QToolButton(fullScreenFrame) ; videoCaptureToggleButtonFS->setIcon(iconvideoCaptureToggleButton) ; videoCaptureToggleButtonFS->setIconSize(iconSize) ; videoCaptureToggleButtonFS->setMinimumSize(buttonSize) ; videoCaptureToggleButtonFS->setMaximumSize(buttonSize) ; videoCaptureToggleButtonFS->setCheckable(true) ; videoCaptureToggleButtonFS->setAutoRaise(true) ; videoCaptureToggleButtonFS->setText(QString()) ; videoCaptureToggleButtonFS->setToolTip(tr("Start Video Call")); hangupButtonFS = new QToolButton(fullScreenFrame) ; hangupButtonFS->setIcon(QIcon(":/images/call-stop.png")) ; hangupButtonFS->setIconSize(iconSize) ; hangupButtonFS->setMinimumSize(buttonSize) ; hangupButtonFS->setMaximumSize(buttonSize) ; hangupButtonFS->setCheckable(false) ; hangupButtonFS->setAutoRaise(true) ; hangupButtonFS->setText(QString()) ; hangupButtonFS->setToolTip(tr("Hangup Call")); hangupButtonFS->hide(); fullscreenToggleButtonFS = new QToolButton(fullScreenFrame); fullscreenToggleButtonFS->setIcon(iconfullscreenToggleButton); fullscreenToggleButtonFS->setIconSize(iconSize); fullscreenToggleButtonFS->setMinimumSize(buttonSize); fullscreenToggleButtonFS->setMaximumSize(buttonSize); fullscreenToggleButtonFS->setCheckable(true); fullscreenToggleButtonFS->setAutoRaise(true); fullscreenToggleButtonFS->setText(QString()); fullscreenToggleButtonFS->setToolTip(tr("Fullscreen mode")); fullscreenToggleButtonFS->setEnabled(false); connect(audioListenToggleButtonFS, SIGNAL(clicked()), this , SLOT(toggleAudioListenFS())); connect(audioCaptureToggleButtonFS, SIGNAL(clicked()), this , SLOT(toggleAudioCaptureFS())); connect(videoCaptureToggleButtonFS, SIGNAL(clicked()), this , SLOT(toggleVideoCaptureFS())); connect(hangupButtonFS, SIGNAL(clicked()), this , SLOT(hangupCall())); connect(fullscreenToggleButtonFS, SIGNAL(clicked()), this , SLOT(toggleFullScreenFS())); toolBarFSLayout->setDirection(QBoxLayout::LeftToRight); toolBarFSLayout->setSpacing(2); toolBarFSLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); toolBarFSLayout->addWidget(audioListenToggleButtonFS); toolBarFSLayout->addWidget(audioCaptureToggleButtonFS); toolBarFSLayout->addWidget(videoCaptureToggleButtonFS); toolBarFSLayout->addWidget(hangupButtonFS); toolBarFSLayout->addWidget(fullscreenToggleButtonFS); toolBarFS->setLayout(toolBarFSLayout); fullScreenFrame->setParent(0); fullScreenFrame->setWindowFlags(Qt::WindowStaysOnTopHint); fullScreenFrame->setFocusPolicy(Qt::StrongFocus); fullScreenFrame->setWindowState(Qt::WindowFullScreen); fullScreenFrame->hide(); fullScreenFrame->installEventFilter(this); mChatWidget->addChatHorizontalWidget(videoWidget) ; inputVideoDevice->setEchoVideoTarget(echoVideoDevice) ; inputVideoDevice->setVideoProcessor(videoProcessor) ; videoProcessor->setDisplayTarget(outputVideoDevice) ; //Ring pbAudioRing = new QProgressBar(); pbAudioRing->setOrientation(Qt::Horizontal); pbAudioRing->setRange(0, 99); pbAudioRing->setTextVisible(false); pbAudioRing->setHidden(true); pbVideoRing = new QProgressBar(); pbVideoRing->setOrientation(Qt::Horizontal); pbVideoRing->setRange(0, 99); pbVideoRing->setTextVisible(false); pbVideoRing->setHidden(true); mChatWidget->addChatBarWidget(pbAudioRing); mChatWidget->addChatBarWidget(pbVideoRing); sendAudioRingTime = -1; sendVideoRingTime = -1; recAudioRingTime = -1; recVideoRingTime = -1; timerAudioRing = new QTimer(this); timerAudioRing->setInterval(300); timerAudioRing->setSingleShot(true); connect(timerAudioRing, SIGNAL(timeout()), this, SLOT(timerAudioRingTimeOut())); timerVideoRing = new QTimer(this); timerVideoRing->setInterval(300); timerVideoRing->setSingleShot(true); connect(timerVideoRing, SIGNAL(timeout()), this, SLOT(timerVideoRingTimeOut())); lastTimePlayOccurs = time(NULL); } VOIPChatWidgetHolder::~VOIPChatWidgetHolder() { hangupCall(); if(inputAudioDevice != NULL) inputAudioDevice->stop() ; delete inputVideoDevice ; delete videoProcessor ; deleteButtonMap(); // stop and delete timers timerAudioRing->stop(); delete(timerAudioRing); timerVideoRing->stop(); delete(timerVideoRing); } void VOIPChatWidgetHolder::deleteButtonMap(int flags) { button_map::iterator it = buttonMapTakeCall.begin(); while (it != buttonMapTakeCall.end()) { if (((it.key().left(1) == "a") && (flags & RS_VOIP_FLAGS_AUDIO_DATA)) || ((it.key().left(1) == "v") && (flags & RS_VOIP_FLAGS_VIDEO_DATA)) ) { QPair pair = it.value(); delete pair.second; delete pair.first; if (flags & RS_VOIP_FLAGS_AUDIO_DATA) recAudioRingTime = -1; if (flags & RS_VOIP_FLAGS_VIDEO_DATA) recVideoRingTime = -1; it = buttonMapTakeCall.erase(it); } else { ++it; } } } void VOIPChatWidgetHolder::addNewAudioButtonMap(const RsPeerId &peer_id) { if (mChatWidget) { recAudioRingTime = 0; timerAudioRingTimeOut(); QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); if (buttonName.isEmpty()) buttonName = QString::fromStdString(peer_id.toStdString().c_str()); if (buttonName.isEmpty()) buttonName = "VoIP"; button_map::iterator it = buttonMapTakeCall.find(QString("a").append(buttonName)); if (it == buttonMapTakeCall.end()){ mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 inviting you to start an audio conversation. Do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); RSButtonOnText *buttonT = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Audio Call")); buttonT->setToolTip(tr("Activate audio")); buttonT->setStyleSheet(QString("border: 1px solid #199909;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #22c70d, stop: 1 #116a06);") ); buttonT->updateImage(); connect(buttonT,SIGNAL(clicked()),this,SLOT(startAudioCapture())); connect(buttonT,SIGNAL(mouseEnter()),this,SLOT(botMouseEnterTake())); connect(buttonT,SIGNAL(mouseLeave()),this,SLOT(botMouseLeaveTake())); RSButtonOnText *buttonD = mChatWidget->getNewButtonOnTextBrowser(tr("Decline Audio Call")); buttonD->setToolTip(tr("Refuse audio call")); buttonD->setStyleSheet(QString("border: 1px solid #6a1106;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #c7220d, stop: 1 #6a1106);") ); buttonD->updateImage(); connect(buttonD,SIGNAL(clicked()),this,SLOT(hangupCallAudio())); connect(buttonD,SIGNAL(mouseEnter()),this,SLOT(botMouseEnterDecline())); connect(buttonD,SIGNAL(mouseLeave()),this,SLOT(botMouseLeaveDecline())); buttonMapTakeCall.insert(QString("a").append(buttonName), QPair(buttonT, buttonD)); } } } void VOIPChatWidgetHolder::addNewVideoButtonMap(const RsPeerId &peer_id) { if (mChatWidget) { recVideoRingTime = 0; timerVideoRingTimeOut(); QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); if (buttonName.isEmpty()) buttonName = QString::fromStdString(peer_id.toStdString().c_str()); if (buttonName.isEmpty()) buttonName = "VoIP"; button_map::iterator it = buttonMapTakeCall.find(QString("v").append(buttonName)); if (it == buttonMapTakeCall.end()){ mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 inviting you to start a video conversation. Do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); RSButtonOnText *buttonT = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Video Call")); buttonT->setToolTip(tr("Activate camera")); buttonT->setStyleSheet(QString("border: 1px solid #199909;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #22c70d, stop: 1 #116a06);") ); buttonT->updateImage(); connect(buttonT,SIGNAL(clicked()),this,SLOT(startVideoCapture())); connect(buttonT,SIGNAL(mouseEnter()),this,SLOT(botMouseEnterTake())); connect(buttonT,SIGNAL(mouseLeave()),this,SLOT(botMouseLeaveTake())); RSButtonOnText *buttonD = mChatWidget->getNewButtonOnTextBrowser(tr("Decline Video Call")); buttonD->setToolTip(tr("Refuse video call")); buttonD->setStyleSheet(QString("border: 1px solid #6a1106;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #c7220d, stop: 1 #6a1106);") ); buttonD->updateImage(); connect(buttonD,SIGNAL(clicked()),this,SLOT(hangupCallVideo())); connect(buttonD,SIGNAL(mouseEnter()),this,SLOT(botMouseEnterDecline())); connect(buttonD,SIGNAL(mouseLeave()),this,SLOT(botMouseLeaveDecline())); buttonMapTakeCall.insert(QString("v").append(buttonName), QPair(buttonT, buttonD)); } } } bool VOIPChatWidgetHolder::eventFilter(QObject *obj, QEvent *event) { if (obj == fullScreenFrame) { if (event->type() == QEvent::Close || event->type() == QEvent::MouseButtonDblClick) { showNormalView(); } if (event->type() == QEvent::Resize) { replaceFullscreenWidget(); } } // pass the event on to the parent class return QObject::eventFilter(obj, event); } void VOIPChatWidgetHolder::hangupCall() { hangupCallAudio(); hangupCallVideo(); hangupButton->hide(); hangupButtonFS->hide(); deleteButtonMap(); } void VOIPChatWidgetHolder::hangupCallAudio() { bool atLeastOneChecked = false; if (audioCaptureToggleButton->isChecked()) { audioCaptureToggleButton->setChecked(false); toggleAudioCapture(); atLeastOneChecked = true; } if (!atLeastOneChecked) { //Decline button ,Friend hang up or chat close if (recAudioRingTime != -1) { rsVOIP->sendVoipHangUpCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_AUDIO_DATA); deleteButtonMap(RS_VOIP_FLAGS_AUDIO_DATA); } sendAudioRingTime = -1; recAudioRingTime = -1; } } void VOIPChatWidgetHolder::hangupCallVideo() { bool atLeastOneChecked = false; if (videoCaptureToggleButton->isChecked()) { videoCaptureToggleButton->setChecked(false); toggleVideoCapture(); atLeastOneChecked = true; } if (fullscreenToggleButton->isChecked()) { fullscreenToggleButton->setChecked(false); toggleFullScreen(); atLeastOneChecked = true; } if (hideChatTextToggleButton->isChecked()) { hideChatTextToggleButton->setChecked(false); toggleHideChatText(); atLeastOneChecked = true; } if (!atLeastOneChecked) { //Decline button ,Friend hang up or chat close if (recVideoRingTime != -1) { rsVOIP->sendVoipHangUpCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_VIDEO_DATA); deleteButtonMap(RS_VOIP_FLAGS_VIDEO_DATA); } sendVideoRingTime = -1; recVideoRingTime = -1; } } void VOIPChatWidgetHolder::toggleAudioListenFS() { audioListenToggleButton->setChecked(audioListenToggleButtonFS->isChecked()); toggleAudioListen(); } void VOIPChatWidgetHolder::toggleAudioListen() { if (audioListenToggleButton->isChecked()) { audioListenToggleButton->setToolTip(tr("Mute yourself")); } else { audioListenToggleButton->setToolTip(tr("Unmute yourself")); //audioListenToggleButton->setChecked(false); /*if (outputAudioDevice) { outputAudioDevice->stop(); }*/ } audioListenToggleButtonFS->setChecked(audioListenToggleButton->isChecked()); audioListenToggleButtonFS->setToolTip(audioListenToggleButton->toolTip()); } void VOIPChatWidgetHolder::startAudioCapture() { recAudioRingTime = -2; audioCaptureToggleButton->setChecked(true); toggleAudioCapture(); } void VOIPChatWidgetHolder::toggleAudioCaptureFS() { audioCaptureToggleButton->setChecked(audioCaptureToggleButtonFS->isChecked()); toggleAudioCapture(); } void VOIPChatWidgetHolder::toggleAudioCapture() { if (audioCaptureToggleButton->isChecked()) { if (recAudioRingTime == -1) { if (sendAudioRingTime == -1) { sendAudioRingTime = 0; timerAudioRingTimeOut(); rsVOIP->sendVoipRinging(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_AUDIO_DATA); return; //Start Audio when accept received } } if (recAudioRingTime != -1) rsVOIP->sendVoipAcceptCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_AUDIO_DATA); recAudioRingTime = -1; //Stop ringing //activate buttons audioListenToggleButton->setEnabled(true); audioListenToggleButton->setChecked(true); audioListenToggleButtonFS->setEnabled(true); audioListenToggleButtonFS->setChecked(true); audioCaptureToggleButton->setToolTip(tr("Hold Call")); hangupButton->show(); hangupButtonFS->show(); //activate audio input if (!inputAudioProcessor) { inputAudioProcessor = new QtSpeex::SpeexInputProcessor(); if (outputAudioProcessor) { connect(outputAudioProcessor, SIGNAL(playingFrame(QByteArray*)), inputAudioProcessor, SLOT(addEchoFrame(QByteArray*))); } inputAudioProcessor->open(QIODevice::WriteOnly | QIODevice::Unbuffered); } if (!inputAudioDevice) { inputAudioDevice = AudioDeviceHelper::getPreferedInputDevice(); } connect(inputAudioProcessor, SIGNAL(networkPacketReady()), this, SLOT(sendAudioData())); inputAudioDevice->start(inputAudioProcessor); //send system message if (mChatWidget) mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime(), tr("Outgoing Call is started..."), ChatWidget::MSGTYPE_SYSTEM); deleteButtonMap(RS_VOIP_FLAGS_AUDIO_DATA); } else { //desactivate buttons audioListenToggleButton->setEnabled(false); audioListenToggleButton->setChecked(false); audioListenToggleButtonFS->setEnabled(false); audioListenToggleButtonFS->setChecked(false); audioCaptureToggleButton->setToolTip(tr("Resume Call")); if (!videoCaptureToggleButton->isChecked()) { hangupButton->hide(); hangupButtonFS->hide(); } if (recAudioRingTime <= -1){ //desactivate audio input disconnect(inputAudioProcessor, SIGNAL(networkPacketReady()), this, SLOT(sendAudioData())); if (inputAudioDevice) { inputAudioDevice->stop(); } //send system message if (mChatWidget) mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("Outgoing Audio Call stopped."), ChatWidget::MSGTYPE_SYSTEM); rsVOIP->sendVoipHangUpCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_AUDIO_DATA); } sendAudioRingTime = -1; recAudioRingTime = -1; } audioCaptureToggleButtonFS->setChecked(audioCaptureToggleButton->isChecked()); audioCaptureToggleButtonFS->setToolTip(audioCaptureToggleButton->toolTip()); } void VOIPChatWidgetHolder::startVideoCapture() { recVideoRingTime = -2; videoCaptureToggleButton->setChecked(true); toggleVideoCapture(); } void VOIPChatWidgetHolder::toggleVideoCaptureFS() { videoCaptureToggleButton->setChecked(videoCaptureToggleButtonFS->isChecked()); toggleVideoCapture(); } void VOIPChatWidgetHolder::toggleVideoCapture() { if (videoCaptureToggleButton->isChecked()) { if (recVideoRingTime == -1) { if (sendVideoRingTime == -1) { sendVideoRingTime = 0; timerVideoRingTimeOut(); rsVOIP->sendVoipRinging(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_VIDEO_DATA); return; //Start Video when accept received } } if (recVideoRingTime != -1) rsVOIP->sendVoipAcceptCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_VIDEO_DATA); recVideoRingTime = -1; //Stop ringing //activate buttons hideChatTextToggleButton->setEnabled(true); fullscreenToggleButton->setEnabled(true); fullscreenToggleButtonFS->setEnabled(true); videoCaptureToggleButton->setToolTip(tr("Shut camera off")); hangupButton->show(); hangupButtonFS->show(); //activate video input videoWidget->show(); inputVideoDevice->start() ; //send system message if (mChatWidget) mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("You're now sending video..."), ChatWidget::MSGTYPE_SYSTEM); deleteButtonMap(RS_VOIP_FLAGS_VIDEO_DATA); } else { //desactivate buttons hideChatTextToggleButton->setEnabled(false); hideChatTextToggleButton->setChecked(false); toggleHideChatText(); fullscreenToggleButton->setEnabled(false); fullscreenToggleButton->setChecked(false); fullscreenToggleButtonFS->setEnabled(false); fullscreenToggleButtonFS->setChecked(false); toggleFullScreen(); videoCaptureToggleButton->setToolTip(tr("Activate camera")); if (!audioCaptureToggleButton->isChecked()) { hangupButton->hide(); hangupButtonFS->hide(); } if (recVideoRingTime<=-1){ //desactivate video input inputVideoDevice->stop() ; outputVideoDevice->showFrameOff(); videoWidget->hide(); //send system message if (mChatWidget) mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("Video call stopped"), ChatWidget::MSGTYPE_SYSTEM); rsVOIP->sendVoipHangUpCall(mChatWidget->getChatId().toPeerId(), RS_VOIP_FLAGS_VIDEO_DATA); } sendVideoRingTime = -1; recVideoRingTime = -1; } videoCaptureToggleButtonFS->setChecked(videoCaptureToggleButton->isChecked()); videoCaptureToggleButtonFS->setToolTip(videoCaptureToggleButton->toolTip()); } void VOIPChatWidgetHolder::addVideoData(const RsPeerId &peer_id, QByteArray* array) { sendVideoRingTime = -2;//Receive Video so Accepted if (!videoCaptureToggleButton->isChecked()) { addNewVideoButtonMap(peer_id); return; } RsVOIPDataChunk chunk ; chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; chunk.size = array->size() ; chunk.data = array->data() ; videoProcessor->receiveEncodedData(chunk) ; } void VOIPChatWidgetHolder::toggleHideChatText() { QBoxLayout *layout = static_cast(videoWidget->layout()); if (hideChatTextToggleButton->isChecked()) { mChatWidget->hideChatText(true); if (layout) layout->setDirection(QBoxLayout::LeftToRight); hideChatTextToggleButton->setToolTip(tr("Show Chat Text")); } else { mChatWidget->hideChatText(false); if (layout) layout->setDirection(QBoxLayout::TopToBottom); hideChatTextToggleButton->setToolTip(tr("Hide Chat Text")); fullscreenToggleButton->setChecked(false); toggleFullScreen(); } } void VOIPChatWidgetHolder::toggleFullScreenFS() { fullscreenToggleButton->setChecked(fullscreenToggleButtonFS->isChecked()); toggleFullScreen(); } void VOIPChatWidgetHolder::toggleFullScreen() { if (fullscreenToggleButton->isChecked()) { fullscreenToggleButton->setToolTip(tr("Return to normal view.")); inputVideoDevice->setEchoVideoTarget(echoVideoDeviceFS) ; videoProcessor->setDisplayTarget(outputVideoDeviceFS) ; fullScreenFrame->show(); } else { mChatWidget->hideChatText(false); fullscreenToggleButton->setToolTip(tr("Fullscreen mode")); inputVideoDevice->setEchoVideoTarget(echoVideoDevice) ; videoProcessor->setDisplayTarget(outputVideoDevice) ; fullScreenFrame->hide(); } fullscreenToggleButtonFS->setChecked(fullscreenToggleButton->isChecked()); fullscreenToggleButtonFS->setToolTip(fullscreenToggleButton->toolTip()); } void VOIPChatWidgetHolder::replaceFullscreenWidget() { if (QSize(toolBarFS->geometry().size() - fullScreenFrame->geometry().size()).isValid()){ QRect fsRect = fullScreenFrame->geometry(); fsRect.setSize(toolBarFS->geometry().size()); fullScreenFrame->setGeometry(fsRect); } outputVideoDeviceFS->setGeometry(QRect(QPoint(0,0),fullScreenFrame->geometry().size())); echoVideoDeviceFS->setGeometry(QRect(QPoint(fullScreenFrame->width(), fullScreenFrame->height()) - QPoint(320,240), QSize(320,240))); QRect toolBarFSGeo = QRect( (fullScreenFrame->width() - toolBarFS->geometry().width()) / 2 , fullScreenFrame->height() - (toolBarFS->geometry().height() * 2) , toolBarFS->geometry().width(), toolBarFS->geometry().height()); toolBarFS->setGeometry(toolBarFSGeo); if (!videoCaptureToggleButton->isChecked()) { outputVideoDeviceFS->showFrameOff(); echoVideoDeviceFS->showFrameOff(); } } void VOIPChatWidgetHolder::showNormalView() { hideChatTextToggleButton->setChecked(false); toggleHideChatText(); fullscreenToggleButton->setChecked(false); fullscreenToggleButtonFS->setChecked(false); toggleFullScreen(); } void VOIPChatWidgetHolder::botMouseEnterTake() { RSButtonOnText *source = qobject_cast(QObject::sender()); if (source){ source->setStyleSheet(QString("border: 1px solid #333333;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #444444, stop: 1 #222222);") ); //source->setDown(true); } } void VOIPChatWidgetHolder::botMouseLeaveTake() { RSButtonOnText *source = qobject_cast(QObject::sender()); if (source){ source->setStyleSheet(QString("border: 1px solid #116a06;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #22c70d, stop: 1 #116a06);") ); //source->setDown(false); } } void VOIPChatWidgetHolder::botMouseEnterDecline() { RSButtonOnText *source = qobject_cast(QObject::sender()); if (source){ source->setStyleSheet(QString("border: 1px solid #333333;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #444444, stop: 1 #222222);") ); //source->setDown(true); } } void VOIPChatWidgetHolder::botMouseLeaveDecline() { RSButtonOnText *source = qobject_cast(QObject::sender()); if (source){ source->setStyleSheet(QString("border: 1px solid #6a1106;") .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") .append("padding: 3px;") .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #c7220d, stop: 1 #6a1106);") ); //source->setDown(false); } } void VOIPChatWidgetHolder::setAcceptedBandwidth(uint32_t bytes_per_sec) { videoProcessor->setMaximumBandwidth(bytes_per_sec) ; } void VOIPChatWidgetHolder::addAudioData(const RsPeerId &peer_id, QByteArray* array) { sendAudioRingTime = -2;//Receive Audio so Accepted if (!audioCaptureToggleButton->isChecked()) { addNewAudioButtonMap(peer_id); return; } if (!outputAudioDevice) { outputAudioDevice = AudioDeviceHelper::getDefaultOutputDevice(); } if (!outputAudioProcessor) { //start output audio device outputAudioProcessor = new QtSpeex::SpeexOutputProcessor(); if (inputAudioProcessor) { connect(outputAudioProcessor, SIGNAL(playingFrame(QByteArray*)), inputAudioProcessor, SLOT(addEchoFrame(QByteArray*))); } outputAudioProcessor->open(QIODevice::ReadOnly | QIODevice::Unbuffered); outputAudioDevice->start(outputAudioProcessor); } if (outputAudioDevice && outputAudioDevice->error() != QAudio::NoError) { std::cerr << "Restarting output device. Error before reset " << outputAudioDevice->error() << " buffer size : " << outputAudioDevice->bufferSize() << std::endl; outputAudioDevice->stop(); outputAudioDevice->reset(); if (outputAudioDevice->error() == QAudio::UnderrunError) outputAudioDevice->setBufferSize(20); outputAudioDevice->start(outputAudioProcessor); } outputAudioProcessor->putNetworkPacket(QString::fromStdString(peer_id.toStdString()), *array); //check the input device for errors if (inputAudioDevice && inputAudioDevice->error() != QAudio::NoError) { std::cerr << "Restarting input device. Error before reset " << inputAudioDevice->error() << std::endl; inputAudioDevice->stop(); inputAudioDevice->reset(); inputAudioDevice->start(inputAudioProcessor); } } void VOIPChatWidgetHolder::sendVideoData() { RsVOIPDataChunk chunk ; while(inputVideoDevice && inputVideoDevice->getNextEncodedPacket(chunk)) rsVOIP->sendVoipData(mChatWidget->getChatId().toPeerId(),chunk) ; } void VOIPChatWidgetHolder::sendAudioData() { while(inputAudioProcessor && inputAudioProcessor->hasPendingPackets()) { QByteArray qbarray = inputAudioProcessor->getNetworkPacket(); RsVOIPDataChunk chunk; chunk.size = qbarray.size(); chunk.data = (void*)qbarray.constData(); chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_AUDIO ; rsVOIP->sendVoipData(mChatWidget->getChatId().toPeerId(),chunk); } } void VOIPChatWidgetHolder::updateStatus(int status) { bool enabled = (status != RS_STATUS_OFFLINE); audioListenToggleButton->setEnabled(audioCaptureToggleButton->isChecked() && enabled); audioListenToggleButtonFS->setEnabled(audioCaptureToggleButton->isChecked() && enabled); audioCaptureToggleButton->setEnabled(enabled); audioCaptureToggleButtonFS->setEnabled(enabled); videoCaptureToggleButton->setEnabled(enabled); videoCaptureToggleButtonFS->setEnabled(enabled); hideChatTextToggleButton->setEnabled(videoCaptureToggleButton->isChecked() && enabled); fullscreenToggleButton->setEnabled(videoCaptureToggleButton->isChecked() && enabled); fullscreenToggleButtonFS->setEnabled(videoCaptureToggleButton->isChecked() && enabled); hangupButton->setEnabled(enabled); hangupButtonFS->setEnabled(enabled); } void VOIPChatWidgetHolder::ReceivedInvitation(const RsPeerId &peer_id, int flags) { switch(flags){ case RS_VOIP_FLAGS_AUDIO_DATA: { if (audioCaptureToggleButton->isChecked()) { if (recAudioRingTime != -1) toggleAudioCapture(); } else { addNewAudioButtonMap(peer_id); } } break; case RS_VOIP_FLAGS_VIDEO_DATA: { if (videoCaptureToggleButton->isChecked()) { if (recVideoRingTime != -1) toggleVideoCapture(); } else { addNewVideoButtonMap(peer_id); } } break; default: std::cerr << "VOIPChatWidgetHolder::ReceivedInvitation(): Received unknown flags item # " << flags << ": not handled yet ! Sorry" << std::endl; break ; } } void VOIPChatWidgetHolder::ReceivedVoipHangUp(const RsPeerId &peer_id, int flags) { switch(flags){ case RS_VOIP_FLAGS_AUDIO_DATA | RS_VOIP_FLAGS_VIDEO_DATA: { if (mChatWidget) { if (videoCaptureToggleButton->isChecked() || audioCaptureToggleButton->isChecked()) { QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 hang up. Your call is closed.").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); } hangupCall(); } } break; case RS_VOIP_FLAGS_AUDIO_DATA: { if (mChatWidget) { if (audioCaptureToggleButton->isChecked()) { QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 hang up. Your audio call is closed.").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); } hangupCallAudio(); } } break; case RS_VOIP_FLAGS_VIDEO_DATA: { if (mChatWidget) { if (videoCaptureToggleButton->isChecked()) { QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 hang up. Your video call is closed.").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); } hangupCallVideo(); } } break; default: std::cerr << "VOIPChatWidgetHolder::ReceivedVoipHangUp(): Received unknown flags item # " << flags << ": not handled yet ! Sorry" << std::endl; break ; } //deleteButtonMap(); } void VOIPChatWidgetHolder::ReceivedVoipAccept(const RsPeerId &peer_id, int flags) { switch(flags){ case RS_VOIP_FLAGS_AUDIO_DATA: { if (mChatWidget) { sendAudioRingTime = -2; QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 accepted your audio call.").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); if (audioCaptureToggleButton->isChecked()) toggleAudioCapture(); } } break; case RS_VOIP_FLAGS_VIDEO_DATA: { if (mChatWidget) { sendVideoRingTime = -2; QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("%1 accepted your video call.").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); if (videoCaptureToggleButton->isChecked()) toggleVideoCapture(); } } break; default: std::cerr << "VOIPChatWidgetHolder::ReceivedVoipHangUp(): Received unknown flags item # " << flags << ": not handled yet ! Sorry" << std::endl; break ; } } void VOIPChatWidgetHolder::timerAudioRingTimeOut() { //Sending or receiving (-2 connected, -1 reseted, >=0 in progress) if (sendAudioRingTime >= 0) { //Sending ++sendAudioRingTime; if (sendAudioRingTime == 100) sendAudioRingTime = 0; pbAudioRing->setValue(sendAudioRingTime); pbAudioRing->setToolTip(tr("Waiting your friend respond your audio call.")); pbAudioRing->setVisible(true); if (time(NULL) > lastTimePlayOccurs) { soundManager->play(VOIP_SOUND_OUTGOING_AUDIO_CALL); lastTimePlayOccurs = time(NULL) + 1; } timerAudioRing->start(); } else if(recAudioRingTime >= 0) { //Receiving ++recAudioRingTime; if (recAudioRingTime == 100) recAudioRingTime = 0; pbAudioRing->setValue(recAudioRingTime); pbAudioRing->setToolTip(tr("Your friend is calling you for audio. Respond.")); pbAudioRing->setVisible(true); //launch an animation. Don't launch it if already animating if (!audioCaptureToggleButton->graphicsEffect() || (audioCaptureToggleButton->graphicsEffect()->inherits("QGraphicsOpacityEffect") && ((QGraphicsOpacityEffect*)audioCaptureToggleButton->graphicsEffect())->opacity() == 1) ) { QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(audioListenToggleButton); audioCaptureToggleButton->setGraphicsEffect(effect); QPropertyAnimation *anim = new QPropertyAnimation(effect, "opacity", effect); anim->setStartValue(1); anim->setKeyValueAt(0.5,0); anim->setEndValue(1); anim->setDuration(timerAudioRing->interval()); anim->start(); } audioCaptureToggleButton->setToolTip(tr("Answer")); if (time(NULL) > lastTimePlayOccurs) { soundManager->play(VOIP_SOUND_INCOMING_AUDIO_CALL); lastTimePlayOccurs = time(NULL) + 1; } if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipAudioCall(mChatWidget->getChatId().toPeerId()); timerAudioRing->start(); } else { //Nothing to do, reset stat pbAudioRing->setHidden(true); pbAudioRing->setValue(0); pbAudioRing->setToolTip(""); audioCaptureToggleButton->setGraphicsEffect(0); } } void VOIPChatWidgetHolder::timerVideoRingTimeOut() { //Sending or receiving (-2 connected, -1 reseted, >=0 in progress) if (sendVideoRingTime >= 0) { //Sending ++sendVideoRingTime; if (sendVideoRingTime == 100) sendVideoRingTime = 0; pbVideoRing->setValue(sendVideoRingTime); pbVideoRing->setToolTip(tr("Waiting your friend respond your video call.")); pbVideoRing->setVisible(true); if (time(NULL) > lastTimePlayOccurs) { soundManager->play(VOIP_SOUND_OUTGOING_VIDEO_CALL); lastTimePlayOccurs = time(NULL) + 1; } timerVideoRing->start(); } else if(recVideoRingTime >= 0) { //Receiving ++recVideoRingTime; if (recVideoRingTime == 100) recVideoRingTime = 0; pbVideoRing->setValue(recVideoRingTime); pbVideoRing->setToolTip(tr("Your friend is calling you for video. Respond.")); pbVideoRing->setVisible(true); //launch an animation. Don't launch it if already animating if (!videoCaptureToggleButton->graphicsEffect() || (videoCaptureToggleButton->graphicsEffect()->inherits("QGraphicsOpacityEffect") && ((QGraphicsOpacityEffect*)videoCaptureToggleButton->graphicsEffect())->opacity() == 1) ) { QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(audioListenToggleButton); videoCaptureToggleButton->setGraphicsEffect(effect); QPropertyAnimation *anim = new QPropertyAnimation(effect, "opacity", effect); anim->setStartValue(1); anim->setKeyValueAt(0.5,0); anim->setEndValue(1); anim->setDuration(timerVideoRing->interval()); anim->start(); } videoCaptureToggleButton->setToolTip(tr("Answer")); if (time(NULL) > lastTimePlayOccurs) { soundManager->play(VOIP_SOUND_INCOMING_VIDEO_CALL); lastTimePlayOccurs = time(NULL) + 1; } if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipVideoCall(mChatWidget->getChatId().toPeerId()); timerVideoRing->start(); } else { //Nothing to do, reset stat pbVideoRing->setHidden(true); pbVideoRing->setValue(0); pbVideoRing->setToolTip(""); videoCaptureToggleButton->setGraphicsEffect(0); } }