You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
4.7 KiB
C++

/*
Copyright (C) 2019-2021 Doug McLain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "codec.h"
#include <iostream>
#include <dlfcn.h>
#ifdef USE_FLITE
extern "C" {
extern cst_voice * register_cmu_us_slt(const char *);
extern cst_voice * register_cmu_us_kal16(const char *);
extern cst_voice * register_cmu_us_awb(const char *);
}
#endif
Codec::Codec(QString callsign, char module, QString hostname, QString host, int port, bool ipv6, QString vocoder, QString modem, QString audioin, QString audioout) :
m_module(module),
m_hostname(hostname),
m_tx(false),
m_ttsid(0),
m_audioin(audioin),
m_audioout(audioout),
m_rxwatchdog(0),
#ifdef Q_OS_WIN
m_rxtimerint(19),
#else
m_rxtimerint(20),
#endif
m_txtimerint(19),
m_vocoder(vocoder),
m_modemport(modem),
m_modem(nullptr),
m_ambedev(nullptr),
m_hwrx(false),
m_hwtx(false),
m_ipv6(ipv6)
{
m_modeinfo.callsign = callsign;
m_modeinfo.gwid = 0;
m_modeinfo.srcid = 0;
m_modeinfo.dstid = 0;
m_modeinfo.host = host;
m_modeinfo.port = port;
m_modeinfo.count = 0;
m_modeinfo.frame_number = 0;
m_modeinfo.frame_total = 0;
m_modeinfo.streamid = 0;
m_modeinfo.stream_state = STREAM_IDLE;
m_modeinfo.vocoder_loaded = false;
#ifdef USE_FLITE
flite_init();
voice_slt = register_cmu_us_slt(nullptr);
voice_kal = register_cmu_us_kal16(nullptr);
voice_awb = register_cmu_us_awb(nullptr);
#endif
}
Codec::~Codec()
{
}
void Codec::in_audio_vol_changed(qreal v)
{
m_audio->set_input_volume(v);
}
void Codec::out_audio_vol_changed(qreal v)
{
m_audio->set_output_volume(v);
}
void Codec::agc_state_changed(int s)
{
qDebug() << "Codec::agc_state_changed() called s == " << s;
m_audio->set_agc(s);
}
void Codec::send_connect()
{
m_modeinfo.status = CONNECTING;
if(m_ipv6 && (m_modeinfo.host != "none")){
qDebug() << "Host == " << m_modeinfo.host;
QList<QHostAddress> h;
QHostInfo i;
h.append(QHostAddress(m_modeinfo.host));
i.setAddresses(h);
hostname_lookup(i);
}
else{
QHostInfo::lookupHost(m_modeinfo.host, this, SLOT(hostname_lookup(QHostInfo)));
}
}
void Codec::toggle_tx(bool tx)
{
tx ? start_tx() : stop_tx();
}
void Codec::start_tx()
{
if(m_hwtx){
m_ambedev->clear_queue();
}
m_txcodecq.clear();
m_tx = true;
m_txcnt = 0;
m_ttscnt = 0;
m_rxtimer->stop();
m_modeinfo.streamid = 0;
m_modeinfo.stream_state = TRANSMITTING;
#ifdef USE_FLITE
if(m_ttsid == 1){
tts_audio = flite_text_to_wave(m_ttstext.toStdString().c_str(), voice_kal);
}
else if(m_ttsid == 2){
tts_audio = flite_text_to_wave(m_ttstext.toStdString().c_str(), voice_awb);
}
else if(m_ttsid == 3){
tts_audio = flite_text_to_wave(m_ttstext.toStdString().c_str(), voice_slt);
}
#endif
if(!m_txtimer->isActive()){
if(m_ttsid == 0){
m_audio->set_input_buffer_size(640);
m_audio->start_capture();
//audioin->start(&audio_buffer);
}
m_txtimer->start(m_txtimerint);
}
}
void Codec::stop_tx()
{
m_tx = false;
}
bool Codec::load_vocoder_plugin()
{
QString config_path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_WIN)
config_path += "/dudetronics";
#endif
#if defined(Q_OS_ANDROID)
QString voc = config_path + "/vocoder_plugin." + QSysInfo::productType() + "." + QSysInfo::currentCpuArchitecture();
#else
QString voc = config_path + "/vocoder_plugin." + QSysInfo::kernelType() + "." + QSysInfo::currentCpuArchitecture();
#endif
//QString voc = "/mnt/data/src/mbe_vocoder/vocoder_plugin.linux.x86_64.so";
void* a = dlopen(voc.toLocal8Bit(), RTLD_LAZY);
if (!a) {
qDebug() << "Cannot load library: " << QString::fromLocal8Bit(dlerror());
return false;
}
dlerror();
create_t* create_a = (create_t*) dlsym(a, "create");
const char* dlsym_error = dlerror();
if (dlsym_error) {
qDebug() << "Cannot load symbol create: " << QString::fromLocal8Bit(dlsym_error);
return false;
}
m_mbevocoder = create_a();
qDebug() << voc + " loaded";
return true;
}
void Codec::deleteLater()
{
if(m_modeinfo.status == CONNECTED_RW){
m_udp->disconnect();
m_ping_timer->stop();
send_disconnect();
delete m_audio;
if(m_hwtx){
delete m_ambedev;
}
if(m_modem){
delete m_modem;
}
}
m_modeinfo.count = 0;
QObject::deleteLater();
}