File indexing completed on 2024-04-21 08:32:06

0001 #include "audiotranscribe.h"
0002 #include <QJsonObject>
0003 #include <QJsonArray>
0004 #include <QJsonDocument>
0005 #include <QRandomGenerator>
0006 #include <QDebug>
0007 
0008 AudioTranscribe::AudioTranscribe(QObject *parent)
0009     : QObject(parent),
0010       m_controller(Controller::instance())
0011 {
0012 
0013     if (m_controller->status() != Controller::Open){
0014         m_controller->start();
0015     }
0016 
0017     connect(m_controller, &Controller::socketStatusChanged, this,
0018             [this]() {
0019         if (m_controller->status() == Controller::Open){
0020             connect(m_controller, &Controller::messageReceived, this,
0021                     &AudioTranscribe::onMainSocketMessageReceived);
0022         }
0023     });
0024 
0025     QAudioFormat format;
0026     format.setCodec(QStringLiteral("audio/PCM"));
0027     format.setSampleRate(16000);
0028     format.setSampleSize(16);
0029     format.setChannelCount(1);
0030     format.setByteOrder(QAudioFormat::LittleEndian);
0031     format.setSampleType(QAudioFormat::SignedInt);
0032 
0033     QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
0034     if (!info.isFormatSupported(format)) {
0035         format = info.nearestFormat(format);
0036         format.setSampleRate(16000);
0037         qDebug() << "Raw audio format not supported by backend. Trying the nearest format.";
0038     }
0039 
0040     m_audioInput = new QAudioInput(format, this);
0041 }
0042 
0043 void AudioTranscribe::start()
0044 {
0045     emit startRequested();
0046     startRecording();
0047     m_stage = 1;
0048 }
0049 
0050 void AudioTranscribe::stop(){
0051     emit endRequested();
0052     endRecording();
0053 }
0054 
0055 void AudioTranscribe::sendData()
0056 {
0057     if (m_controller->status() == Controller::Open){
0058         QJsonObject root;
0059         qDebug() << "Sending Data";
0060         root[QStringLiteral("responseid")] = getRequestIdentifier();
0061         root[QStringLiteral("file")] = QStringLiteral("/tmp/%1_in.raw").arg(m_requestIdentifier);
0062         m_controller->sendRequest(QStringLiteral("libqmycroft.request.transcribe"), root.toVariantMap());
0063     }
0064 }
0065 
0066 void AudioTranscribe::startRecording()
0067 {
0068     destinationFile.setFileName(QStringLiteral("/tmp/%1_in.raw").arg(m_requestIdentifier));
0069     destinationFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
0070     m_audioInput->start(&destinationFile);
0071     emit recordingStarted();
0072 }
0073 
0074 void AudioTranscribe::endRecording()
0075 {
0076     m_audioInput->stop();
0077     destinationFile.close();
0078     emit recordingEnded();
0079     sendData();
0080     m_stage = 0;
0081 }
0082 
0083 void AudioTranscribe::generateRequestIdentifier()
0084 {
0085     m_requestIdentifier = QRandomGenerator::global()->bounded(10000, 99999);
0086     emit requestIdentifierGenerated();
0087 }
0088 
0089 QString AudioTranscribe::getRequestIdentifier()
0090 {
0091     return QString::number(m_requestIdentifier);
0092 }
0093 
0094 void AudioTranscribe::onMainSocketMessageReceived(const QString &message)
0095 {
0096     auto doc = QJsonDocument::fromJson(message.toUtf8());
0097 
0098     if (doc.isEmpty()) {
0099         qWarning() << "Empty or invalid JSON message arrived on the main socket:" << message;
0100         return;
0101     }
0102 
0103     auto type = doc[QStringLiteral("type")].toString();
0104     if(type == QStringLiteral("libqmycroft.request.transcribe.result")){
0105         QString targetResponseId = doc[QStringLiteral("data")][QStringLiteral("targetResponseId")].toString();
0106         QString targetResult = doc[QStringLiteral("data")][QStringLiteral("targetResult")].toString();
0107         if(targetResponseId == getRequestIdentifier()) {
0108             emit responseReceived(targetResult);
0109         }
0110     }
0111 }
0112 
0113 AudioTranscribe::Status AudioTranscribe::status() const
0114 {
0115     switch(m_stage)
0116     {
0117     case 0:
0118         return Inactive;
0119     case 1:
0120         return Active;
0121     default:
0122         return Inactive;
0123     }
0124 }