2014-07-13 09:57:25 -04:00
# include <QToolButton>
# include <QPropertyAnimation>
# include <QIcon>
# include <QLayout>
# include <gui/audiodevicehelper.h>
# include "interface/rsvoip.h"
# include "gui/SoundManager.h"
# include "util/HandleRichText.h"
# include "gui/common/StatusDefs.h"
# include "gui/chat/ChatWidget.h"
# include "VOIPChatWidgetHolder.h"
# include "VideoProcessor.h"
# include "QVideoDevice.h"
# include <retroshare/rsstatus.h>
2014-12-19 07:17:58 -05:00
# define CALL_START ": / images / call-start.png"
# define CALL_STOP ": / images / call-stop.png"
# define CALL_HOLD ": / images / call-hold.png"
2014-07-13 09:57:25 -04:00
VOIPChatWidgetHolder : : VOIPChatWidgetHolder ( ChatWidget * chatWidget )
: QObject ( ) , ChatWidgetHolder ( chatWidget )
{
QIcon icon ;
2014-12-19 07:17:58 -05:00
icon . addPixmap ( QPixmap ( " :/images/audio-volume-muted.png " ) ) ;
icon . addPixmap ( QPixmap ( " :/images/audio-volume-high.png " ) , QIcon : : Normal , QIcon : : On ) ;
icon . addPixmap ( QPixmap ( " :/images/audio-volume-high.png " ) , QIcon : : Disabled , QIcon : : On ) ;
icon . addPixmap ( QPixmap ( " :/images/audio-volume-high.png " ) , QIcon : : Active , QIcon : : On ) ;
icon . addPixmap ( QPixmap ( " :/images/audio-volume-high.png " ) , QIcon : : Selected , QIcon : : On ) ;
2014-07-13 09:57:25 -04:00
audioListenToggleButton = new QToolButton ;
audioListenToggleButton - > setIcon ( icon ) ;
2014-12-19 12:41:34 -05:00
audioListenToggleButton - > setIconSize ( QSize ( 42 , 42 ) ) ;
2014-07-13 09:57:25 -04:00
audioListenToggleButton - > setAutoRaise ( true ) ;
audioListenToggleButton - > setCheckable ( true ) ;
2014-12-19 12:41:34 -05:00
audioListenToggleButton - > setMinimumSize ( QSize ( 44 , 44 ) ) ;
audioListenToggleButton - > setMaximumSize ( QSize ( 44 , 44 ) ) ;
2014-07-13 09:57:25 -04:00
audioListenToggleButton - > setText ( QString ( ) ) ;
audioListenToggleButton - > setToolTip ( tr ( " Mute " ) ) ;
QIcon icon2 ;
2014-12-19 07:17:58 -05:00
icon2 . addPixmap ( QPixmap ( " :/images/call-start.png " ) ) ;
icon2 . addPixmap ( QPixmap ( " :/images/call-hold.png " ) , QIcon : : Normal , QIcon : : On ) ;
icon2 . addPixmap ( QPixmap ( " :/images/call-hold.png " ) , QIcon : : Disabled , QIcon : : On ) ;
icon2 . addPixmap ( QPixmap ( " :/images/call-hold.png " ) , QIcon : : Active , QIcon : : On ) ;
icon2 . addPixmap ( QPixmap ( " :/images/call-hold.png " ) , QIcon : : Selected , QIcon : : On ) ;
2014-07-13 09:57:25 -04:00
audioCaptureToggleButton = new QToolButton ;
2014-12-19 12:41:34 -05:00
audioCaptureToggleButton - > setMinimumSize ( QSize ( 44 , 44 ) ) ;
audioCaptureToggleButton - > setMaximumSize ( QSize ( 44 , 44 ) ) ;
2014-07-13 09:57:25 -04:00
audioCaptureToggleButton - > setText ( QString ( ) ) ;
audioCaptureToggleButton - > setToolTip ( tr ( " Start Call " ) ) ;
audioCaptureToggleButton - > setIcon ( icon2 ) ;
2014-12-19 12:41:34 -05:00
audioCaptureToggleButton - > setIconSize ( QSize ( 42 , 42 ) ) ;
2014-07-13 09:57:25 -04:00
audioCaptureToggleButton - > setAutoRaise ( true ) ;
audioCaptureToggleButton - > setCheckable ( true ) ;
2014-12-19 07:17:58 -05:00
hangupButton = new QToolButton ;
hangupButton - > setIcon ( QIcon ( " :/images/call-stop.png " ) ) ;
2014-12-19 12:41:34 -05:00
hangupButton - > setIconSize ( QSize ( 42 , 42 ) ) ;
hangupButton - > setMinimumSize ( QSize ( 44 , 44 ) ) ;
hangupButton - > setMaximumSize ( QSize ( 44 , 44 ) ) ;
2014-12-19 07:17:58 -05:00
hangupButton - > setCheckable ( false ) ;
hangupButton - > setAutoRaise ( true ) ;
hangupButton - > setText ( QString ( ) ) ;
hangupButton - > setToolTip ( tr ( " Hangup Call " ) ) ;
hangupButton - > hide ( ) ;
2014-07-13 09:57:25 -04:00
QIcon icon3 ;
2014-09-21 08:31:16 -04:00
icon3 . addPixmap ( QPixmap ( " :/images/video-icon-on.png " ) ) ;
icon3 . addPixmap ( QPixmap ( " :/images/video-icon-off.png " ) , QIcon : : Normal , QIcon : : On ) ;
icon3 . addPixmap ( QPixmap ( " :/images/video-icon-off.png " ) , QIcon : : Disabled , QIcon : : On ) ;
icon3 . addPixmap ( QPixmap ( " :/images/video-icon-off.png " ) , QIcon : : Active , QIcon : : On ) ;
icon3 . addPixmap ( QPixmap ( " :/images/video-icon-off.png " ) , QIcon : : Selected , QIcon : : On ) ;
2014-07-13 09:57:25 -04:00
videoCaptureToggleButton = new QToolButton ;
2014-12-19 12:41:34 -05:00
videoCaptureToggleButton - > setMinimumSize ( QSize ( 44 , 44 ) ) ;
videoCaptureToggleButton - > setMaximumSize ( QSize ( 44 , 44 ) ) ;
2014-07-13 09:57:25 -04:00
videoCaptureToggleButton - > setText ( QString ( ) ) ;
2014-08-13 09:19:22 -04:00
videoCaptureToggleButton - > setToolTip ( tr ( " Start Video Call " ) ) ;
2014-07-13 09:57:25 -04:00
videoCaptureToggleButton - > setIcon ( icon3 ) ;
2014-12-19 12:41:34 -05:00
videoCaptureToggleButton - > setIconSize ( QSize ( 42 , 42 ) ) ;
2014-07-13 09:57:25 -04:00
videoCaptureToggleButton - > setAutoRaise ( true ) ;
videoCaptureToggleButton - > setCheckable ( true ) ;
connect ( videoCaptureToggleButton , SIGNAL ( clicked ( ) ) , this , SLOT ( toggleVideoCapture ( ) ) ) ;
connect ( audioListenToggleButton , SIGNAL ( clicked ( ) ) , this , SLOT ( toggleAudioListen ( ) ) ) ;
connect ( audioCaptureToggleButton , SIGNAL ( clicked ( ) ) , this , SLOT ( toggleAudioCapture ( ) ) ) ;
connect ( hangupButton , SIGNAL ( clicked ( ) ) , this , SLOT ( hangupCall ( ) ) ) ;
2014-12-19 07:17:58 -05:00
mChatWidget - > addVOIPBarWidget ( audioListenToggleButton ) ;
mChatWidget - > addVOIPBarWidget ( audioCaptureToggleButton ) ;
mChatWidget - > addVOIPBarWidget ( hangupButton ) ;
mChatWidget - > addVOIPBarWidget ( videoCaptureToggleButton ) ;
2014-07-13 09:57:25 -04:00
outputAudioProcessor = NULL ;
outputAudioDevice = NULL ;
inputAudioProcessor = NULL ;
inputAudioDevice = NULL ;
inputVideoDevice = new QVideoInputDevice ( mChatWidget ) ; // not started yet ;-)
inputVideoProcessor = new JPEGVideoEncoder ;
outputVideoProcessor = new JPEGVideoDecoder ;
// Make a widget with two video devices, one for echo, and one for the talking peer.
videoWidget = new QWidget ( mChatWidget ) ;
2014-12-04 08:49:04 -05:00
videoWidget - > setLayout ( new QVBoxLayout ( ) ) ;
2014-07-13 09:57:25 -04:00
videoWidget - > layout ( ) - > addWidget ( outputVideoDevice = new QVideoOutputDevice ( videoWidget ) ) ;
2014-12-06 09:21:36 -05:00
videoWidget - > layout ( ) - > addWidget ( echoVideoDevice = new QVideoOutputDevice ( videoWidget ) ) ;
2014-09-20 12:28:26 -04:00
videoWidget - > hide ( ) ;
2014-07-13 09:57:25 -04:00
2014-07-15 16:04:31 -04:00
connect ( inputVideoDevice , SIGNAL ( networkPacketReady ( ) ) , this , SLOT ( sendVideoData ( ) ) ) ;
2014-12-04 08:49:04 -05:00
echoVideoDevice - > setMinimumSize ( 320 , 256 ) ;
outputVideoDevice - > setMinimumSize ( 320 , 256 ) ;
2014-12-05 11:47:59 -05:00
echoVideoDevice - > setStyleSheet ( " border: 4px solid #CCCCCC; border-radius: 4px; " ) ;
outputVideoDevice - > setStyleSheet ( " border: 4px solid #CCCCCC; border-radius: 4px; " ) ;
2014-07-13 09:57:25 -04:00
mChatWidget - > addChatHorizontalWidget ( videoWidget ) ;
inputVideoDevice - > setEchoVideoTarget ( echoVideoDevice ) ;
2014-07-15 16:04:31 -04:00
inputVideoDevice - > setVideoEncoder ( inputVideoProcessor ) ;
2014-07-13 09:57:25 -04:00
outputVideoProcessor - > setDisplayTarget ( outputVideoDevice ) ;
}
VOIPChatWidgetHolder : : ~ VOIPChatWidgetHolder ( )
{
if ( inputAudioDevice ! = NULL )
inputAudioDevice - > stop ( ) ;
delete inputVideoDevice ;
delete inputVideoProcessor ;
delete outputVideoProcessor ;
2015-03-21 17:25:17 -04:00
button_map : : iterator it = buttonMapTakeVideo . begin ( ) ;
while ( it ! = buttonMapTakeVideo . end ( ) ) {
it = buttonMapTakeVideo . erase ( it ) ;
}
2014-07-13 09:57:25 -04:00
}
void VOIPChatWidgetHolder : : toggleAudioListen ( )
{
if ( audioListenToggleButton - > isChecked ( ) ) {
audioListenToggleButton - > setToolTip ( tr ( " Mute yourself " ) ) ;
} else {
audioListenToggleButton - > setToolTip ( tr ( " Unmute yourself " ) ) ;
//audioListenToggleButton->setChecked(false);
/*if (outputAudioDevice) {
outputAudioDevice - > stop ( ) ;
} */
}
}
void VOIPChatWidgetHolder : : hangupCall ( )
{
2014-07-20 16:50:36 -04:00
disconnect ( inputAudioProcessor , SIGNAL ( networkPacketReady ( ) ) , this , SLOT ( sendAudioData ( ) ) ) ;
if ( inputAudioDevice ) {
inputAudioDevice - > stop ( ) ;
}
if ( outputAudioDevice ) {
outputAudioDevice - > stop ( ) ;
}
2014-12-06 09:21:36 -05:00
if ( mChatWidget ) {
mChatWidget - > addChatMsg ( true , tr ( " VoIP Status " ) , QDateTime : : currentDateTime ( ) , QDateTime : : currentDateTime ( ) , tr ( " Outgoing Call stopped. " ) , ChatWidget : : MSGTYPE_SYSTEM ) ;
}
2014-07-20 16:50:36 -04:00
audioListenToggleButton - > setChecked ( false ) ;
audioCaptureToggleButton - > setChecked ( false ) ;
2014-09-20 12:44:26 -04:00
hangupButton - > hide ( ) ;
2014-07-13 09:57:25 -04:00
}
void VOIPChatWidgetHolder : : toggleAudioCapture ( )
{
if ( audioCaptureToggleButton - > isChecked ( ) ) {
//activate audio output
audioListenToggleButton - > setChecked ( true ) ;
audioCaptureToggleButton - > setToolTip ( tr ( " Hold Call " ) ) ;
2014-09-20 12:44:26 -04:00
hangupButton - > show ( ) ;
2014-07-13 09:57:25 -04:00
//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 ) ;
if ( mChatWidget ) {
mChatWidget - > addChatMsg ( true , tr ( " VoIP Status " ) , QDateTime : : currentDateTime ( ) , QDateTime : : currentDateTime ( ) , tr ( " Outgoing Call is started... " ) , ChatWidget : : MSGTYPE_SYSTEM ) ;
}
} else {
disconnect ( inputAudioProcessor , SIGNAL ( networkPacketReady ( ) ) , this , SLOT ( sendAudioData ( ) ) ) ;
if ( inputAudioDevice ) {
inputAudioDevice - > stop ( ) ;
}
audioCaptureToggleButton - > setToolTip ( tr ( " Resume Call " ) ) ;
2014-09-20 12:44:26 -04:00
hangupButton - > hide ( ) ;
2014-07-13 09:57:25 -04:00
}
}
2015-03-21 17:25:17 -04:00
void VOIPChatWidgetHolder : : startVideoCapture ( )
{
videoCaptureToggleButton - > setChecked ( true ) ;
toggleVideoCapture ( ) ;
}
2014-07-13 09:57:25 -04:00
void VOIPChatWidgetHolder : : toggleVideoCapture ( )
{
if ( videoCaptureToggleButton - > isChecked ( ) )
{
//activate video input
//
2014-09-20 12:28:26 -04:00
videoWidget - > show ( ) ;
2014-07-13 09:57:25 -04:00
inputVideoDevice - > start ( ) ;
videoCaptureToggleButton - > setToolTip ( tr ( " Shut camera off " ) ) ;
if ( mChatWidget )
2015-03-21 17:25:17 -04:00
mChatWidget - > addChatMsg ( true , tr ( " VoIP Status " ) , QDateTime : : currentDateTime ( ) , QDateTime : : currentDateTime ( )
, tr ( " You're now sending video... " ) , ChatWidget : : MSGTYPE_SYSTEM ) ;
button_map : : iterator it = buttonMapTakeVideo . begin ( ) ;
while ( it ! = buttonMapTakeVideo . end ( ) ) {
RSButtonOnText * button = it . value ( ) ;
delete button ;
it = buttonMapTakeVideo . erase ( it ) ;
}
2014-07-13 09:57:25 -04:00
}
else
{
2014-07-17 10:13:02 -04:00
inputVideoDevice - > stop ( ) ;
2014-07-13 09:57:25 -04:00
videoCaptureToggleButton - > setToolTip ( tr ( " Activate camera " ) ) ;
2014-07-20 16:50:36 -04:00
outputVideoDevice - > showFrameOff ( ) ;
2014-09-20 12:28:26 -04:00
videoWidget - > hide ( ) ;
2014-12-06 09:21:36 -05:00
if ( mChatWidget )
2015-03-21 17:25:17 -04:00
mChatWidget - > addChatMsg ( true , tr ( " VoIP Status " ) , QDateTime : : currentDateTime ( ) , QDateTime : : currentDateTime ( )
, tr ( " Video call stopped " ) , ChatWidget : : MSGTYPE_SYSTEM ) ;
2014-07-13 09:57:25 -04:00
}
}
2014-07-15 16:04:31 -04:00
void VOIPChatWidgetHolder : : addVideoData ( const QString name , QByteArray * array )
{
outputVideoProcessor - > receiveEncodedData ( ( unsigned char * ) array - > data ( ) , array - > size ( ) ) ;
2015-03-21 17:25:17 -04:00
if ( ! videoCaptureToggleButton - > isChecked ( ) ) {
if ( mChatWidget ) {
QString buttonName = name ;
if ( buttonName . isEmpty ( ) ) buttonName = " VoIP " ; //TODO maybe change all with GxsId
button_map : : iterator it = buttonMapTakeVideo . find ( buttonName ) ;
if ( it = = buttonMapTakeVideo . end ( ) ) {
mChatWidget - > addChatMsg ( true , tr ( " VoIP Status " ) , QDateTime : : currentDateTime ( ) , QDateTime : : currentDateTime ( )
, tr ( " Video call from: %1 " ) . arg ( buttonName ) , ChatWidget : : MSGTYPE_SYSTEM ) ;
RSButtonOnText * button = mChatWidget - > getNewButtonOnTextBrowser ( tr ( " Take Video Call " ) ) ;
button - > setToolTip ( tr ( " Activate camera " ) ) ;
button - > setStyleSheet ( QString ( " background-color: green; " )
. append ( " border-style: outset; " )
. append ( " border-width: 5px; " )
. append ( " border-radius: 5px; " )
. append ( " border-color: beige; " )
) ;
button - > updateImage ( ) ;
connect ( button , SIGNAL ( clicked ( ) ) , this , SLOT ( startVideoCapture ( ) ) ) ;
connect ( button , SIGNAL ( mouseEnter ( ) ) , this , SLOT ( botMouseEnter ( ) ) ) ;
connect ( button , SIGNAL ( mouseLeave ( ) ) , this , SLOT ( botMouseLeave ( ) ) ) ;
buttonMapTakeVideo . insert ( buttonName , button ) ;
}
}
}
}
void VOIPChatWidgetHolder : : botMouseEnter ( )
{
RSButtonOnText * source = qobject_cast < RSButtonOnText * > ( QObject : : sender ( ) ) ;
if ( source ) {
source - > setStyleSheet ( QString ( " background-color: red; " )
. append ( " border-style: outset; " )
. append ( " border-width: 5px; " )
. append ( " border-radius: 5px; " )
. append ( " border-color: beige; " )
) ;
//source->setDown(true);
}
}
void VOIPChatWidgetHolder : : botMouseLeave ( )
{
RSButtonOnText * source = qobject_cast < RSButtonOnText * > ( QObject : : sender ( ) ) ;
if ( source ) {
source - > setStyleSheet ( QString ( " background-color: green; " )
. append ( " border-style: outset; " )
. append ( " border-width: 5px; " )
. append ( " border-radius: 5px; " )
. append ( " border-color: beige; " )
) ;
//source->setDown(false);
}
2014-07-15 16:04:31 -04:00
}
2014-07-20 16:50:36 -04:00
void VOIPChatWidgetHolder : : setAcceptedBandwidth ( const QString name , uint32_t bytes_per_sec )
{
inputVideoProcessor - > setMaximumFrameRate ( bytes_per_sec ) ;
}
2014-07-13 09:57:25 -04:00
void VOIPChatWidgetHolder : : addAudioData ( const QString name , QByteArray * array )
{
if ( ! audioCaptureToggleButton - > isChecked ( ) ) {
//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 " ) ;
anim - > setStartValue ( 1 ) ;
anim - > setKeyValueAt ( 0.5 , 0 ) ;
anim - > setEndValue ( 1 ) ;
anim - > setDuration ( 400 ) ;
anim - > start ( ) ;
}
// soundManager->play(VOIP_SOUND_INCOMING_CALL);
audioCaptureToggleButton - > setToolTip ( tr ( " Answer " ) ) ;
//TODO make a toaster and a sound for the incoming call
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 ( name , * 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 ) ;
}
}
2014-07-15 16:04:31 -04:00
void VOIPChatWidgetHolder : : sendVideoData ( )
{
RsVoipDataChunk chunk ;
while ( inputVideoDevice & & inputVideoDevice - > getNextEncodedPacket ( chunk ) )
2014-12-30 09:26:04 -05:00
rsVoip - > sendVoipData ( mChatWidget - > getChatId ( ) . toPeerId ( ) , chunk ) ;
2014-07-15 16:04:31 -04:00
}
2014-07-13 09:57:25 -04:00
void VOIPChatWidgetHolder : : sendAudioData ( )
{
while ( inputAudioProcessor & & inputAudioProcessor - > hasPendingPackets ( ) ) {
QByteArray qbarray = inputAudioProcessor - > getNetworkPacket ( ) ;
RsVoipDataChunk chunk ;
chunk . size = qbarray . size ( ) ;
chunk . data = ( void * ) qbarray . constData ( ) ;
2014-07-15 16:04:31 -04:00
chunk . type = RsVoipDataChunk : : RS_VOIP_DATA_TYPE_AUDIO ;
2014-12-30 09:26:04 -05:00
rsVoip - > sendVoipData ( mChatWidget - > getChatId ( ) . toPeerId ( ) , chunk ) ;
2014-07-13 09:57:25 -04:00
}
}
void VOIPChatWidgetHolder : : updateStatus ( int status )
{
audioListenToggleButton - > setEnabled ( true ) ;
audioCaptureToggleButton - > setEnabled ( true ) ;
hangupButton - > setEnabled ( true ) ;
switch ( status ) {
case RS_STATUS_OFFLINE :
audioListenToggleButton - > setEnabled ( false ) ;
audioCaptureToggleButton - > setEnabled ( false ) ;
hangupButton - > setEnabled ( false ) ;
break ;
}
}