summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-09-20 11:53:40 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2014-09-20 11:53:40 +0200
commit808225629721c2f7d5c751edc60e5c6744be7886 (patch)
tree3d97fc3b7319b5f94e688a454de51b32321ebfd7
parent46d4e577bceb12c9463fdf4ef1d9a9a348f13543 (diff)
First (crashing) prototype.
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am14
-rw-r--r--src/audioinput.cc6
-rw-r--r--src/audioinputhandler.cc (renamed from src/audiohandler.cc)19
-rw-r--r--src/audioinputhandler.h (renamed from src/audiohandler.h)16
-rw-r--r--src/audiooutputhandler.cc38
-rw-r--r--src/audiooutputhandler.h48
-rw-r--r--src/frame.cc25
-rw-r--r--src/frame.h24
-rw-r--r--src/inputstreamer.cc122
-rw-r--r--src/inputstreamer.h65
-rw-r--r--src/mainwindow.cc67
-rw-r--r--src/mainwindow.h18
-rw-r--r--src/opusdecoder.cc53
-rw-r--r--src/opusdecoder.h48
-rw-r--r--src/opusencoder.cc70
-rw-r--r--src/opusencoder.h9
-rw-r--r--src/outputstreamer.cc127
-rw-r--r--src/outputstreamer.h62
-rw-r--r--src/simplertp.cc4
-rw-r--r--src/soundplayer.cc123
-rw-r--r--src/soundplayer.h65
-rw-r--r--src/v4l.cc10
-rw-r--r--src/v4l.h5
24 files changed, 941 insertions, 99 deletions
diff --git a/configure.ac b/configure.ac
index 36978fd..2374032 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,7 +31,7 @@ PKG_PROG_PKG_CONFIG(0.23)
dnl ======================
dnl Check for Qt
dnl ======================
-PKG_CHECK_MODULES(QT, QtCore QtGui QtXml >= 4.5)
+PKG_CHECK_MODULES(QT, QtCore QtGui QtNetwork >= 4.5)
AC_CHECK_PROGS(QT_MOC, [moc4 moc-qt4 moc], [])
AC_CHECK_PROGS(QT_RCC, [rcc4 rcc-qt4 rcc], [])
AC_CHECK_PROGS(QT_UIC, [uic4 uic-qt4 uic], [])
diff --git a/src/Makefile.am b/src/Makefile.am
index 1b457ca..27ff019 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,20 +18,30 @@ simplertp_SOURCES = \
mainwindow.cc \
v4l.cc \
opusencoder.cc \
+ opusdecoder.cc \
samplecache.cc \
frame.cc \
audioinput.cc \
- audiohandler.cc
+ audioinputhandler.cc \
+ audiooutputhandler.cc \
+ soundplayer.cc \
+ outputstreamer.cc \
+ inputstreamer.cc
EXTRA_DIST = \
simplertp.qrc
mainwindow.h \
v4l.h \
opusencoder.h \
+ opusdecoder.h \
samplecache.h \
frame.h \
audioinput.h \
- audiohandler.h
+ audioinputhandler.h \
+ audiooutputhandler.h \
+ soundplayer.h \
+ outputstreamer.h \
+ inputstreamer.h
simplertp_MOC = $(shell ../tools/MocList cc )
diff --git a/src/audioinput.cc b/src/audioinput.cc
index 8197193..cc68e4b 100644
--- a/src/audioinput.cc
+++ b/src/audioinput.cc
@@ -32,20 +32,20 @@ AudioInput::AudioInput(const char *device)
{
int err;
ai = ai_init(&err, device, "", 48000, 1);
- printf("ai_err: %d\n", err);
+ if(err) printf("ai_err: %d\n", err);
}
AudioInput::~AudioInput()
{
int err;
ai_close(&err, ai);
- printf("ai_err: %d\n", err);
+ if(err) printf("ai_err: %d\n", err);
}
int AudioInput::getSamples(void *pcm, size_t size)
{
int err;
int ret = ai_read(&err, ai, pcm, size);
- printf("ai_err: %d\n", err);
+ if(err) printf("ai_err: %d\n", err);
return ret;
}
diff --git a/src/audiohandler.cc b/src/audioinputhandler.cc
index 8deb414..29af3cb 100644
--- a/src/audiohandler.cc
+++ b/src/audioinputhandler.cc
@@ -1,8 +1,8 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * audiohandler.cc
+ * audioinputhandler.cc
*
- * Fri Sep 19 19:58:05 CEST 2014
+ * Sat Sep 20 11:03:46 CEST 2014
* Copyright 2014 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,29 +24,32 @@
* along with SimpleRTP; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include "audiohandler.h"
+#include "audioinputhandler.h"
-AudioHandler::AudioHandler(QString device)
+#include <QMetaType>
+
+AudioInputHandler::AudioInputHandler(QString device)
: ai(device.toStdString().c_str())
{
+ qRegisterMetaType<framelist_t>("framelist_t");
start();
}
-AudioHandler::~AudioHandler()
+AudioInputHandler::~AudioInputHandler()
{
running = false;
wait();
}
-void AudioHandler::run()
+void AudioInputHandler::run()
{
char pcm[4096];
running = true;
while(running) {
int sz = ai.getSamples(pcm, sizeof(pcm));
- printf("sz: %d\n", sz);
+ // printf("sz: %d\n", sz);
framelist_t fl = oe.encode(pcm, sz);
- emit newAudio(fl);
+ if(fl.size()) emit newAudio(fl);
}
}
diff --git a/src/audiohandler.h b/src/audioinputhandler.h
index b61cfef..dbf43e7 100644
--- a/src/audiohandler.h
+++ b/src/audioinputhandler.h
@@ -1,8 +1,8 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * audiohandler.h
+ * audioinputhandler.h
*
- * Fri Sep 19 19:58:05 CEST 2014
+ * Sat Sep 20 11:03:46 CEST 2014
* Copyright 2014 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,8 +24,8 @@
* along with SimpleRTP; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __SIMPLERTP_AUDIOHANDLER_H__
-#define __SIMPLERTP_AUDIOHANDLER_H__
+#ifndef __SIMPLERTP_AUDIOINPUTHANDLER_H__
+#define __SIMPLERTP_AUDIOINPUTHANDLER_H__
#include <QThread>
#include <QString>
@@ -33,11 +33,11 @@
#include "audioinput.h"
#include "opusencoder.h"
-class AudioHandler : public QThread {
+class AudioInputHandler : public QThread {
Q_OBJECT
public:
- AudioHandler(QString device);
- ~AudioHandler();
+ AudioInputHandler(QString device);
+ ~AudioInputHandler();
void run();
@@ -51,4 +51,4 @@ private:
volatile bool running;
};
-#endif/*__SIMPLERTP_AUDIOHANDLER_H__*/
+#endif/*__SIMPLERTP_AUDIOINPUTHANDLER_H__*/
diff --git a/src/audiooutputhandler.cc b/src/audiooutputhandler.cc
new file mode 100644
index 0000000..6a5056f
--- /dev/null
+++ b/src/audiooutputhandler.cc
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputhandler.cc
+ *
+ * Sat Sep 20 11:03:53 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "audiooutputhandler.h"
+
+AudioOutputHandler::AudioOutputHandler()
+{
+}
+
+void AudioOutputHandler::newAudio(Frame frame)
+{
+ char pcm[10000];
+ int ret = decoder.decode(frame, pcm, sizeof(pcm));
+ if(ret > 0) player.playSamples(pcm, ret);
+}
diff --git a/src/audiooutputhandler.h b/src/audiooutputhandler.h
new file mode 100644
index 0000000..ff2054e
--- /dev/null
+++ b/src/audiooutputhandler.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputhandler.h
+ *
+ * Sat Sep 20 11:03:52 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __SIMPLERTP_AUDIOOUTPUTHANDLER_H__
+#define __SIMPLERTP_AUDIOOUTPUTHANDLER_H__
+
+#include <QObject>
+
+#include "soundplayer.h"
+#include "opusdecoder.h"
+
+class AudioOutputHandler : public QObject {
+Q_OBJECT
+public:
+ AudioOutputHandler();
+
+public slots:
+ void newAudio(Frame frame);
+
+private:
+ SoundPlayer player;
+ OpusDecoder decoder;
+};
+
+#endif/*__SIMPLERTP_AUDIOOUTPUTHANDLER_H__*/
diff --git a/src/frame.cc b/src/frame.cc
index 4801897..38d6f0f 100644
--- a/src/frame.cc
+++ b/src/frame.cc
@@ -29,8 +29,33 @@
#include <stdio.h>
#include <stdlib.h>
+static unsigned long int ts_cnt = 0;
+
+Frame::Frame()
+{
+ data = NULL;
+ size = 0;
+ ts = 0;
+}
+
+Frame::Frame(const Frame &frame)
+{
+ data = frame.data;
+ size = frame.size;
+ ts = frame.ts;
+}
+
Frame::Frame(size_t s)
{
size = s;
data = (char*)malloc(size);
+ ts = ts_cnt++;
+}
+
+Frame::Frame(const char *d, size_t s)
+{
+ size = s;
+ data = (char*)malloc(size);
+ memcpy(data, d, s);
+ ts = ts_cnt++;
}
diff --git a/src/frame.h b/src/frame.h
index f5faebd..eb5cebe 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -29,12 +29,34 @@
#include <stdio.h>
#include <QVector>
+#include <QObject>
-class Frame {
+class Frame : public QObject {
+Q_OBJECT
public:
+ /**
+ * Empty fram, no data, size == 0
+ */
+ Frame();
+
+ /**
+ * Copy constructor, take sover pointer
+ */
+ Frame(const Frame &frame);
+
+ /**
+ * Allocate buffer
+ */
Frame(size_t s);
+
+ /**
+ * Allocate new buffer and copy data
+ */
+ Frame(const char *data, size_t size);
+
char *data;
size_t size;
+ unsigned long int ts;
};
typedef QVector< Frame* > framelist_t;
diff --git a/src/inputstreamer.cc b/src/inputstreamer.cc
new file mode 100644
index 0000000..a1d7aa9
--- /dev/null
+++ b/src/inputstreamer.cc
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * inputstreamer.cc
+ *
+ * Sat Sep 20 10:15:51 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "inputstreamer.h"
+
+#define KEY "123456789012345678901234567890123456789012345678901234567890"
+#define SSRC 1234567890
+#define CSRC_V 42
+#define CSRC_A 43
+
+InputStreamer::InputStreamer(QHostAddress addr, quint16 port)
+ : socket(this)
+{
+ total = 0;
+
+ socket.bind(port);
+ this->addr = addr;
+ this->port = port;
+
+ running = true;
+ start();
+}
+
+InputStreamer::~InputStreamer()
+{
+ running = false;
+ wait();
+}
+
+#include <unistd.h>
+void InputStreamer::run()
+{
+ lrtp_status_t status;
+
+ lrtp = lrtp_init(&status, KEY, SSRC);
+ if(status != LRTP_OK) printf("O:lrtp_init err: %d\n", status);
+
+ int res;
+ res = lrtp_create_profile(lrtp, PROFILE_JPEG, CSRC_V, OPTION_END);
+ if(res != 0) printf("O:lrtp_create_profile (v) err: %d\n", res);
+
+ res = lrtp_create_profile(lrtp, PROFILE_OPUS, CSRC_A, OPTION_END);
+ if(res != 0) printf("O:lrtp_create_profile (a) err: %d\n", res);
+
+ char packet[16*1024];
+ while(running) {
+ qint64 packetsize =
+ socket.readDatagram(packet, (quint64)sizeof(packet), 0,0);
+ if(packetsize < 1) {
+ usleep(1000);
+ continue;
+ }
+ total += packetsize;
+
+ // Now decode the sucker....
+ lrtp_unpack(lrtp, packet, packetsize);
+ int n = 0;
+ int ret;
+ char frame[512 * 1024]; // 512kbyte should be enough for even the larges
+ // JPEG frames...
+ unsigned int csrc;
+ unsigned int ts;
+ while((ret = lrtp_dequeue_frame(lrtp, frame, sizeof(frame), &csrc, &ts))
+ != 0) {
+ if(ret < 0) printf("\nlrtp_dequeue_frame: %d\n", ret);
+ if(csrc == CSRC_V) {
+ // Video frame
+ Frame f(frame, ret);
+ f.ts = ts;
+ emit newImage(f);
+ printf("v"); fflush(stdout);
+ } else if(csrc == CSRC_A) {
+ // Audio frame
+ Frame f(frame, ret);
+ f.ts = ts;
+ emit newAudio(f);
+ printf("a"); fflush(stdout);
+ } else {
+ printf("Unknown stream: CSRC: %d\n", csrc);
+ }
+ }
+ }
+
+ status = lrtp_destroy_profile(lrtp, CSRC_V);
+ if(status != LRTP_OK) printf("O:lrtp_destroy_profile (v) err: %d\n", status);
+
+ status = lrtp_destroy_profile(lrtp, CSRC_A);
+ if(status != LRTP_OK) printf("O:lrtp_destroy_profile (a) err: %d\n", status);
+
+ status = lrtp_close(lrtp);
+ if(status != LRTP_OK) printf("O:lrtp_close err: %d\n", status);
+}
+
+size_t InputStreamer::getTotal()
+{
+ size_t t = total;
+ total = 0;
+ return t;
+}
diff --git a/src/inputstreamer.h b/src/inputstreamer.h
new file mode 100644
index 0000000..168485e
--- /dev/null
+++ b/src/inputstreamer.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * inputstreamer.h
+ *
+ * Sat Sep 20 10:15:50 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __SIMPLERTP_INPUTSTREAMER_H__
+#define __SIMPLERTP_INPUTSTREAMER_H__
+
+#include <QObject>
+#include <QUdpSocket>
+#include <QThread>
+
+#include <lrtp.h>
+
+#include "frame.h"
+
+class InputStreamer : public QThread {
+Q_OBJECT
+public:
+ InputStreamer(QHostAddress addr, quint16 port);
+ ~InputStreamer();
+
+ void run();
+
+ size_t getTotal();
+
+signals:
+ void newImage(Frame frame);
+ void newAudio(Frame frame);
+
+private:
+ struct lrtp_t *lrtp;
+
+ QHostAddress addr;
+ quint16 port;
+
+ QUdpSocket socket;
+
+ size_t total;
+
+ volatile bool running;
+};
+
+#endif/*__SIMPLERTP_INPUTSTREAMER_H__*/
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index 4dcac58..3e31136 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -27,38 +27,85 @@
#include "mainwindow.h"
#include <QLabel>
+#include <QStatusBar>
+
#include <stdio.h>
-MainWindow::MainWindow(QString v4ldev, QString adev)
- : v4l(v4ldev), ah(adev)
+MainWindow::MainWindow(QString v4ldev, QString adev,
+ QHostAddress addr, quint16 port)
+ : v4l(v4ldev), aih(adev), ostreamer(addr, port), istreamer(addr, port)
{
- connect(&v4l, SIGNAL(newImage(QImage)),
- this, SLOT(newImage(QImage)));
+ /* // Self view:
+ connect(&v4l, SIGNAL(newImage(Frame)),
+ this, SLOT(newImage(Frame)));
+ */
+ connect(&istreamer, SIGNAL(newImage(Frame)),
+ this, SLOT(newImage(Frame)));
+
+ connect(&istreamer, SIGNAL(newAudio(Frame)),
+ &aoh, SLOT(newAudio(Frame)));
- connect(&ah, SIGNAL(newAudio(framelist_t)),
+ /*
+ connect(&aih, SIGNAL(newAudio(framelist_t)),
this, SLOT(newAudio(framelist_t)));
+ */
+ connect(&v4l, SIGNAL(newImage(Frame)),
+ &ostreamer, SLOT(newImage(Frame)));
+
+ connect(&aih, SIGNAL(newAudio(framelist_t)),
+ &ostreamer, SLOT(newAudio(framelist_t)));
+
+ connect(&status_timer, SIGNAL(timeout()),
+ this, SLOT(updateStatus()));
+
+ status_timer.start(1000);
setCentralWidget(new QLabel());
+
+ statusBar()->showMessage("Starting...");
}
-void MainWindow::newImage(QImage img)
+void MainWindow::updateStatus()
{
+ size_t ob = ostreamer.getTotal() / 60 / 1024;
+ size_t ib = istreamer.getTotal() / 60 / 1024;
+ QString status =
+ "In: " + QString::number(ib) + "kb/s"
+ + " - " +
+ "Out: " + QString::number(ob) + "kb/s"
+ ;
+ statusBar()->showMessage(status);
+}
+
+void MainWindow::newImage(Frame frame)
+{
+ QImage img;
+ bool res = img.loadFromData((const uchar*)frame.data, frame.size, "JPG");
+ // printf("processImage() => %s\n", res?"true":"false");
if(img.isNull()) {
printf("Invalid image\n");
return;
}
- printf("img->w: %d\n", img.width());
- printf("img->h: %d\n", img.height());
+ // printf("img->w: %d\n", img.width());
+ // printf("img->h: %d\n", img.height())
QLabel *l = (QLabel*)centralWidget();
QPixmap p;
p.convertFromImage(img);
l->setPixmap(p);
- printf("Got one\n");
+
+ // printf("v"); fflush(stdout);
}
void MainWindow::newAudio(framelist_t list)
{
- printf("audio: %d frames\n", list.size());
+ /*
+ framelist_t::iterator i = list.begin();
+ while(i != list.end()) {
+ sp.playSamples(*i);
+ }
+ // printf("audio: %d frames\n", list.size());
+ */
+ // printf("a"); fflush(stdout);
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 0ce1f4a..78bd50b 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -29,22 +29,32 @@
#include <QMainWindow>
#include <QString>
+#include <QTimer>
#include "v4l.h"
-#include "audiohandler.h"
+#include "audioinputhandler.h"
+#include "audiooutputhandler.h"
+#include "outputstreamer.h"
+#include "inputstreamer.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
- MainWindow(QString v4ldev, QString adev);
+ MainWindow(QString v4ldev, QString adev, QHostAddress addr, quint16 port);
public slots:
- void newImage(QImage img);
+ void newImage(Frame frame);
void newAudio(framelist_t list);
+ void updateStatus();
private:
V4L v4l;
- AudioHandler ah;
+ AudioInputHandler aih;
+ AudioOutputHandler aoh;
+ OutputStreamer ostreamer;
+ InputStreamer istreamer;
+
+ QTimer status_timer;
};
#endif/*__SIMPLERTP_MAINWINDOW_H__*/
diff --git a/src/opusdecoder.cc b/src/opusdecoder.cc
new file mode 100644
index 0000000..195c699
--- /dev/null
+++ b/src/opusdecoder.cc
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * opusdecoder.cc
+ *
+ * Sat Sep 20 11:15:23 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "opusdecoder.h"
+
+OpusDecoder::OpusDecoder()
+{
+ int err;
+ decoder = opus_decoder_create(48000, 1, &err);
+ if(err) printf("opus_decoder_create: %d\n", err);
+}
+
+OpusDecoder::~OpusDecoder()
+{
+ if(decoder) opus_decoder_destroy(decoder);
+}
+
+int OpusDecoder::decode(Frame frame, char *pcm, size_t size)
+{
+ if(!decoder) {
+ printf("Missing opus decoder handle\n");
+ return 0;
+ }
+
+ int res = opus_decode(decoder,
+ (const unsigned char*)frame.data, frame.size,
+ (opus_int16*)pcm, size, 0);
+ if(res >= 0) return res * sizeof(short);
+ printf("opus_decode: %d\n", res);
+}
diff --git a/src/opusdecoder.h b/src/opusdecoder.h
new file mode 100644
index 0000000..13ee09e
--- /dev/null
+++ b/src/opusdecoder.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * opusdecoder.h
+ *
+ * Sat Sep 20 11:15:23 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __SIMPLERTP_OPUSDECODER_H__
+#define __SIMPLERTP_OPUSDECODER_H__
+
+#include <opus/opus.h>
+
+#include "frame.h"
+
+// Frame size 10ms
+#define OPUS_FRAME_SIZE 10
+
+class OpusDecoder {
+public:
+ OpusDecoder();
+ ~OpusDecoder();
+
+ int decode(Frame frame, char *pcm, size_t size);
+
+private:
+ struct OpusDecoder *decoder;
+};
+
+#endif/*__SIMPLERTP_OPUSDECODER_H__*/
diff --git a/src/opusencoder.cc b/src/opusencoder.cc
index 77ea0d1..b5c343a 100644
--- a/src/opusencoder.cc
+++ b/src/opusencoder.cc
@@ -27,98 +27,62 @@
#include "opusencoder.h"
#include <string.h>
-#include <opus/opus.h>
#include <stdio.h>
-#include "samplecache.h"
-
#define OPUS_BITRATE 64000
-struct opus_encoder_private_t {
- OpusEncoder *ce;
- SampleCache *cache;
-};
-
OpusEncoder::OpusEncoder()
+ : cache(5760 * 10)
{
- prv = new struct opus_encoder_private_t;
-
- prv->cache = new SampleCache(5760 * 10);
-
int error = 0;
-
- samplerate_t srate = opus_samplerate();
-
- prv->ce =
- opus_encoder_create(srate, 1/*channels()*/, OPUS_APPLICATION_AUDIO, &error);
- if(!prv->ce || error != OPUS_OK) {
- printf("srate: %d, ch: %d, Error: %d\n", srate, 1/*channels()*/, error);
- //throw InitException();
+ encoder =
+ opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &error);
+ if(!encoder || error != OPUS_OK) {
+ printf("opus_encoder_create: %d\n", error);
}
// 500 to 512000
- opus_encoder_ctl(prv->ce, OPUS_SET_BITRATE(OPUS_BITRATE/*bitrate()*/));
+ opus_encoder_ctl(encoder, OPUS_SET_BITRATE(OPUS_BITRATE));
// [0-10] with 10 representing the highest complexity.
- opus_encoder_ctl(prv->ce, OPUS_SET_COMPLEXITY(10));
-
- /*
- printf("Encoder(fs: %d, ch: %d, bitrate: %d)\n", srate, channels(),
- bitrate());
- */
+ opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(10));
}
OpusEncoder::~OpusEncoder()
{
- if(prv) {
- if(prv->ce) opus_encoder_destroy(prv->ce);
- if(prv->cache) delete prv->cache;
- delete prv;
- }
+ if(encoder) opus_encoder_destroy(encoder);
}
unsigned int OpusEncoder::framesize()
{
- return opus_samplerate() / 1000 * OPUS_FRAME_SIZE; // 10ms audio data
-}
-
-samplerate_t OpusEncoder::opus_samplerate()
-{
- return 48000;
+ return 48000 / 1000 * OPUS_FRAME_SIZE; // 10ms audio data
}
framelist_t OpusEncoder::encode(const char *pcm, size_t size)
{
framelist_t list;
- // printf("PCM size: %d\n", size);
-
- samplerate_t srate = opus_samplerate();
-
- if(prv->ce == NULL) {
+ if(encoder == NULL) {
//throw InitException();
- printf("prv->ce == NULL\n");
+ printf("encoder == NULL\n");
}
- size_t bytes_per_packet = ((OPUS_BITRATE/*bitrate()*/ *framesize())/srate+4)/8;
+ size_t bytes_per_packet = ((OPUS_BITRATE *framesize())/48000+4)/8;
- prv->cache->addSamples((short*)pcm, size / sizeof(short));
+ cache.addSamples((short*)pcm, size / sizeof(short));
//size_t p = 0;
opus_int16 *samples = new opus_int16[framesize()];
- while(prv->cache->cacheSize() >= framesize()) {
- size_t sz = prv->cache->getSamples(samples, framesize());
+ while(cache.cacheSize() >= framesize()) {
+ size_t sz = cache.getSamples(samples, framesize());
Frame *frame = new Frame(bytes_per_packet);
- int n = opus_encode(prv->ce, samples, sz / 1/*channels()*//*sizeof(short)*/,
+ int n = opus_encode(encoder, samples, sz / 1,
(unsigned char *)frame->data, (opus_int32)frame->size);
- //printf("Compressed to %d\n", n);
-
if(n < 0) {
printf("n < 0\n");
- //throw EncodingException();
}
frame->size = n;
@@ -127,7 +91,5 @@ framelist_t OpusEncoder::encode(const char *pcm, size_t size)
}
delete[] samples;
- //printf("%d frames in list\n", list.size());
-
return list;
}
diff --git a/src/opusencoder.h b/src/opusencoder.h
index b0e16fd..9aeaf3a 100644
--- a/src/opusencoder.h
+++ b/src/opusencoder.h
@@ -27,13 +27,14 @@
#ifndef __SIMPLERTP_OPUS_ENCODER_H__
#define __SIMPLERTP_OPUS_ENCODER_H__
+#include <opus/opus.h>
+
#include "frame.h"
+#include "samplecache.h"
// Frame size 10ms
#define OPUS_FRAME_SIZE 10
-struct opus_encoder_private_t;
-
class OpusEncoder {
public:
OpusEncoder();
@@ -41,11 +42,11 @@ public:
framelist_t encode(const char *pcm, size_t size);
- samplerate_t opus_samplerate();
unsigned int framesize();
private:
- struct opus_encoder_private_t *prv;
+ struct OpusEncoder *encoder;
+ SampleCache cache;
};
#endif/*__SIMPLERTP_OPUS_ENCODER_H__*/
diff --git a/src/outputstreamer.cc b/src/outputstreamer.cc
new file mode 100644
index 0000000..e652c7e
--- /dev/null
+++ b/src/outputstreamer.cc
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * streamer.cc
+ *
+ * Fri Sep 19 21:05:08 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "outputstreamer.h"
+
+#define KEY "123456789012345678901234567890123456789012345678901234567890"
+#define SSRC 1234567890
+#define CSRC_V 42
+#define CSRC_A 43
+
+OutputStreamer::OutputStreamer(QHostAddress addr, quint16 port)
+ : socket(this)
+{
+ total = 0;
+
+ lrtp_status_t status;
+
+ lrtp = lrtp_init(&status, KEY, SSRC);
+ if(status != LRTP_OK) printf("O:lrtp_init err: %d\n", status);
+
+ int res;
+ res = lrtp_create_profile(lrtp, PROFILE_JPEG, CSRC_V, OPTION_END);
+ if(res != 0) printf("O:lrtp_create_profile (v) err: %d\n", res);
+
+ res = lrtp_create_profile(lrtp, PROFILE_OPUS, CSRC_A, OPTION_END);
+ if(res != 0) printf("O:lrtp_create_profile (a) err: %d\n", res);
+
+ this->addr = addr;
+ this->port = port;
+}
+
+OutputStreamer::~OutputStreamer()
+{
+ lrtp_status_t status;
+
+ status = lrtp_destroy_profile(lrtp, CSRC_V);
+ if(status != LRTP_OK) printf("O:lrtp_destroy_profile (v) err: %d\n", status);
+
+ status = lrtp_destroy_profile(lrtp, CSRC_A);
+ if(status != LRTP_OK) printf("O:lrtp_destroy_profile (a) err: %d\n", status);
+
+ status = lrtp_close(lrtp);
+ if(status != LRTP_OK) printf("O:lrtp_close err: %d\n", status);
+}
+
+void OutputStreamer::newImage(Frame frame)
+{
+ int ret = 0;
+ ret = lrtp_enqueue_frame(lrtp, CSRC_V,
+ frame.data, frame.size, frame.ts,
+ LRTP_COPY);
+ if(ret != 0) printf("O:lrtp_enqueue_frame (v) err: %d\n", ret);
+
+ char packet[16*1024];
+ while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) > 0) {
+ //printf("v"); fflush(stdout);
+ sendPackage(packet, ret);
+ }
+ //CPPUNIT_ASSERT_EQUAL(ret, 0);
+
+ free(frame.data);
+ // delete frame;
+ //free(frame);
+}
+
+void OutputStreamer::newAudio(framelist_t frames)
+{
+ framelist_t::iterator fi = frames.begin();
+ while(fi != frames.end()) {
+ Frame *frame = *fi;
+
+ int ret = 0;
+ ret = lrtp_enqueue_frame(lrtp, CSRC_A,
+ frame->data, frame->size, frame->ts,
+ LRTP_COPY);
+ if(ret != 0) printf("O:lrtp_enqueue_frame (a) err: %d\n", ret);
+
+ char packet[16*1024];
+ while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) > 0) {
+ //printf("a"); fflush(stdout);
+ sendPackage(packet, ret);
+ }
+ //CPPUNIT_ASSERT_EQUAL(ret, 0);
+
+ free(frame->data);
+ delete frame;
+ //free(frame);
+
+ fi++;
+ }
+}
+
+void OutputStreamer::sendPackage(const char *data, size_t size)
+{
+ total += size;
+ socket.writeDatagram(data, (quint64)size, addr, port);
+}
+
+size_t OutputStreamer::getTotal()
+{
+ size_t t = total;
+ total = 0;
+ return t;
+}
diff --git a/src/outputstreamer.h b/src/outputstreamer.h
new file mode 100644
index 0000000..f53d35a
--- /dev/null
+++ b/src/outputstreamer.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * outputstreamer.h
+ *
+ * Fri Sep 19 21:05:07 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of SimpleRTP.
+ *
+ * SimpleRTP 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.
+ *
+ * SimpleRTP 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 SimpleRTP; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __SIMPLERTP_STREAMER_H__
+#define __SIMPLERTP_STREAMER_H__
+
+#include <QObject>
+#include <QUdpSocket>
+
+#include <lrtp.h>
+
+#include "frame.h"
+
+class OutputStreamer : public QObject {
+Q_OBJECT
+public:
+ OutputStreamer(QHostAddress addr, quint16 port);
+ ~OutputStreamer();
+
+ size_t getTotal();
+
+public slots:
+ void newImage(Frame frame);
+ void newAudio(framelist_t frames);
+
+private:
+ void sendPackage(const char *data, size_t size);
+
+ struct lrtp_t *lrtp;
+
+ QHostAddress addr;
+ quint16 port;
+
+ QUdpSocket socket;
+
+ size_t total;
+};
+
+#endif/*__SIMPLERTP_STREAMER_H__*/
diff --git a/src/simplertp.cc b/src/simplertp.cc
index 837bec5..eea3ebd 100644
--- a/src/simplertp.cc
+++ b/src/simplertp.cc
@@ -34,11 +34,13 @@ int main(int argc, char *argv[])
QString v4ldev = "/dev/video0";
QString adev = "hw:2,0";
+ QHostAddress addr("192.168.0.10");
+ quint16 port = 10000;
if(argc > 1) v4ldev = argv[1];
if(argc > 2) adev = argv[2];
- MainWindow wnd(v4ldev, adev);
+ MainWindow wnd(v4ldev, adev, addr, port);
wnd.show();
return app.exec();
diff --git a/src/soundplayer.cc b/src/soundplayer.cc
new file mode 100644
index 0000000..6aea2bf
--- /dev/null
+++ b/src/soundplayer.cc
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * soundplayer.cc
+ *
+ * Fri Sep 5 17:31:28 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Kaiman.
+ *
+ * Kaiman 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.
+ *
+ * Kaiman 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 Kaiman; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "soundplayer.h"
+
+#include <ao/ao.h>
+#include <sndfile.h>
+
+#define BUFSZ 512
+
+SoundPlayer::SoundPlayer()
+{
+ start();
+}
+
+SoundPlayer::~SoundPlayer()
+{
+ running = false;
+ wait();
+}
+
+void SoundPlayer::run()
+{
+
+ printf("SoundPlayer running\n");
+
+ ao_initialize();
+
+ ao_sample_format sf;
+ memset(&sf, 0, sizeof(sf));
+ sf.bits = 16;
+ sf.rate = 16000;
+ sf.channels = 1;
+ sf.byte_format = AO_FMT_NATIVE;
+
+ ao_device *dev = ao_open_live(ao_default_driver_id(), &sf, 0);
+
+ running = true;
+
+ short s[BUFSZ];
+ while(running) {
+ sem.acquire();
+
+ char *pcm;
+ size_t size;
+
+ {
+ QMutexLocker lock(&mutex);
+ pcm = qi.pcm;
+ size = qi.size;
+ }
+
+ printf("."); fflush(stdout);
+
+ ao_play(dev, pcm, size);
+
+ //free(pcm);
+
+ /*
+ memset(s, 0, BUFSZ * sizeof(short));
+
+ QList<QueueItem>::iterator it = active.begin();
+ while(it != active.end()) {
+ QueueItem &item = *it;
+
+ for(size_t i = 0; i < BUFSZ; i++) {
+ if(item.pos >= item.size) {
+ free(item.samples);
+ it = active.erase(it);
+ goto nextitem;
+ }
+ s[i] += item.samples[item.pos];
+ item.pos++;
+ }
+
+ it++;
+
+ nextitem:
+ int a = 1;(void)a;
+ }
+
+ ao_play(dev, (char*)s, BUFSZ * sizeof(short));
+ */
+ }
+
+ ao_close(dev);
+ ao_shutdown();
+}
+
+void SoundPlayer::playSamples(const char *pcm, size_t size)
+{
+ QMutexLocker lock(&mutex);
+
+ qi.pcm = (char*)malloc(size);
+ memcpy(qi.pcm, pcm, size);
+ qi.size = size;
+
+ sem.release();
+}
diff --git a/src/soundplayer.h b/src/soundplayer.h
new file mode 100644
index 0000000..28c0cf8
--- /dev/null
+++ b/src/soundplayer.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * soundplayer.h
+ *
+ * Fri Sep 5 17:31:27 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Kaiman.
+ *
+ * Kaiman 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.
+ *
+ * Kaiman 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 Kaiman; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __KAIMAN_SOUNDPLAYER_H__
+#define __KAIMAN_SOUNDPLAYER_H__
+
+#include <QThread>
+#include <QString>
+#include <QList>
+#include <QMutex>
+#include <QSemaphore>
+
+#include "frame.h"
+
+class QueueItem {
+public:
+ char *pcm;
+ size_t size;
+};
+
+class SoundPlayer : public QThread {
+public:
+ SoundPlayer();
+ ~SoundPlayer();
+
+ void playSamples(const char *pcm, size_t size);
+
+ void run();
+
+private:
+ volatile bool running;
+ QMutex mutex;
+ QSemaphore sem;
+
+ QueueItem qi;
+
+ QList<QueueItem> queue;
+ QList<QueueItem> active;
+};
+
+#endif/*__KAIMAN_SOUNDPLAYER_H__*/
diff --git a/src/v4l.cc b/src/v4l.cc
index 38f53b7..55b0397 100644
--- a/src/v4l.cc
+++ b/src/v4l.cc
@@ -44,6 +44,8 @@
#include <linux/videodev2.h>
+#include <QMetaType>
+
extern "C" {
#include <jpeglib.h>
}
@@ -791,6 +793,8 @@ int main(int argc, char **argv)
V4L::V4L(QString device)
{
+ qRegisterMetaType<Frame>("Frame");
+
dev_name = strdup(device.toStdString().c_str());
v4l = this; // Set global V4L object pointer.
@@ -823,8 +827,12 @@ void V4L::run()
void V4L::processImage(const void *p, int size)
{
+ /*
QImage img;
bool res = img.loadFromData((const uchar *)p, size, "JPG");
- printf("processImage() => %s\n", res?"true":"false");
+ //printf("processImage() => %s\n", res?"true":"false");
if(res) emit newImage(img);
+ */
+ Frame frame((const char *)p, size);
+ emit newImage(frame);
}
diff --git a/src/v4l.h b/src/v4l.h
index 2fe474e..7d381f0 100644
--- a/src/v4l.h
+++ b/src/v4l.h
@@ -28,9 +28,10 @@
#define __SIMPLERTP_V4L_H__
#include <QThread>
-#include <QImage>
#include <QString>
+#include "frame.h"
+
class V4L : public QThread {
Q_OBJECT
public:
@@ -42,7 +43,7 @@ public:
void processImage(const void *p, int size);
signals:
- void newImage(QImage image);
+ void newImage(Frame frame);
};
#endif/*__SIMPLERTP_V4L_H__*/