aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Fabio Bas2010-04-06 11:03:56 +0000
committerGravatar Fabio Bas2010-04-06 11:03:56 +0000
commit2e9a3fd886191137627ecb83bc9c8a4c8d3463c5 (patch)
tree324e257977f64e2e62a7a68f48cd7ecbb1fe5741 /src
parentadded a workaround for the userlist/ircview width problem (diff)
downloadKVIrc-2e9a3fd886191137627ecb83bc9c8a4c8d3463c5.tar.gz
KVIrc-2e9a3fd886191137627ecb83bc9c8a4c8d3463c5.tar.bz2
KVIrc-2e9a3fd886191137627ecb83bc9c8a4c8d3463c5.zip
more work on dcc video: video&&text working in sjpeg; stay away from ogg/theora by now
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@4242 17fca916-40b9-46aa-a4ea-0a15b648b75c
Diffstat (limited to 'src')
-rw-r--r--src/kvilib/ext/kvi_oggtheora.cpp67
-rw-r--r--src/kvilib/ext/kvi_oggtheora.h98
-rw-r--r--src/kvirc/kernel/kvi_userinput.cpp1
-rw-r--r--src/kvirc/kvs/kvi_kvs_coresimplecommands_mr.cpp1
-rw-r--r--src/kvirc/ui/kvi_window.h3
-rw-r--r--src/modules/dcc/codec.cpp92
-rw-r--r--src/modules/dcc/codec.h12
-rw-r--r--src/modules/dcc/libkvidcc.cpp2
-rw-r--r--src/modules/dcc/video.cpp758
-rw-r--r--src/modules/dcc/video.h47
10 files changed, 619 insertions, 462 deletions
diff --git a/src/kvilib/ext/kvi_oggtheora.cpp b/src/kvilib/ext/kvi_oggtheora.cpp
index eecb29773..a234dffaa 100644
--- a/src/kvilib/ext/kvi_oggtheora.cpp
+++ b/src/kvilib/ext/kvi_oggtheora.cpp
@@ -79,6 +79,10 @@ KviTheoraEncoder::KviTheoraEncoder(KviDataBuffer * stream, int iWidth, int iHeig
audio_q=.6f;
samples_sofar=0;
+ //text
+ text=true;
+ text_sofar=0;
+
//user settings
m_pStream=stream;
geometry.pic_w=iWidth;
@@ -125,6 +129,18 @@ KviTheoraEncoder::KviTheoraEncoder(KviDataBuffer * stream, int iWidth, int iHeig
vorbis_block_init(&vd,&vb);
}
+ // initialize out text codec
+ if(text)
+ {
+ ogg_stream_init(&zo,rand());
+ ret = KviOggIrcText::irct_encode_init();
+ if(ret)
+ {
+ qDebug("error initializing irctext");
+ return;
+ }
+ }
+
// Set up Theora encoder
// Theora has a divisible-by-sixteen restriction for the encoded frame size
// scale the picture size up to the nearest /16 and calculate offsets
@@ -196,7 +212,8 @@ KviTheoraEncoder::KviTheoraEncoder(KviDataBuffer * stream, int iWidth, int iHeig
ogg_stream_packetin(&to,&op);
}
- if(audio){
+ if(audio)
+ {
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
@@ -213,6 +230,19 @@ KviTheoraEncoder::KviTheoraEncoder(KviDataBuffer * stream, int iWidth, int iHeig
ogg_stream_packetin(&vo,&header_code);
}
+ if(text)
+ {
+ ogg_packet header;
+ KviOggIrcText::irct_encode_headerout(&header);
+ ogg_stream_packetin(&zo,&header); // automatically placed in its own page
+ if(ogg_stream_pageout(&zo,&og)!=1){
+ qDebug("Internal Ogg library error (irct).");
+ return;
+ }
+ m_pStream->append(og.header,og.header_len);
+ m_pStream->append(og.body,og.body_len);
+ }
+
// Flush the rest of our headers. This ensures the actual data in each stream
// will start on a new page, as per spec.
for(;;){
@@ -320,6 +350,31 @@ void KviTheoraEncoder::addAudioFrame(unsigned char* audioPkt, int audioSize)
audioflag=0;
}
+void KviTheoraEncoder::addTextFrame(unsigned char* textPkt, int textSize)
+{
+ if(!text)
+ return;
+
+ ogg_page textpage;
+ ogg_packet op;
+
+ text_sofar++;
+
+ // is there an audio page flushed? If not, fetch one if possible
+ textflag=KviOggIrcText::irct_encode_packetout((char *) textPkt, textSize, text_sofar,&op);
+ ogg_stream_packetin(&zo, &op);
+ ogg_stream_pageout(&zo, &textpage);
+
+
+
+ // no pages? Must be end of stream.
+ if(!textflag) return;
+
+ m_pStream->append(textpage.header,textpage.header_len);
+ m_pStream->append(textpage.body,textpage.body_len);
+ textflag=0;
+}
+
int KviTheoraEncoder::fetch_and_process_video_packet(quint8 * videoYuv,th_enc_ctx *td,ogg_packet *op)
{
th_ycbcr_buffer ycbcr;
@@ -589,15 +644,20 @@ void KviTheoraDecoder::addData(KviDataBuffer * stream)
/* identify the codec: try theora */
if(!theora_p && th_decode_headerin(&ti,&tc,&ts,&op)>=0){
-// qDebug("is theora, ts=%p &ts=%p",ts, &ts);
+ qDebug("is theora, ts=%p &ts=%p",ts, &ts);
/* it is theora */
memcpy(&to,&test,sizeof(test));
theora_p=1;
}else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
-// qDebug("is vorbis");
+ qDebug("is vorbis");
/* it is vorbis */
memcpy(&vo,&test,sizeof(test));
vorbis_p=1;
+ }else if(!irct_p && KviOggIrcText::irct_decode_headerin(&op)>=0){
+ qDebug("is irct");
+ /* it is irct */
+ memcpy(&zo,&test,sizeof(test));
+ irct_p=1;
}else{
// qDebug("is other");
/* whatever it is, we don't care about it */
@@ -885,6 +945,7 @@ int KviTheoraDecoder::queue_page(ogg_page *page)
{
if(theora_p)ogg_stream_pagein(&to,page);
if(vorbis_p)ogg_stream_pagein(&vo,page);
+ if(irct_p)ogg_stream_pagein(&zo,page);
return 0;
}
diff --git a/src/kvilib/ext/kvi_oggtheora.h b/src/kvilib/ext/kvi_oggtheora.h
index c9db484e8..751579cc7 100644
--- a/src/kvilib/ext/kvi_oggtheora.h
+++ b/src/kvilib/ext/kvi_oggtheora.h
@@ -27,6 +27,7 @@
#ifndef COMPILE_DISABLE_OGG_THEORA
#include "kvi_settings.h"
+#include "kvi_malloc.h"
#include "theora/theoradec.h"
#include "theora/theoraenc.h"
@@ -56,12 +57,98 @@ typedef struct _KviTheoraGeometry {
int pic_y;
} KviTheoraGeometry;
-class KVILIB_API KviTheoraEncoder {
+class KVILIB_API KviOggIrcText
+{
+private:
+ static void _tp_readbuffer(oggpack_buffer *opb, char *buf, const long len)
+ {
+ long i;
+
+ for (i = 0; i < len; i++)
+ *buf++=oggpack_read(opb,8);
+ }
+
+ static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len)
+ {
+ long i;
+
+ for (i = 0; i < len; i++)
+ oggpack_write(opb, *buf++, 8);
+ }
+
+public:
+ static int irct_encode_init()
+ {
+ return 0;
+ };
+
+ static int irct_encode_clear()
+ {
+ return 0;
+ };
+
+ static int irct_encode_headerout(ogg_packet *op) {
+ oggpack_buffer ob;
+ oggpack_writeinit(&ob);
+ oggpack_write(&ob, 0, 8); //header init
+ _tp_writebuffer(&ob, "irct", 32);
+ oggpack_write(&ob, 0, 8); //version 0
+ oggpack_write(&ob, 1, 8); //subversion 1
+ int bytes=oggpack_bytes(&ob);
+ op->packet= (unsigned char*) kvi_malloc(bytes);
+ memcpy(op->packet, oggpack_get_buffer(&ob), bytes);
+ op->bytes=bytes;
+ oggpack_writeclear(&ob);
+ op->b_o_s=1; //begins a logical bitstream
+ op->e_o_s=0;
+ op->packetno=0;
+ op->granulepos=0;
+
+ return 0;
+ }
+ static int irct_encode_packetout(const char* textPkt, int textSize, int last_p, ogg_packet *op) {
+ if(!textSize)return(0);
+
+ oggpack_buffer ob;
+ oggpack_writeinit(&ob);
+ _tp_writebuffer(&ob, textPkt, textSize); //pre-encoded text
+ int bytes=oggpack_bytes(&ob);
+ op->packet= (unsigned char *)kvi_malloc(bytes);
+ memcpy(op->packet, oggpack_get_buffer(&ob), bytes);
+ op->bytes=bytes;
+ oggpack_writeclear(&ob);
+ op->b_o_s=0;
+ op->e_o_s=last_p;
+
+ op->packetno=last_p;
+ op->granulepos=0;
+
+ return 0;
+ }
+ static int irct_decode_headerin(ogg_packet *op) {
+ oggpack_buffer ob;
+ oggpack_readinit(&ob, op->packet, op->bytes);
+ quint8 ret, version, subversion;
+ ret = oggpack_read(&ob,8);
+ if(ret!=0) return 1;
+ char * buf = (char*) kvi_malloc(4);
+ _tp_readbuffer(&ob, buf, 4);
+ if(strncmp(buf, "irct", 4)!=0) return 1;
+ version = oggpack_read(&ob,8);
+ subversion = oggpack_read(&ob,8);
+ qDebug("irct stream version %d.%d", version, subversion);
+ return 0;
+ }
+};
+
+class KVILIB_API KviTheoraEncoder
+{
public:
KviTheoraEncoder(KviDataBuffer * stream, int iWidth=320, int iHeight=240, int iFpsN=5, int iFpsD=1, int iParN=4, int iParD=3);
virtual ~KviTheoraEncoder();
void addVideoFrame(QRgb * rgb32, int videoSize);
void addAudioFrame(unsigned char* audioPkt, int audioSize);
+ void addTextFrame(unsigned char* textPkt, int textSize);
private:
int fetch_and_process_video(quint8 * videoYuv,ogg_page *videopage,ogg_stream_state *to,th_enc_ctx *td,int videoflag);
int fetch_and_process_video_packet(quint8 * videoYuv,th_enc_ctx *td,ogg_packet *op);
@@ -71,12 +158,15 @@ private:
KviDataBuffer * m_pStream;
quint8 * videoYuv;
+ bool text;
+
bool audio;
int audio_ch;
int audio_hz;
float audio_q;
ogg_int64_t samples_sofar;
-
+ ogg_int64_t text_sofar;
+
int frame_state;
ogg_int64_t frames;
unsigned char *yuvframe[3];
@@ -90,6 +180,7 @@ private:
// The amount to read into the auxilliary buffer.
size_t y4m_aux_buf_read_sz;
+ ogg_stream_state zo; // take physical pages, weld into a logical stream of packets
ogg_stream_state to; // take physical pages, weld into a logical stream of packets
ogg_stream_state vo; // take physical pages, weld into a logical stream of packets
ogg_page og; // one Ogg bitstream page. Vorbis packets are inside
@@ -104,6 +195,7 @@ private:
vorbis_dsp_state vd; // central working state for the packet->PCM decoder
vorbis_block vb; // local working space for packet->PCM decode
+ int textflag;
int audioflag;
int videoflag;
private:
@@ -130,6 +222,7 @@ private:
ogg_page og;
ogg_stream_state vo;
ogg_stream_state to;
+ ogg_stream_state zo;
th_info ti;
th_comment tc;
th_dec_ctx *td;
@@ -142,6 +235,7 @@ private:
int theora_p;
int vorbis_p;
+ int irct_p;
int stateflag;
int lu_Y[256];
diff --git a/src/kvirc/kernel/kvi_userinput.cpp b/src/kvirc/kernel/kvi_userinput.cpp
index 524c1d727..455ca73da 100644
--- a/src/kvirc/kernel/kvi_userinput.cpp
+++ b/src/kvirc/kernel/kvi_userinput.cpp
@@ -152,6 +152,7 @@ namespace KviUserInput
pWindow->ownMessage(buf);
break;
case KVI_WINDOW_TYPE_DCCCHAT:
+ case KVI_WINDOW_TYPE_DCCVIDEO:
pWindow->ownMessage(buf);
break;
default:
diff --git a/src/kvirc/kvs/kvi_kvs_coresimplecommands_mr.cpp b/src/kvirc/kvs/kvi_kvs_coresimplecommands_mr.cpp
index 1bf4906e4..07b4ab5f9 100644
--- a/src/kvirc/kvs/kvi_kvs_coresimplecommands_mr.cpp
+++ b/src/kvirc/kvs/kvi_kvs_coresimplecommands_mr.cpp
@@ -89,6 +89,7 @@ namespace KviKvsCoreSimpleCommands
case KVI_WINDOW_TYPE_QUERY:
KVSCSC_REQUIRE_CONNECTION
case KVI_WINDOW_TYPE_DCCCHAT:
+ case KVI_WINDOW_TYPE_DCCVIDEO:
KVSCSC_pWindow->ownAction(szText);
break;
default:
diff --git a/src/kvirc/ui/kvi_window.h b/src/kvirc/ui/kvi_window.h
index da5b68404..1ed5392da 100644
--- a/src/kvirc/ui/kvi_window.h
+++ b/src/kvirc/ui/kvi_window.h
@@ -103,8 +103,9 @@ class KviTalHBox;
#define KVI_WINDOW_TYPE_SCRIPTOBJECT 21
#define KVI_WINDOW_TYPE_USERWINDOW 22
#define KVI_WINDOW_TYPE_DEBUG 23
+#define KVI_WINDOW_TYPE_DCCVIDEO 24
-#define KVI_WINDOW_NUM_TYPES 24
+#define KVI_WINDOW_NUM_TYPES 25
#define KVI_WINDOW_TYPE_USER 10000
diff --git a/src/modules/dcc/codec.cpp b/src/modules/dcc/codec.cpp
index ffcbf330a..7e1433f1a 100644
--- a/src/modules/dcc/codec.cpp
+++ b/src/modules/dcc/codec.cpp
@@ -109,11 +109,11 @@ void KviDccVideoCodec::encodeVideo(KviDataBuffer *,KviDataBuffer *)
{
}
-void KviDccVideoCodec::encodeAudio(KviDataBuffer *,KviDataBuffer *)
+void KviDccVideoCodec::encodeText(KviDataBuffer *,KviDataBuffer *)
{
}
-void KviDccVideoCodec::decode(KviDataBuffer *,KviDataBuffer *)
+void KviDccVideoCodec::decode(KviDataBuffer *,KviDataBuffer *,KviDataBuffer *)
{
}
@@ -162,40 +162,90 @@ void KviDccVideoSJpegCodec::encodeVideo(KviDataBuffer * videoSignal,KviDataBuffe
videoSignal->clear();
}
-void KviDccVideoSJpegCodec::encodeAudio(KviDataBuffer * audioSignal,KviDataBuffer * stream)
+void KviDccVideoSJpegCodec::encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream)
{
- //no audio support
- Q_UNUSED(stream);
- if(audioSignal->size() < 1) return;
+ static unsigned const char *irct_magic_init = (unsigned const char*) "\0<text>\0";
+ static unsigned const char *irct_magic_end = (unsigned const char*) "\0</text>\0";
- audioSignal->clear();
+ qDebug("encodeText %s %d",textSignal->data(), textSignal->size());
+ if(textSignal->size() < 1) return;
+ stream->append(irct_magic_init,8);
+ stream->append((const unsigned char*)textSignal->data(),textSignal->size());
+ stream->append(irct_magic_end,9);
+ textSignal->clear();
return;
}
-void KviDccVideoSJpegCodec::decode(KviDataBuffer * stream,KviDataBuffer * signal)
+void KviDccVideoSJpegCodec::decode(KviDataBuffer * stream,KviDataBuffer * videoSignal,KviDataBuffer * textSignal)
{
static unsigned const char jpg_magic_init[4] = { 0xFF, 0xD8, 0xFF, 0xE0}; //SOI + APP0
static unsigned const char jpg_magic_end[2] = { 0xFF, 0xD9}; //EOI
+ static unsigned const char *irct_magic_init = (unsigned const char*) "\0<text>\0";
+ static unsigned const char *irct_magic_end = (unsigned const char*) "\0</text>\0";
+
if(stream->size() < 1)return;
- int start = stream->find(jpg_magic_init, 4);
- int end = stream->find(jpg_magic_end, 2);
- if(start != -1 && end != -1)
+
+ int txtStart = stream->find(irct_magic_init, 8);
+ int txtEnd = stream->find(irct_magic_end, 9);
+
+ int jpgStart = stream->find(jpg_magic_init, 4);
+
+ if(txtStart!=-1 && txtEnd !=-1 && txtStart<jpgStart)
+ {
+ qDebug("a txtStart %d txtEnd %d",txtStart,txtEnd);
+ stream->remove(txtStart+8);
+ int len = txtEnd - txtStart -8; //-8 irct_magic_init
+ if(len>0)
+ {
+ textSignal->append(stream->data(), len);
+ char*txt=(char*)malloc(len+1);
+ memcpy(txt,stream->data(), len);
+ txt[len]='\0';
+ qDebug("a recv |%s| %d",txt,len);
+ }
+ stream->remove(len+9);
+ }
+
+ jpgStart = stream->find(jpg_magic_init, 4);
+ int jpgEnd = stream->find(jpg_magic_end, 2);
+
+ if(jpgStart != -1 && jpgEnd != -1)
{
+// qDebug("jpgStart %d jpgEnd %d",jpgStart,jpgEnd);
QImage img;
//remove junk before jpeg start
- stream->remove(start);
- int len = end - start + 1;
+ stream->remove(jpgStart);
+ int len = jpgEnd - jpgStart + 1;
img.loadFromData(stream->data(), stream->size());
if(!img.isNull())
{
- signal->clear();
- signal->append(img.bits(),img.numBytes());
+ videoSignal->clear();
+ videoSignal->append(img.bits(),img.numBytes());
}
stream->remove(len);
}
+
+ txtStart = stream->find(irct_magic_init, 8);
+ txtEnd = stream->find(irct_magic_end, 9);
+
+ if(txtStart!=-1 && txtEnd !=-1)
+ {
+ qDebug("b txtStart %d txtEnd %d",txtStart,txtEnd);
+ stream->remove(txtStart+8);
+ int len = txtEnd - txtStart -8; //-8 irct_magic_init
+ if(len>0)
+ {
+ textSignal->append(stream->data(), len);
+ char*txt=(char*)malloc(len+1);
+ memcpy(txt,stream->data(), len);
+ txt[len]='\0';
+ qDebug("b recv |%s| %d",txt,len);
+ }
+ stream->remove(len+9);
+ }
}
int KviDccVideoSJpegCodec::encodedFrameSize()
@@ -240,23 +290,23 @@ void KviDccVideoTheoraCodec::encodeVideo(KviDataBuffer * videoSignal,KviDataBuff
videoSignal->clear();
}
-void KviDccVideoTheoraCodec::encodeAudio(KviDataBuffer * audioSignal,KviDataBuffer * stream)
+void KviDccVideoTheoraCodec::encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream)
{
- if(audioSignal->size() < 1) return;
+ if(textSignal->size() < 1) return;
if(!m_pEncoder)
m_pEncoder = new KviTheoraEncoder(stream);
- m_pEncoder->addAudioFrame(audioSignal->data(),audioSignal->size());
- audioSignal->clear();
+ m_pEncoder->addTextFrame(textSignal->data(),textSignal->size());
+ textSignal->clear();
}
-void KviDccVideoTheoraCodec::decode(KviDataBuffer * stream,KviDataBuffer * signal)
+void KviDccVideoTheoraCodec::decode(KviDataBuffer * stream,KviDataBuffer * videoSignal,KviDataBuffer * textSignal)
{
if(stream->size() < 1)return;
if(!m_pDecoder)
- m_pDecoder = new KviTheoraDecoder(signal);
+ m_pDecoder = new KviTheoraDecoder(videoSignal);
m_pDecoder->addData(stream);
}
diff --git a/src/modules/dcc/codec.h b/src/modules/dcc/codec.h
index da3c24d18..62d5161c3 100644
--- a/src/modules/dcc/codec.h
+++ b/src/modules/dcc/codec.h
@@ -65,8 +65,8 @@ protected:
public:
const char * name();
virtual void encodeVideo(KviDataBuffer * videoSignal, KviDataBuffer * stream);
- virtual void encodeAudio(KviDataBuffer * audioSignal, KviDataBuffer * stream);
- virtual void decode(KviDataBuffer * stream,KviDataBuffer * signal);
+ virtual void encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream);
+ virtual void decode(KviDataBuffer * stream,KviDataBuffer * videoSignal,KviDataBuffer * textSignal);
virtual int encodedFrameSize();
virtual int decodedFrameSize();
};
@@ -78,8 +78,8 @@ public:
virtual ~KviDccVideoSJpegCodec();
public:
virtual void encodeVideo(KviDataBuffer * videoSignal, KviDataBuffer * stream);
- virtual void encodeAudio(KviDataBuffer * audioSignal, KviDataBuffer * stream);
- virtual void decode(KviDataBuffer * stream,KviDataBuffer * signal);
+ virtual void encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream);
+ virtual void decode(KviDataBuffer * stream,KviDataBuffer * videoSignal,KviDataBuffer * textSignal);
virtual int encodedFrameSize();
virtual int decodedFrameSize();
};
@@ -92,8 +92,8 @@ public:
virtual ~KviDccVideoTheoraCodec();
public:
virtual void encodeVideo(KviDataBuffer * videoSignal, KviDataBuffer * stream);
- virtual void encodeAudio(KviDataBuffer * audioSignal, KviDataBuffer * stream);
- virtual void decode(KviDataBuffer * stream,KviDataBuffer * signal);
+ virtual void encodeText(KviDataBuffer * textSignal, KviDataBuffer * stream);
+ virtual void decode(KviDataBuffer * stream,KviDataBuffer * videoSignal,KviDataBuffer * textSignal);
virtual int encodedFrameSize();
virtual int decodedFrameSize();
private:
diff --git a/src/modules/dcc/libkvidcc.cpp b/src/modules/dcc/libkvidcc.cpp
index 261f8ae75..5f252728c 100644
--- a/src/modules/dcc/libkvidcc.cpp
+++ b/src/modules/dcc/libkvidcc.cpp
@@ -1210,7 +1210,7 @@ static bool dcc_kvs_cmd_video(KviKvsModuleCommandCall * c)
if(!kvi_dcc_video_is_valid_codec(szCodec.toUtf8().data()))
{
- c->warning(__tr2qs_ctx("Invalid codec specified, defaulting to 'sjpeg'","dcc"));
+ c->warning(__tr2qs_ctx("Invalid codec specified","dcc"));
d->szCodec = "sjpeg";
} else {
d->szCodec = szCodec;
diff --git a/src/modules/dcc/video.cpp b/src/modules/dcc/video.cpp
index db0d0a23f..fd1fa8782 100644
--- a/src/modules/dcc/video.cpp
+++ b/src/modules/dcc/video.cpp
@@ -22,13 +22,15 @@
//
//=============================================================================
+#include "kvi_settings.h"
+
#include "video.h"
#include "marshal.h"
#include "broker.h"
-#include "kvi_settings.h"
#include "kvi_iconmanager.h"
#include "kvi_ircview.h"
+#include "kvi_kvs_eventtriggers.h"
#include "kvi_locale.h"
#include "kvi_out.h"
#include "kvi_error.h"
@@ -39,10 +41,22 @@
#include "kvi_socket.h"
#include "kvi_ircconnection.h"
#include "kvi_tal_vbox.h"
+#include "kvi_mirccntrl.h"
+#include "kvi_frame.h"
#include <QToolTip>
#include <QByteArray>
#include <QBuffer>
+#include <QTextDocument> //for Qt::escape
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ #include "kvi_crypt.h"
+ #include "kvi_cryptcontroller.h"
+#endif
+
+#ifdef COMPILE_SSL_SUPPORT
+ #include "kvi_sslmaster.h"
+#endif
#include <sys/ioctl.h>
@@ -53,36 +67,6 @@ extern KviDccBroker * g_pDccBroker;
int g_iVideoDevicePoolInstances=0;
#endif
-//Check for the *SS Api....we don't want to fail here...
-
-#ifndef COMPILE_DISABLE_DCC_VOICE
- #ifdef HAVE_LINUX_SOUNDCARD_H
- #include <linux/soundcard.h>
- #else
- #ifdef HAVE_SYS_SOUNDCARD_H
- #include <sys/soundcard.h>
- #else
- #ifdef HAVE_SOUNDCARD_H
- #include <soundcard.h>
- #else
- //CAN NOT COMPILE :(
- #define COMPILE_DISABLE_DCC_VOICE
- #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
- #warning "Cannot find the soundcard.h header; you will NOT be able to use DCC Voice"
- #endif
- #endif
- #endif
- #endif
-#endif
-
-
-//#define KVI_AUDIO_DEVICE "/dev/dsp"
-// 32 fragments , 512 bytes
-#define KVI_SNDCTL_FRAG_SIZE 0x00B00009
-#define KVI_FRAGMENT_SIZE_IN_BYTES 512
-#define KVI_FORMAT AFMT_S16_LE
-#define KVI_NUM_CHANNELS 1
-
bool kvi_dcc_video_is_valid_codec(const char * codecName)
{
if(kvi_strEqualCI("sjpeg",codecName))return true;
@@ -111,11 +95,6 @@ KviDccVideoThread::KviDccVideoThread(KviWindow * wnd,kvi_socket_t fd,KviDccVideo
m_pInfoMutex = new KviMutex();
m_bRecordingRequestPending = false;
-#ifndef COMPILE_DISABLE_DCC_VOICE
- m_bSoundcardChecked = false;
- m_soundFd = -1;
- m_soundFdMode = 0;
-#endif
//local video input
if(!g_pVideoDevicePool)
{
@@ -146,163 +125,6 @@ KviDccVideoThread::~KviDccVideoThread()
#endif
}
-
-bool KviDccVideoThread::checkSoundcard()
-{
-#ifdef COMPILE_DISABLE_DCC_VOICE
- return false;
-#else
- bool bOpened = false;
- if(m_soundFd == -1)
- {
- if(!openSoundcard(O_RDONLY))return false;
- bOpened = true;
- }
-
- int caps;
-
- m_bSoundcardChecked = true;
-
- if(ioctl(m_soundFd,SNDCTL_DSP_GETCAPS,&caps) < 0)
- {
- postMessageEvent(__tr2qs_ctx("WARNING: failed to check the soundcard duplex capabilities: if this is a half-duplex soundcard, use the DCC VOICE option to force half-duplex algorithm","dcc").toUtf8().data());
- if(bOpened)closeSoundcard();
- return false;
- }
-
- if(!(caps & DSP_CAP_DUPLEX))
- {
- m_pOpt->bForceHalfDuplex = true; // the device is half duplex...use it in that way
- postMessageEvent(__tr2qs_ctx("Half duplex soundcard detected, you will not be able to talk and listen at the same time","dcc").toUtf8().data());
- }
-
- if(bOpened)closeSoundcard();
-
- return true;
-#endif
-}
-
-
-bool KviDccVideoThread::openSoundcard(int mode)
-{
-#ifdef COMPILE_DISABLE_DCC_VOICE
- return false;
-#else
- int speed = m_pOpt->iSampleRate;
- static int chans=KVI_NUM_CHANNELS;
- static int fmt=KVI_FORMAT;
- static int frag = KVI_SNDCTL_FRAG_SIZE;
-
-
- if(m_soundFd != -1)
- {
- if(m_soundFdMode == mode)return true; // already open
- closeSoundcard();
- }
-
- m_soundFd = ::open(m_pOpt->szSoundDevice.ptr(),mode | O_NONBLOCK);
- if(m_soundFd < 0)return false;
-
- if(!m_pOpt->bForceHalfDuplex)
- {
- if(ioctl(m_soundFd,SNDCTL_DSP_SETDUPLEX,0) < 0)goto exit_false;
- }
-
- if(ioctl(m_soundFd,SNDCTL_DSP_SETFRAGMENT,&frag)<0)goto exit_false;
- if(ioctl(m_soundFd,SNDCTL_DSP_SETFMT,&fmt)<0)goto exit_false;
- if(ioctl(m_soundFd,SNDCTL_DSP_CHANNELS,&chans)<0)goto exit_false;
- if(ioctl(m_soundFd,SNDCTL_DSP_SPEED,&speed)<0)goto exit_false;
- if(speed != m_pOpt->iSampleRate)
- {
- KviStr tmp(KviStr::Format,__tr2qs_ctx("WARNING: failed to set the requested sample rate (%d): the device used closest match (%d)","dcc").toUtf8().data(),
- m_pOpt->iSampleRate,speed);
- postMessageEvent(tmp.ptr());
- }
-
- // TODO: #warning "We could also support blocking operations mode"
-
- m_soundFdMode = mode;
-
-
- return true;
-
-exit_false:
- closeSoundcard();
- return false;
-#endif
-}
-
-bool KviDccVideoThread::openSoundcardForWriting()
-{
-#ifndef COMPILE_DISABLE_DCC_VOICE
- return openSoundcardWithDuplexOption(O_WRONLY,O_RDONLY);
-#else
- return false;
-#endif
-}
-
-bool KviDccVideoThread::openSoundcardForReading()
-{
-#ifndef COMPILE_DISABLE_DCC_VOICE
- return openSoundcardWithDuplexOption(O_RDONLY,O_WRONLY);
-#else
- return false;
-#endif
-}
-
-bool KviDccVideoThread::openSoundcardWithDuplexOption(int openMode,int failMode)
-{
-#ifndef COMPILE_DISABLE_DCC_VOICE
- if(m_soundFd == -1)
- {
- // soundcard not open yet...open for write (at least)
- if(m_pOpt->bForceHalfDuplex)
- {
- // Forcing half duplex... (user option or the card does not support full duplex mode)
- if(!openSoundcard(openMode))return false;
- } else {
- // Try read/write open
- if(!openSoundcard(O_RDWR))
- {
- // half-duplex sound card ?
- if(!m_bSoundcardChecked)
- {
- // We haven't checked the full-duplex support yet...
- // Try to open in RDONLY o WRONLY mode
- if(!openSoundcard(openMode))return false;
- if(!checkSoundcard())
- {
- postMessageEvent(__tr2qs_ctx("Ops...failed to test the soundcard capabilities...expect problems...","dcc").toUtf8().data());
- }
- } // else the test has been done and it is a full duplex card that is just busy
- }
- }
- } else {
- // Hmmm...already open
- // If it is open in O_RDWR or O_WRONLY mode...it is ok for us
- // but if it is open in O_RDONLY mode...we can do nothing...just wait
- return (m_soundFdMode != failMode);
- }
-
- return true;
-#else
- return false;
-#endif
-}
-
-void KviDccVideoThread::closeSoundcard()
-{
-#ifndef COMPILE_DISABLE_DCC_VOICE
- if(m_soundFd != -1)
- {
- ::close(m_soundFd);
- m_soundFd = -1;
- m_soundFdMode = 0;
- }
-#endif
-}
-
-
bool KviDccVideoThread::readWriteStep()
{
#ifndef COMPILE_DISABLE_DCC_VIDEO
@@ -320,7 +142,7 @@ bool KviDccVideoThread::readWriteStep()
if(readLen > 0)
{
if(readLen < 4096)m_inFrameBuffer.resize(actualSize + readLen);
- m_pOpt->pCodec->decode(&m_inFrameBuffer,&m_inSignalBuffer);
+ m_pOpt->pCodec->decode(&m_inFrameBuffer,&m_videoInSignalBuffer,&m_textInSignalBuffer);
//#warning "A maximum length for the signal buffer is actually needed!!!"
} else {
bCanRead=false;
@@ -355,10 +177,10 @@ bool KviDccVideoThread::videoStep()
// Are we playing ?
if(m_bPlaying)
{
- if(m_inSignalBuffer.size() > 0)
+ if(m_videoInSignalBuffer.size() > 0)
{
- QImage img(m_inSignalBuffer.data(), 320, 240, 1280, QImage::Format_ARGB32);
-// qDebug("IMG data %p size %d", m_inSignalBuffer.data(), m_inSignalBuffer.size());
+ QImage img(m_videoInSignalBuffer.data(), 320, 240, 1280, QImage::Format_ARGB32);
+// qDebug("IMG data %p size %d", m_videoInSignalBuffer.data(), m_videoInSignalBuffer.size());
if(!img.isNull())
m_inImage = img;
}
@@ -381,167 +203,100 @@ bool KviDccVideoThread::videoStep()
return true;
}
-bool KviDccVideoThread::audioStep()
+bool KviDccVideoThread::textStep()
{
#ifndef COMPILE_DISABLE_DCC_VIDEO
-#ifndef COMPILE_DISABLE_DCC_VOICE
// Are we playing ?
-/*
if(m_bPlaying)
{
- // Do we have something to write ?
- audio_buf_info info;
- if(m_inSignalBuffer.size() > 0)
+ if(m_textInSignalBuffer.size() > 0)
{
- // Get the number of fragments that can be written to the soundcard without blocking
-
- if(ioctl(m_soundFd,SNDCTL_DSP_GETOSPACE,&info) < 0)
- {
- debug("get o space failed");
- info.bytes = KVI_FRAGMENT_SIZE_IN_BYTES; // dummy... if this is not correct...well...we will block for 1024/16000 of a sec
- info.fragments = 1;
- info.fragsize = KVI_FRAGMENT_SIZE_IN_BYTES;
- }
- if(info.fragments > 0)
- {
- int toWrite = info.fragments * info.fragsize;
- //debug("Can write %d bytes",toWrite);
- if(m_inSignalBuffer.size() < toWrite)toWrite = m_inSignalBuffer.size();
- int written = write(m_soundFd,m_inSignalBuffer.data(),toWrite);
- if(written > 0)m_inSignalBuffer.remove(written);
- else {
-//#warning "Do something for -1 here ?"
-//#warning "Usleep ?"
- }
- } //else {
- // No stuff can be written...we are running too fast ?
- // m_uSleepTime += 100; // sleep for a while
- //}
- } else {
- // hmmmm....playing , but nothing to write , possible underrun or EOF
- // a nice idea would be to use SNDCTL_DSP_GETODELAY here...
- // but it appears to be broken on some audio devices
- if(ioctl(m_soundFd,SNDCTL_DSP_GETOSPACE,&info) < 0)info.fragstotal = info.fragments; // dummy...but what should we do ?
- if(info.fragstotal == info.fragments)
- {
- // underrun or EOF: close the device
- stopPlaying();
- }
- }
- } else {
- // do we have anything to play ?
- if(m_inSignalBuffer.size() > 0)
- {
- if(m_inSignalBuffer.size() >= m_pOpt->iPreBufferSize)
- {
- // yep...stuff to play... open the soundcard , if possible
- startPlaying();
-
- m_iLastSignalBufferSize = m_inSignalBuffer.size();
- } else {
- // have stuff to play , but it's not enough to fill the pre-buffer
- //
- struct timeval tv;
- gettimeofday(&tv,0);
-
- long int sigBufferTime = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
-
- if(m_inSignalBuffer.size() == m_iLastSignalBufferSize)
- {
- // the same signal buffer size... check the time
- // m_pOpt->iPreBufferSize / 16 gives us the preBufferTime in msecs
- // we calc the remaining preBufferTime by subtracting the
- // size of buffer already filled and we also add 50 milliseconds... smart heuristic
- int preBufferTime = ((m_pOpt->iPreBufferSize - m_iLastSignalBufferSize) / 16) + 50;
- // if the buffer size hasn't changed since preBufferTime
- // it's time to start playing anyway, since there is
- // either a network stall or it was just a really short data stream
- if((sigBufferTime - m_iLastSignalBufferTime) > preBufferTime)
- {
- startPlaying();
- if(m_bPlaying)m_iLastSignalBufferSize = 0;
- }
- } else {
- // signal buffer size differs...we have received new packets
- // and still pre-buffering
- m_iLastSignalBufferSize = m_inSignalBuffer.size();
- m_iLastSignalBufferTime = sigBufferTime;
- }
- }
+ KviDccThreadIncomingData data;
+ data.iLen = m_textInSignalBuffer.size();
+ data.buffer = (char*) kvi_malloc(data.iLen);
+ memcpy(data.buffer, m_textInSignalBuffer.data(), data.iLen);
+ handleIncomingData(&data,false);
+ m_textInSignalBuffer.clear();
}
}
-*/
+
// Are we recording ?
if(m_bRecording)
{
- fd_set rs;
- FD_ZERO(&rs);
- FD_SET(m_soundFd,&rs);
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10;
- int ret = select(m_soundFd + 1,&rs,0,0,&tv);
- if(ret > 0)
+ if(((KviDccVideo*)parent())->m_tmpTextDataOut.size())
{
- // This is rather easy...
- audio_buf_info info;
- if(ioctl(m_soundFd,SNDCTL_DSP_GETISPACE,&info) < 0)
- {
- debug("Ispace failed");
- info.fragments = 0; // dummy...
- info.bytes = 0;
- }
+ m_textOutSignalBuffer.append((const unsigned char*) ((KviDccVideo*)parent())->m_tmpTextDataOut.constData(), ((KviDccVideo*)parent())->m_tmpTextDataOut.size());
+ ((KviDccVideo*)parent())->m_tmpTextDataOut.clear();
+ }
- //debug("INFO: fragments: %d, fragstotal: %d, fragsize: %d, bytes: %d",info.fragments,info.fragstotal,info.fragsize,info.bytes);
+ if(m_textOutSignalBuffer.size())
+ m_pOpt->pCodec->encodeText(&m_textOutSignalBuffer,&m_outFrameBuffer);
+ }
- if(info.fragments == 0 && info.bytes == 0)
- {
- // force a dummy read: the device needs to be triggered
- info.fragments = 1;
- }
+#endif // !COMPILE_DISABLE_DCC_VIDEO
+ return true;
+}
- if(info.fragments > 0)
+bool KviDccVideoThread::handleIncomingData(KviDccThreadIncomingData * data,bool bCritical)
+{
+ __range_valid(data->iLen);
+ __range_valid(data->buffer);
+ char * aux = data->buffer;
+ char * end = data->buffer + data->iLen;
+ while(aux != end)
+ {
+ if((*aux == '\n') || (*aux == '\0'))
+ {
+ KviThreadDataEvent<KviStr> * e = new KviThreadDataEvent<KviStr>(KVI_DCC_THREAD_EVENT_DATA);
+ // The left part is len chars long
+ int len = aux - data->buffer;
+// debug("LEN = %d, iLen = %d",len,data->iLen);
+//#warning "DO IT BETTER (the \r cutting)"
+ KviStr * s = new KviStr(data->buffer,len);
+ if(s->lastCharIs('\r'))s->cutRight(1);
+ e->setData(s);
+ // but we cut also \n (or \0)
+ ++aux;
+ // so len += 1; --> new data->iLen -= len;
+ data->iLen -= (len + 1);
+// debug("iLen now = %d",data->iLen);
+ __range_valid(data->iLen >= 0);
+ if(data->iLen > 0)
{
- int oldSize = m_audioOutSignalBuffer.size();
- int available = info.fragments * info.fragsize;
- m_audioOutSignalBuffer.addSize(available);
- int readed = read(m_soundFd,m_audioOutSignalBuffer.data() + oldSize,available);
-
- if(readed < available)
- {
- // huh ? ...error ?
- if(readed >= 0)m_audioOutSignalBuffer.resize(oldSize + readed);
- else {
- if((errno == EINTR) || (errno == EAGAIN))
- {
- m_audioOutSignalBuffer.resize(oldSize);
- } else {
-//#warning "Critical error...do something reasonable!"
- m_audioOutSignalBuffer.resize(oldSize);
- }
- }
- }
-/*
- debug("Signal buffer:");
- for(int i=0;i<200;i+=2)
- {
- if(i >= m_outSignalBuffer.size())break;
- printf("%04x ",*(((unsigned short *)(m_outSignalBuffer.data() + i))));
- if((i % 6) == 0)printf("\n");
- }
- debug("END\n");
-*/
- m_pOpt->pCodec->encodeAudio(&m_audioOutSignalBuffer,&m_outFrameBuffer);
+ // memmove the remaining part to the beginning
+ // aux points after \n or \0
+ kvi_memmove(data->buffer,aux,data->iLen);
+ data->buffer = (char *)kvi_realloc(data->buffer,data->iLen);
+ end = data->buffer + data->iLen;
+ aux = data->buffer;
+ } else {
+ // no more data in the buffer
+ __range_valid(data->iLen == 0);
+ kvi_free(data->buffer);
+ data->buffer = end = aux = 0;
}
- }// else {
- // Nothing to read
- // m_uSleepTime += 100;
- // }
+ postEvent(parent(),e);
+ } else aux++;
+// debug("PASSING CHAR %c",*aux);
+ }
+ // now aux == end
+ if(bCritical)
+ {
+ // need to flush everything...
+ if(data->iLen > 0)
+ {
+ // in the last part there are no NULL and \n chars
+ KviThreadDataEvent<KviStr> * e = new KviThreadDataEvent<KviStr>(KVI_DCC_THREAD_EVENT_DATA);
+ KviStr * s = new KviStr(data->buffer,data->iLen);
+ if(s->lastCharIs('\r'))s->cutRight(1);
+ e->setData(s);
+ data->iLen = 0;
+ kvi_free(data->buffer);
+ data->buffer = 0;
+ postEvent(parent(),e);
+ }
}
-
-#endif // !COMPILE_DISABLE_DCC_VOICE
-#endif // !COMPILE_DISABLE_DCC_VIDEO
return true;
}
@@ -550,10 +305,6 @@ void KviDccVideoThread::startRecording()
#ifndef COMPILE_DISABLE_DCC_VIDEO
//debug("Start recording");
if(m_bRecording)return; // already started
-
- //FIXME this is mandatory only for audio!
- openSoundcardForReading();
-
{
// debug("Posting event");
@@ -581,8 +332,6 @@ void KviDccVideoThread::stopRecording()
postEvent(KviDccThread::parent(),e);
m_bRecording = false;
- //FIXME this is mandatory only if we are using audio
- if(!m_bPlaying)closeSoundcard();
#endif
}
@@ -591,15 +340,12 @@ void KviDccVideoThread::startPlaying()
#ifndef COMPILE_DISABLE_DCC_VIDEO
//debug("Start playing");
if(m_bPlaying)return;
- //FIXME this is mandatory only if we are using audio
- openSoundcardForWriting();
- //if()
- {
- KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION);
- e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_START_PLAYING));
- postEvent(KviDccThread::parent(),e);
- m_bPlaying = true;
- }
+
+ KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION);
+ e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_START_PLAYING));
+ postEvent(KviDccThread::parent(),e);
+ m_bPlaying = true;
+
#endif
}
@@ -612,10 +358,7 @@ void KviDccVideoThread::stopPlaying()
KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION);
e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_STOP_PLAYING));
postEvent(KviDccThread::parent(),e);
-
m_bPlaying = false;
- //FIXME this is mandatory only if we are using audio
- if(!m_bRecording)closeSoundcard();
#endif
}
@@ -647,14 +390,14 @@ void KviDccVideoThread::run()
}
if(!readWriteStep())goto exit_dcc;
- //if(!videoStep() || !audioStep())goto exit_dcc;
if(!videoStep())goto exit_dcc;
-
+ if(!textStep())goto exit_dcc;
+
m_pInfoMutex->lock();
m_pInfoMutex->unlock();
//if(m_uSleepTime)usleep(m_uSleepTime);
-// qDebug("in %d out %d in_sig %d out_sig %d", m_inFrameBuffer.size(), m_outFrameBuffer.size(), m_inSignalBuffer.size(), m_videoOutSignalBuffer.size());
+// qDebug("in %d out %d in_sig %d out_sig %d", m_inFrameBuffer.size(), m_outFrameBuffer.size(), m_videoInSignalBuffer.size(), m_videoOutSignalBuffer.size());
usleep(200);
// Start recording if the request was not fulfilled yet
@@ -670,13 +413,31 @@ exit_dcc:
}
KviDccVideo::KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name)
-: KviDccWindow(KVI_WINDOW_TYPE_DCCVOICE,pFrm,name,dcc)
+: KviDccWindow(KVI_WINDOW_TYPE_DCCVIDEO,pFrm,name,dcc)
{
m_pDescriptor = dcc;
m_pSlaveThread = 0;
m_pszTarget = 0;
- m_pLayout = new QGridLayout();
+ m_pLayout = new QGridLayout(this);
+
+ m_pButtonBox = new KviTalHBox(this);
+
+ m_pLabel = new KviThemedLabel(m_pButtonBox, this, "dcc_chat_label");
+ m_pLabel->setText(name);
+ m_pButtonBox->setStretchFactor(m_pLabel,1);
+
+ m_pButtonContainer= new KviTalHBox(m_pButtonBox);
+ createTextEncodingButton(m_pButtonContainer);
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ createCryptControllerButton(m_pButtonContainer);
+#endif
+ m_pLayout->addWidget(m_pButtonBox, 0, 0, 1, 3);
+
+ m_pIrcView = new KviIrcView(this,pFrm,this);
+ connect(m_pIrcView,SIGNAL(rightClicked()),this,SLOT(textViewRightClicked()));
+ m_pInput = new KviInput(this);
//remote video
m_pInVideoLabel = new QLabel();
@@ -685,7 +446,7 @@ KviDccVideo::KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name
m_pInVideoLabel->setFrameShape(QFrame::Box);
m_pInVideoLabel->setScaledContents(true);
m_pInVideoLabel->setAlignment(Qt::AlignCenter);
- m_pLayout->addWidget(m_pInVideoLabel, 0, 0, 10, 1);
+ m_pLayout->addWidget(m_pInVideoLabel, 1, 0, 6, 1);
//local video
m_pOutVideoLabel = new QLabel();
@@ -694,32 +455,38 @@ KviDccVideo::KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name
m_pOutVideoLabel->setFrameShape(QFrame::Box);
m_pOutVideoLabel->setScaledContents(true);
m_pOutVideoLabel->setAlignment(Qt::AlignCenter);
- m_pLayout->addWidget(m_pOutVideoLabel, 11, 0, 10, 1);
+ m_pLayout->addWidget(m_pOutVideoLabel, 1, 1, 6, 1);
//local video input: config
- m_pLabel[0] = new QLabel();
- m_pLabel[0]->setText(__tr2qs_ctx("Video device:","dcc"));
- m_pLayout->addWidget(m_pLabel[0], 11, 1, 1, 1);
+ m_pVideoLabel[0] = new QLabel();
+ m_pVideoLabel[0]->setText(__tr2qs_ctx("Video device:","dcc"));
+ m_pLayout->addWidget(m_pVideoLabel[0], 1, 2, 1, 1);
m_pCDevices = new QComboBox();
- m_pLayout->addWidget(m_pCDevices, 12, 1, 1, 1);
+ m_pLayout->addWidget(m_pCDevices, 2, 2, 1, 1);
- m_pLabel[1] = new QLabel();
- m_pLabel[1]->setText(__tr2qs_ctx("Input:","dcc"));
- m_pLayout->addWidget(m_pLabel[1], 13, 1, 1, 1);
+ m_pVideoLabel[1] = new QLabel();
+ m_pVideoLabel[1]->setText(__tr2qs_ctx("Input:","dcc"));
+ m_pLayout->addWidget(m_pVideoLabel[1], 3, 2, 1, 1);
m_pCInputs = new QComboBox();
- m_pLayout->addWidget(m_pCInputs, 14, 1, 1, 1);
+ m_pLayout->addWidget(m_pCInputs, 4, 2, 1, 1);
- m_pLabel[2] = new QLabel();
- m_pLabel[2]->setText(__tr2qs_ctx("Standard:","dcc"));
- m_pLayout->addWidget(m_pLabel[2], 15, 1, 1, 1);
+ m_pVideoLabel[2] = new QLabel();
+ m_pVideoLabel[2]->setText(__tr2qs_ctx("Standard:","dcc"));
+ m_pLayout->addWidget(m_pVideoLabel[2], 5, 2, 1, 1);
m_pCStandards = new QComboBox();
- m_pLayout->addWidget(m_pCStandards, 16, 1, 1, 1);
+ m_pLayout->addWidget(m_pCStandards, 6, 2, 1, 1);
+
+ m_pLayout->addWidget(m_pIrcView, 7, 0, 1, 3);
+ m_pLayout->addWidget(m_pInput, 8, 0, 1, 3);
+ m_pLayout->setRowStretch(7,1);
setLayout(m_pLayout);
+ if(KVI_OPTION_BOOL(KviOption_boolAutoLogDccChat))m_pIrcView->startLogging();
+
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(slotUpdateImage()) );
m_Timer.start(200); //5fps
@@ -759,14 +526,14 @@ KviDccVideo::~KviDccVideo()
delete m_pCStandards;
m_pCStandards=0;
}
- if(m_pLabel[0])
+ if(m_pVideoLabel[0])
{
- delete m_pLabel[2];
- delete m_pLabel[1];
- delete m_pLabel[0];
- m_pLabel[2] = 0;
- m_pLabel[1] = 0;
- m_pLabel[0] = 0;
+ delete m_pVideoLabel[2];
+ delete m_pVideoLabel[1];
+ delete m_pVideoLabel[0];
+ m_pVideoLabel[2] = 0;
+ m_pVideoLabel[1] = 0;
+ m_pVideoLabel[0] = 0;
}
if(m_pLayout)
{
@@ -792,6 +559,21 @@ KviDccVideo::~KviDccVideo()
}
}
+void KviDccVideo::textViewRightClicked()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatPopupRequest,this,m_pDescriptor->idString());
+}
+
+void KviDccVideo::triggerCreationEvents()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatWindowCreated,this,m_pDescriptor->idString());
+}
+
+void KviDccVideo::triggerDestructionEvents()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatWindowClosing,this,m_pDescriptor->idString());
+}
+
void KviDccVideo::startConnection()
{
if(!(m_pDescriptor->bActive))
@@ -867,6 +649,109 @@ QPixmap * KviDccVideo::myIconPtr()
return g_pIconManager->getSmallIcon(KVI_SMALLICON_DCCVOICE);
}
+void KviDccVideo::ownMessage(const QString &text)
+{
+ if(!m_pSlaveThread)
+ {
+ output(KVI_OUT_SYSTEMWARNING,__tr2qs_ctx("Cannot send data: No active connection","dcc"));
+ return;
+ }
+
+ QByteArray szData = encodeText(text);
+ const char * d = szData.data();
+ if(!d)return;
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ if(cryptSessionInfo())
+ {
+ if(cryptSessionInfo()->bDoEncrypt)
+ {
+ if(*d != KVI_TEXT_CRYPTESCAPE)
+ {
+ KviStr encrypted;
+ cryptSessionInfo()->pEngine->setMaxEncryptLen(-1);
+ switch(cryptSessionInfo()->pEngine->encrypt(d,encrypted))
+ {
+ case KviCryptEngine::Encrypted:
+ {
+ KviStr buf(KviStr::Format,"%s\r\n",encrypted.ptr());
+ m_tmpTextDataOut.append(buf.ptr(), buf.len());
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSGCRYPTED,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),text,KviConsole::NoNotifications);
+ }
+ break;
+ case KviCryptEngine::Encoded:
+ {
+ KviStr buf(KviStr::Format,"%s\r\n",encrypted.ptr());
+ m_tmpTextDataOut.append(buf.ptr(), buf.len());
+ QString encr = decodeText(encrypted.ptr());
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),encr,KviConsole::NoNotifications);
+ }
+ break;
+ default: // also case KviCryptEngine::EncryptError
+ {
+ QString szErr = cryptSessionInfo()->pEngine->lastError();
+ output(KVI_OUT_SYSTEMERROR,
+ __tr2qs_ctx("The crypto engine was not able to encrypt the current message (%Q): %Q, no data was sent to the remote end","dcc"),
+ &text,&szErr);
+ }
+ break;
+ }
+ return;
+ } else {
+ d++; //eat the escape code
+ KviStr buf(KviStr::Format,"%s\r\n",d);
+ QString tmp = text.right(text.length() - 1);
+ m_tmpTextDataOut.append(buf.ptr(), buf.len());
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),tmp,KviConsole::NoNotifications);
+ return;
+ }
+ }
+ }
+#endif
+ KviStr buf(KviStr::Format,"%s\r\n",d);
+ m_tmpTextDataOut.append(buf.ptr(), buf.len());
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),text,KviConsole::NoNotifications);
+}
+
+const QString & KviDccVideo::localNick()
+{
+ // FIXME: This is just a complete HACK
+ m_szLocalNick = m_pDescriptor->szLocalNick;
+ return m_szLocalNick;
+}
+
+void KviDccVideo::ownAction(const QString &text)
+{
+ if(m_pSlaveThread)
+ {
+ QString szTmpBuffer;
+ //see bug ticket #220
+ if(KVI_OPTION_BOOL(KviOption_boolStripMircColorsInUserMessages))
+ {
+ szTmpBuffer = KviMircCntrl::stripControlBytes(text);
+ } else {
+ szTmpBuffer = text;
+ }
+
+ QByteArray szData = encodeText(szTmpBuffer);
+ const char * d = szData.data();
+ if(!d)return;
+ KviStr buf(KviStr::Format,"%cACTION %s%c\r\n",0x01,d,0x01);
+ m_tmpTextDataOut.append(buf.ptr(), buf.len());
+ output(KVI_OUT_ACTION,"%Q %Q",&(m_pDescriptor->szLocalNick),&szTmpBuffer);
+ } else {
+ output(KVI_OUT_SYSTEMWARNING,__tr2qs_ctx("Cannot send data: No active connection","dcc"));
+ }
+}
+
bool KviDccVideo::event(QEvent *e)
{
if(e->type() == KVI_THREAD_EVENT)
@@ -879,12 +764,98 @@ bool KviDccVideo::event(QEvent *e)
QString ssss = KviError::getDescription(*err);
output(KVI_OUT_DCCERROR,__tr2qs_ctx("ERROR: %Q","dcc"),&(ssss));
delete err;
-/* m_pTalkButton->setEnabled(false);
- m_pRecordingLabel->setEnabled(false);
- m_pPlayingLabel->setEnabled(false);*/
return true;
}
break;
+ case KVI_DCC_THREAD_EVENT_DATA:
+ {
+ KviStr * encoded = ((KviThreadDataEvent<KviStr> *)e)->getData();
+ KviStr d=KviStr(decodeText(encoded->ptr()));
+ if(d.firstCharIs(0x01))
+ {
+ d.cutLeft(1);
+ if(d.lastCharIs(0x01))d.cutRight(1);
+ if(kvi_strEqualCIN("ACTION",d.ptr(),6))d.cutLeft(6);
+ d.stripLeftWhiteSpace();
+ output(KVI_OUT_ACTION,"%Q %s",&(m_pDescriptor->szNick),d.ptr());
+ if(!hasAttention())
+ {
+ if(KVI_OPTION_BOOL(KviOption_boolFlashDccChatWindowOnNewMessages))
+ {
+ demandAttention();
+ }
+ if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewDccChatMessages))
+ {
+ QString szMsg = "<b>";
+ szMsg += m_pDescriptor->szNick;
+ szMsg += "</b> ";
+ szMsg += Qt::escape(QString(d.ptr()));
+ //debug("kvi_sp_ctcp.cpp:975 debug: %s",szMsg.data());
+ g_pApp->notifierMessage(this,KVI_OPTION_MSGTYPE(KVI_OUT_ACTION).pixId(),szMsg,KVI_OPTION_UINT(KviOption_uintNotifierAutoHideTime));
+ }
+ }
+ } else {
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ if(KviCryptSessionInfo * cinf = cryptSessionInfo())
+ {
+ if(cinf->bDoDecrypt)
+ {
+ KviStr decryptedStuff;
+ switch(cinf->pEngine->decrypt(d.ptr(),decryptedStuff))
+ {
+ case KviCryptEngine::DecryptOkWasEncrypted:
+ case KviCryptEngine::DecryptOkWasEncoded:
+ case KviCryptEngine::DecryptOkWasPlainText:
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatMessage,this,QString(decryptedStuff.ptr()),m_pDescriptor->idString()))
+ {
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_DCCCHATMSG,
+ m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szUser.toUtf8().data(),
+ m_pDescriptor->szHost.toUtf8().data(),decryptedStuff.ptr());
+ }
+ delete encoded;
+ return true;
+ break;
+
+ default: // also case KviCryptEngine::DecryptError
+ {
+ QString szErr = cinf->pEngine->lastError();
+ output(KVI_OUT_SYSTEMERROR,
+ __tr2qs_ctx("The following message appears to be encrypted, but the crypto engine failed to decode it: %Q","dcc"),
+ &szErr);
+ }
+ break;
+ }
+ }
+ } else {
+#endif
+ // FIXME!
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatMessage,this,QString(d.ptr()),m_pDescriptor->idString()))
+ {
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_DCCCHATMSG,
+ m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szUser.toUtf8().data(),
+ m_pDescriptor->szHost.toUtf8().data(),d.ptr());
+ if(!hasAttention())
+ {
+ if(KVI_OPTION_BOOL(KviOption_boolFlashDccChatWindowOnNewMessages))
+ {
+ demandAttention();
+ }
+ if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewDccChatMessages))
+ {
+ QString szMsg = Qt::escape(QString(d.ptr()));
+ g_pApp->notifierMessage(this,KVI_SMALLICON_DCCCHATMSG,szMsg,KVI_OPTION_UINT(KviOption_uintNotifierAutoHideTime));
+ }
+ }
+ }
+#ifdef COMPILE_CRYPT_SUPPORT
+ }
+#endif
+ }
+ delete encoded;
+ return true;
+ }
+
case KVI_DCC_THREAD_EVENT_MESSAGE:
{
KviStr * str = ((KviThreadDataEvent<KviStr> *)e)->getData();
@@ -929,10 +900,6 @@ void KviDccVideo::handleMarshalError(int err)
{
QString ssss = KviError::getDescription(err);
output(KVI_OUT_DCCERROR,__tr2qs_ctx("DCC Failed: %Q","dcc"),&ssss);
-/* m_pTalkButton->setEnabled(false);
- m_pTalkButton->setChecked(false);
- m_pRecordingLabel->setEnabled(false);
- m_pPlayingLabel->setEnabled(false);*/
}
void KviDccVideo::connected()
@@ -952,10 +919,6 @@ void KviDccVideo::connected()
KviDccVideoThreadOptions * opt = new KviDccVideoThreadOptions;
opt->pCodec = kvi_dcc_video_get_codec(m_pDescriptor->szCodec.ptr());
- opt->bForceHalfDuplex = KVI_OPTION_BOOL(KviOption_boolDccVoiceForceHalfDuplex);
- opt->iPreBufferSize = KVI_OPTION_UINT(KviOption_uintDccVoicePreBufferSize);
- opt->szSoundDevice = KVI_OPTION_STRING(KviOption_stringDccVoiceSoundDevice).toUtf8().data();
- opt->iSampleRate = 8000;
output(KVI_OUT_DCCMSG,__tr2qs_ctx("Actual codec used is '%s'","dcc"),opt->pCodec->name());
@@ -974,8 +937,6 @@ void KviDccVideo::connected()
#endif
m_pSlaveThread->start();
-
-// m_pTalkButton->setEnabled(true);
}
void KviDccVideo::stopTalking()
@@ -1011,7 +972,7 @@ void KviDccVideo::slotUpdateImage()
void KviDccVideo::deviceRegistered(const QString &)
{
- /*
+
#ifndef COMPILE_DISABLE_DCC_VIDEO
g_pVideoDevicePool->fillDeviceQComboBox(m_pCDevices);
g_pVideoDevicePool->fillInputQComboBox(m_pCInputs);
@@ -1029,19 +990,16 @@ void KviDccVideo::deviceRegistered(const QString &)
// m_Timer.start(200); //5fps
// }
#endif
-#*/
}
void KviDccVideo::deviceUnregistered(const QString & )
{
-/*
#ifndef COMPILE_DISABLE_DCC_VIDEO
g_pVideoDevicePool->fillDeviceQComboBox(m_pCDevices);
g_pVideoDevicePool->fillInputQComboBox(m_pCInputs);
g_pVideoDevicePool->fillStandardQComboBox(m_pCStandards);
#endif
-*/
}
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
diff --git a/src/modules/dcc/video.h b/src/modules/dcc/video.h
index 02f93cd77..628c319d1 100644
--- a/src/modules/dcc/video.h
+++ b/src/modules/dcc/video.h
@@ -33,6 +33,7 @@
#include "kvi_databuffer.h"
#include "kvi_sockettype.h"
#include "kvi_tal_hbox.h"
+#include "kvi_themedlabel.h"
#include <QLabel>
#include <QToolButton>
@@ -62,10 +63,6 @@ typedef struct _KviDccVideoThreadOptions
{
QString szVideoDevice;
KviDccVideoCodec * pCodec;
- bool bForceHalfDuplex;
- int iPreBufferSize;
- int iSampleRate;
- KviStr szSoundDevice;
} KviDccVideoThreadOptions;
class KviDccVideoThread : public KviDccThread
@@ -78,9 +75,10 @@ protected:
KviDccVideoThreadOptions * m_pOpt;
KviDataBuffer m_outFrameBuffer;
KviDataBuffer m_inFrameBuffer;
- KviDataBuffer m_inSignalBuffer;
+ KviDataBuffer m_videoInSignalBuffer;
+ KviDataBuffer m_textInSignalBuffer;
KviDataBuffer m_videoOutSignalBuffer;
- KviDataBuffer m_audioOutSignalBuffer;
+ KviDataBuffer m_textOutSignalBuffer;
bool m_bPlaying;
bool m_bRecording;
bool m_bRecordingRequestPending;
@@ -89,30 +87,20 @@ protected:
// stuff protected by the mutex:
int m_iInputBufferSize;
int m_iOutputBufferSize;
- //audio
- int m_soundFd;
- int m_soundFdMode;
- bool m_bSoundcardChecked;
protected:
QImage m_inImage;
QImage m_outImage;
protected:
bool readWriteStep();
bool videoStep();
- bool audioStep();
+ bool textStep();
void startRecording();
void stopRecording();
void startPlaying();
void stopPlaying();
inline bool isPlaying() { return m_bPlaying; };
virtual void run();
- //audio
- bool checkSoundcard();
- bool openSoundcardWithDuplexOption(int openMode,int failMode);
- bool openSoundcard(int mode);
- bool openSoundcardForWriting();
- bool openSoundcardForReading();
- void closeSoundcard();
+ virtual bool handleIncomingData(KviDccThreadIncomingData *data,bool bCritical);
};
@@ -124,6 +112,10 @@ public:
KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name);
~KviDccVideo();
protected:
+ KviThemedLabel * m_pLabel;
+ KviTalHBox * m_pButtonBox;
+ KviTalHBox * m_pButtonContainer;
+
QLabel *m_pInVideoLabel;
QLabel *m_pOutVideoLabel;
QComboBox *m_pCDevices;
@@ -131,35 +123,34 @@ protected:
QComboBox *m_pCStandards;
QGridLayout *m_pLayout;
QTimer m_Timer;
- QLabel * m_pLabel[2];
+ QLabel * m_pVideoLabel[2];
QString * m_pszTarget;
KviDccVideoThread * m_pSlaveThread;
+ QByteArray m_tmpTextDataOut;
+ QString m_szLocalNick;
protected:
-// virtual void focusInEvent(QFocusEvent *);
+ virtual void triggerCreationEvents();
+ virtual void triggerDestructionEvents();
virtual const QString & target();
virtual void fillCaptionBuffers();
virtual QPixmap * myIconPtr();
-/*
- virtual void resizeEvent(QResizeEvent *e);
- virtual QSize sizeHint() const;
-*/
virtual bool event(QEvent *e);
virtual void getBaseLogFileName(QString &buffer);
void startTalking();
void stopTalking();
void startConnection();
-// int getMixerVolume(void) const;
+ virtual const QString & localNick();
+ virtual void ownMessage(const QString &text);
+ virtual void ownAction(const QString &text);
protected slots:
void handleMarshalError(int err);
void connected();
void startOrStopTalking(bool bStart);
-/*
- void setMixerVolume(int);
-*/
void connectionInProgress();
void slotUpdateImage();
void deviceRegistered(const QString &);
void deviceUnregistered(const QString &);
+ void textViewRightClicked();
};