mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-04 16:01:14 -05:00
DSD demod plugin: fixed DV Serial concurrent support
This commit is contained in:
parent
d01a4166eb
commit
be467fdc24
@ -113,14 +113,18 @@ It is based on the [DSDcc](https://github.com/f4exb/dsdcc) C++ library which is
|
|||||||
|
|
||||||
If you have one or more serial devices interfacing the AMBE3000 chip in packet mode you can use them to decode AMBE voice frames. For that purpose you will need to compile with [SerialDV](https://github.com/f4exb/serialDV) support. Please refer to this project Readme.md to compile and install SerialDV. If you install it in a custom location say `/opt/install/serialdv` you will need to add these defines to the cmake command: `-DLIBSERIALDV_INCLUDE_DIR=/opt/install/serialdv/include/serialdv -DLIBSERIALDV_LIBRARY=/opt/install/serialdv/lib/libserialdv.so`
|
If you have one or more serial devices interfacing the AMBE3000 chip in packet mode you can use them to decode AMBE voice frames. For that purpose you will need to compile with [SerialDV](https://github.com/f4exb/serialDV) support. Please refer to this project Readme.md to compile and install SerialDV. If you install it in a custom location say `/opt/install/serialdv` you will need to add these defines to the cmake command: `-DLIBSERIALDV_INCLUDE_DIR=/opt/install/serialdv/include/serialdv -DLIBSERIALDV_LIBRARY=/opt/install/serialdv/lib/libserialdv.so`
|
||||||
|
|
||||||
Such serial devices work with a serial interface at 400 kb. While this seems large for a serial interface this limits the throughput and hence the capability of decoding several channels in parallel. The software can enqueue requests over many devices so the more you have the more channels you can decode in parallel. Note also that a channel that does not output voice frames will not require a device for decoding.
|
Although such serial devices work with a serial interface at 400 kb in practice maybe for other reasons they are capable of handling only one conversation at a time. The software will allocate the device dynamically to a conversation with an inactivity timeout of 500ms. In practice you will have to have as many devices connected to your system as the number of conversations you would like to be handled in parallel.
|
||||||
|
|
||||||
Note that this is not supported in Windows.
|
Note that this is not supported in Windows because of trouble with COM port support (contributors welcome!).
|
||||||
|
|
||||||
Alternatively you can use [mbelib](https://github.com/szechyjs/mbelib) but mbelib comes with some copyright issues (see next). If you have mbelib installed in a custom location, say `/opt/install/mbelib` you will need to add these defines to the cmake command: `-DLIBMBE_INCLUDE_DIR=/opt/install/mbelib/include -DLIBMBE_LIBRARY=/opt/install/mbelib/lib/libmbe.so`
|
Alternatively you can use [mbelib](https://github.com/szechyjs/mbelib) but mbelib comes with some copyright issues (see next). If you have mbelib installed in a custom location, say `/opt/install/mbelib` you will need to add these defines to the cmake command: `-DLIBMBE_INCLUDE_DIR=/opt/install/mbelib/include -DLIBMBE_LIBRARY=/opt/install/mbelib/lib/libmbe.so`
|
||||||
|
|
||||||
|
Possible copyright issues apart (see next) the audio quality with the DVSI AMBE chip is much better.
|
||||||
|
|
||||||
While DSDcc is intended to be patent-free, `mbelib` that it uses describes functions that may be covered by one or more U.S. patents owned by DVSI Inc. The source code itself should not be infringing as it merely describes possible methods of implementation. Compiling or using `mbelib` may infringe on patents rights in your jurisdiction and/or require licensing. It is unknown if DVSI will sell licenses for software that uses `mbelib`.
|
While DSDcc is intended to be patent-free, `mbelib` that it uses describes functions that may be covered by one or more U.S. patents owned by DVSI Inc. The source code itself should not be infringing as it merely describes possible methods of implementation. Compiling or using `mbelib` may infringe on patents rights in your jurisdiction and/or require licensing. It is unknown if DVSI will sell licenses for software that uses `mbelib`.
|
||||||
|
|
||||||
|
Possible copyright issues apart the audio quality with the DVSI AMBE chip is much better.
|
||||||
|
|
||||||
If you are not comfortable with this just do not install DSDcc and/or mbelib and the plugin will not be compiled and added to SDRangel. For packaged distributions just remove from the installation directory:
|
If you are not comfortable with this just do not install DSDcc and/or mbelib and the plugin will not be compiled and added to SDRangel. For packaged distributions just remove from the installation directory:
|
||||||
|
|
||||||
- For Linux distributions: `plugins/channel/libdemoddsd.so`
|
- For Linux distributions: `plugins/channel/libdemoddsd.so`
|
||||||
|
@ -24,9 +24,11 @@ You can use a serial device connected to your system that implements and exposes
|
|||||||
- Compile with [SerialDV](https://github.com/f4exb/serialDV) support Please refer to this project Readme.md to compile and install SerialDV. If you install it in a custom location say `/opt/install/serialdv` you will need to add these defines to the cmake command: `-DLIBSERIALDV_INCLUDE_DIR=/opt/install/serialdv/include/serialdv -DLIBSERIALDV_LIBRARY=/opt/install/serialdv/lib/libserialdv.so`
|
- Compile with [SerialDV](https://github.com/f4exb/serialDV) support Please refer to this project Readme.md to compile and install SerialDV. If you install it in a custom location say `/opt/install/serialdv` you will need to add these defines to the cmake command: `-DLIBSERIALDV_INCLUDE_DIR=/opt/install/serialdv/include/serialdv -DLIBSERIALDV_LIBRARY=/opt/install/serialdv/lib/libserialdv.so`
|
||||||
- Enable DV serial devices in your system by checking the option in the Preferences menu. YOu will need to enable the DV serial devices each time you start SDRangel.
|
- Enable DV serial devices in your system by checking the option in the Preferences menu. YOu will need to enable the DV serial devices each time you start SDRangel.
|
||||||
|
|
||||||
Please note that such serial devices work with a serial interface at 400 kb. While this seems large for a serial interface this limits the throughput and hence the capability of decoding several channels in parallel. The software can enqueue requests over many devices so the more you have the more channels you can decode in parallel. Note also that a channel that does not output voice frames will not require a device for decoding so only channels that receive voice frames at any one time will require a DV serial device.
|
Although such serial devices work with a serial interface at 400 kb in practice maybe for other reasons they are capable of handling only one conversation at a time. The software will allocate the device dynamically to a conversation with an inactivity timeout of 500ms. In practice you will have to have as many devices connected to your system as the number of conversations you would like to be handled in parallel.
|
||||||
|
|
||||||
Note also that this is not supported in Windows.
|
Note also that this is not supported in Windows because of trouble with COM port support (contributors welcome!).
|
||||||
|
|
||||||
|
Altermatively you can use software decoding with Mbelib. Possible copyright issues apart (see next) the audio quality with the DVSI AMBE chip is much better.
|
||||||
|
|
||||||
<h2>Mbelib support</h2>
|
<h2>Mbelib support</h2>
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
#include "audio/audiooutput.h"
|
#include "audio/audiooutput.h"
|
||||||
#include "dvserialengine.h"
|
#include "dvserialengine.h"
|
||||||
@ -198,6 +199,7 @@ bool DVSerialEngine::scan()
|
|||||||
connect(controller.worker, SIGNAL(finished()), controller.worker, SLOT(deleteLater()));
|
connect(controller.worker, SIGNAL(finished()), controller.worker, SLOT(deleteLater()));
|
||||||
connect(controller.thread, SIGNAL(finished()), controller.thread, SLOT(deleteLater()));
|
connect(controller.thread, SIGNAL(finished()), controller.thread, SLOT(deleteLater()));
|
||||||
connect(&controller.worker->m_inputMessageQueue, SIGNAL(messageEnqueued()), controller.worker, SLOT(handleInputMessages()));
|
connect(&controller.worker->m_inputMessageQueue, SIGNAL(messageEnqueued()), controller.worker, SLOT(handleInputMessages()));
|
||||||
|
connect(controller.worker->m_timer, SIGNAL(timeout()), controller.worker, SLOT(releaseQueue()));
|
||||||
controller.thread->start();
|
controller.thread->start();
|
||||||
|
|
||||||
m_controllers.push_back(controller);
|
m_controllers.push_back(controller);
|
||||||
@ -247,20 +249,37 @@ void DVSerialEngine::getDevicesNames(std::vector<std::string>& deviceNames)
|
|||||||
void DVSerialEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo)
|
void DVSerialEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo)
|
||||||
{
|
{
|
||||||
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
||||||
|
std::vector<DVSerialController>::iterator itAvail = m_controllers.end();
|
||||||
|
bool done = false;
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
while (it != m_controllers.end())
|
while (it != m_controllers.end())
|
||||||
{
|
{
|
||||||
if (it->worker->m_inputMessageQueue.size() < 2)
|
if (it->worker->m_audioFifo == audioFifo)
|
||||||
{
|
{
|
||||||
it->worker->m_inputMessageQueue.push(DVSerialWorker::MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo));
|
it->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo);
|
||||||
break;
|
done = true;
|
||||||
|
}
|
||||||
|
else if (it->worker->m_audioFifo == 0)
|
||||||
|
{
|
||||||
|
itAvail = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it == m_controllers.end())
|
if (!done)
|
||||||
{
|
{
|
||||||
qDebug("DVSerialEngine::pushMbeFrame: no DV serial device available. MBE frame dropped");
|
if (itAvail != m_controllers.end())
|
||||||
|
{
|
||||||
|
int wNum = itAvail - m_controllers.begin();
|
||||||
|
|
||||||
|
qDebug("DVSerialEngine::pushMbeFrame: push %p on empty queue %d", audioFifo, wNum);
|
||||||
|
itAvail->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("DVSerialEngine::pushMbeFrame: no DV serial device available. MBE frame dropped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#define SDRBASE_DSP_DVSERIALENGINE_H_
|
#define SDRBASE_DSP_DVSERIALENGINE_H_
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -60,6 +61,7 @@ private:
|
|||||||
std::list<std::string> m_comList;
|
std::list<std::string> m_comList;
|
||||||
std::list<std::string> m_comList8250;
|
std::list<std::string> m_comList8250;
|
||||||
std::vector<DVSerialController> m_controllers;
|
std::vector<DVSerialController> m_controllers;
|
||||||
|
QMutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,10 +32,14 @@ DVSerialWorker::DVSerialWorker() :
|
|||||||
{
|
{
|
||||||
m_audioBuffer.resize(48000);
|
m_audioBuffer.resize(48000);
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
m_audioFifo = 0;
|
||||||
|
m_timer = new QTimer(this);
|
||||||
|
m_timer->setSingleShot(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
DVSerialWorker::~DVSerialWorker()
|
DVSerialWorker::~DVSerialWorker()
|
||||||
{
|
{
|
||||||
|
delete m_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DVSerialWorker::open(const std::string& serialDevice)
|
bool DVSerialWorker::open(const std::string& serialDevice)
|
||||||
@ -70,6 +74,7 @@ void DVSerialWorker::stop()
|
|||||||
void DVSerialWorker::handleInputMessages()
|
void DVSerialWorker::handleInputMessages()
|
||||||
{
|
{
|
||||||
Message* message;
|
Message* message;
|
||||||
|
m_timer->start(500); // FIFO queue holding timeout
|
||||||
|
|
||||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||||
{
|
{
|
||||||
@ -81,8 +86,6 @@ void DVSerialWorker::handleInputMessages()
|
|||||||
if (m_dvController.decode(m_dvAudioSamples, decodeMsg->getMbeFrame(), decodeMsg->getMbeRate(), dBVolume))
|
if (m_dvController.decode(m_dvAudioSamples, decodeMsg->getMbeFrame(), decodeMsg->getMbeRate(), dBVolume))
|
||||||
{
|
{
|
||||||
upsample6(m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels(), decodeMsg->getAudioFifo());
|
upsample6(m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels(), decodeMsg->getAudioFifo());
|
||||||
// upsample6(m_dvAudioSamples, m_audioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE);
|
|
||||||
// decodeMsg->getAudioFifo()->write((const quint8 *) m_audioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE * 6, 10);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -94,6 +97,21 @@ void DVSerialWorker::handleInputMessages()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DVSerialWorker::pushMbeFrame(const unsigned char *mbeFrame,
|
||||||
|
int mbeRateIndex,
|
||||||
|
int mbeVolumeIndex,
|
||||||
|
unsigned char channels, AudioFifo *audioFifo)
|
||||||
|
{
|
||||||
|
m_audioFifo = audioFifo;
|
||||||
|
m_inputMessageQueue.push(MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DVSerialWorker::releaseQueue()
|
||||||
|
{
|
||||||
|
qDebug("DVSerialWorker::releaseQueue: release %p", m_audioFifo);
|
||||||
|
m_audioFifo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void DVSerialWorker::upsample6(short *in, int nbSamplesIn, unsigned char channels, AudioFifo *audioFifo)
|
void DVSerialWorker::upsample6(short *in, int nbSamplesIn, unsigned char channels, AudioFifo *audioFifo)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < nbSamplesIn; i++)
|
for (int i = 0; i < nbSamplesIn; i++)
|
||||||
@ -134,6 +152,7 @@ void DVSerialWorker::upsample6(short *in, short *out, int nbSamplesIn)
|
|||||||
int prev = (int) m_upsamplerLastValue;
|
int prev = (int) m_upsamplerLastValue;
|
||||||
short up;
|
short up;
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
// for (int j = 0; j < 6; j++)
|
// for (int j = 0; j < 6; j++)
|
||||||
// {
|
// {
|
||||||
// up = 32768.0f * cos(m_phase);
|
// up = 32768.0f * cos(m_phase);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -83,6 +84,12 @@ public:
|
|||||||
DVSerialWorker();
|
DVSerialWorker();
|
||||||
~DVSerialWorker();
|
~DVSerialWorker();
|
||||||
|
|
||||||
|
void pushMbeFrame(const unsigned char *mbeFrame,
|
||||||
|
int mbeRateIndex,
|
||||||
|
int mbeVolumeIndex,
|
||||||
|
unsigned char channels,
|
||||||
|
AudioFifo *audioFifo);
|
||||||
|
|
||||||
bool open(const std::string& serialDevice);
|
bool open(const std::string& serialDevice);
|
||||||
void close();
|
void close();
|
||||||
void process();
|
void process();
|
||||||
@ -95,13 +102,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||||
|
AudioFifo *m_audioFifo;
|
||||||
|
QTimer *m_timer;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void inputMessageReady();
|
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleInputMessages();
|
void handleInputMessages();
|
||||||
|
void releaseQueue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct AudioSample {
|
struct AudioSample {
|
||||||
|
Loading…
Reference in New Issue
Block a user