From d38f56b9fe300ee8aab1db1bf5f6b91ca613fe67 Mon Sep 17 00:00:00 2001 From: Sebastian Wolf Date: Sat, 2 Jan 2021 00:15:25 +0100 Subject: [PATCH] Recording Vorbis files works & connected to UI --- harbour-fernschreiber.pro | 2 +- qml/components/VoiceNoteOverlay.qml | 145 ++++++++++++++++++-- qml/pages/ChatPage.qml | 5 + src/fernschreiberutils.cpp | 104 +++++++++++++- src/fernschreiberutils.h | 46 ++++++- src/harbour-fernschreiber.cpp | 1 + translations/harbour-fernschreiber-de.ts | 24 ++++ translations/harbour-fernschreiber-en.ts | 24 ++++ translations/harbour-fernschreiber-es.ts | 24 ++++ translations/harbour-fernschreiber-fi.ts | 24 ++++ translations/harbour-fernschreiber-hu.ts | 24 ++++ translations/harbour-fernschreiber-it.ts | 24 ++++ translations/harbour-fernschreiber-pl.ts | 24 ++++ translations/harbour-fernschreiber-ru.ts | 24 ++++ translations/harbour-fernschreiber-sv.ts | 24 ++++ translations/harbour-fernschreiber-zh_CN.ts | 24 ++++ translations/harbour-fernschreiber.ts | 24 ++++ 17 files changed, 555 insertions(+), 12 deletions(-) diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index 4c1e850..5823b5a 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -16,7 +16,7 @@ CONFIG += sailfishapp sailfishapp_i18n PKGCONFIG += nemonotifications-qt5 zlib -QT += core dbus sql +QT += core dbus sql multimedia DEFINES += QT_STATICPLUGIN diff --git a/qml/components/VoiceNoteOverlay.qml b/qml/components/VoiceNoteOverlay.qml index fb2b92a..66dcb4f 100644 --- a/qml/components/VoiceNoteOverlay.qml +++ b/qml/components/VoiceNoteOverlay.qml @@ -1,5 +1,5 @@ /* - Copyright (C) 2020 Sebastian J. Wolf and other contributors + Copyright (C) 2020-21 Sebastian J. Wolf and other contributors This file is part of Fernschreiber. @@ -18,13 +18,74 @@ */ import QtQuick 2.6 import Sailfish.Silica 1.0 +import WerkWolf.Fernschreiber 1.0 import "../components" import "../js/twemoji.js" as Emoji +import "../js/debug.js" as Debug Item { id: voiceNoteOverlayItem anchors.fill: parent + property int recordingState: fernschreiberUtils.getVoiceNoteRecordingState(); + property int recordingDuration: 0; + + function handleRecordingState() { + switch (recordingState) { + case FernschreiberUtilities.Unavailable: + recordingStateLabel.text = qsTr("Unavailable"); + break; + case FernschreiberUtilities.Stopped: + recordingStateLabel.text = qsTr("Stopped"); + break; + case FernschreiberUtilities.Starting: + recordingStateLabel.text = qsTr("Starting"); + break; + case FernschreiberUtilities.Recording: + recordingStateLabel.text = qsTr("Recording"); + break; + case FernschreiberUtilities.Stopping: + recordingStateLabel.text = qsTr("Stopping"); + break; + } + } + + function getTwoDigitString(numberToBeConverted) { + var numberString = "00"; + if (numberToBeConverted > 0 && numberToBeConverted < 10) { + numberString = "0" + String(numberToBeConverted); + } + if (numberToBeConverted >= 10) { + numberString = String(numberToBeConverted); + } + return numberString; + } + + function handleRecordingDuration() { + var minutes = Math.floor(recordingDuration / 60); + var seconds = recordingDuration % 60; + recordingDurationLabel.text = getTwoDigitString(minutes) + ":" + getTwoDigitString(seconds); + } + + Component.onCompleted: { + handleRecordingState(); + handleRecordingDuration(); + } + + Connections { + target: fernschreiberUtils + onVoiceNoteDurationChanged: { + Debug.log("New duration received: " + duration); + recordingDuration = Math.round(duration / 1000); + handleRecordingDuration(); + } + onVoiceNoteRecordingStateChanged: { + Debug.log("New state received: " + state); + recordingState = state; + handleRecordingState(); + } + } + Rectangle { id: stickerPickerOverlayBackground anchors.fill: parent @@ -52,17 +113,85 @@ Item { text: qsTr("Record a Voice Note") } - Image { - id: recorderImage - source: "image://theme/icon-l-recorder" + Label { + wrapMode: Text.Wrap + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + horizontalAlignment: Text.AlignHCenter + text: qsTr("Press the button to start recording") + font.pixelSize: Theme.fontSizeMedium anchors { horizontalCenter: parent.horizontalCenter } + } - fillMode: Image.PreserveAspectFit - asynchronous: true - width: Theme.itemSizeLarge - height: Theme.itemSizeLarge + Item { + width: Theme.iconSizeExtraLarge + height: Theme.iconSizeExtraLarge + anchors { + horizontalCenter: parent.horizontalCenter + } + Rectangle { + color: Theme.primaryColor + opacity: Theme.opacityOverlay + width: Theme.iconSizeExtraLarge + height: Theme.iconSizeExtraLarge + anchors.centerIn: parent + radius: width / 2 + } + + Rectangle { + id: recordButton + color: "red" + width: Theme.iconSizeExtraLarge * 0.6 + height: Theme.iconSizeExtraLarge * 0.6 + anchors.centerIn: parent + radius: width / 2 + MouseArea { + anchors.fill: parent + onClicked: { + recordButton.visible = false; + fernschreiberUtils.startRecordingVoiceNote(); + } + } + } + + Rectangle { + id: stopButton + visible: !recordButton.visible + color: Theme.overlayBackgroundColor + width: Theme.iconSizeExtraLarge * 0.4 + height: Theme.iconSizeExtraLarge * 0.4 + anchors.centerIn: parent + MouseArea { + anchors.fill: parent + onClicked: { + recordButton.visible = true; + fernschreiberUtils.stopRecordingVoiceNote(); + } + } + } + } + + Label { + id: recordingStateLabel + wrapMode: Text.Wrap + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Theme.fontSizeMedium + anchors { + horizontalCenter: parent.horizontalCenter + } + } + + Label { + id: recordingDurationLabel + wrapMode: Text.Wrap + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Theme.fontSizeMedium + anchors { + horizontalCenter: parent.horizontalCenter + } } } diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index f5f0aeb..0cdbb6f 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -1145,6 +1145,11 @@ Page { width: parent.width height: active ? parent.height : 0 source: "../components/VoiceNoteOverlay.qml" + onActiveChanged: { + if (!active) { + fernschreiberUtils.stopRecordingVoiceNote(); + } + } } } diff --git a/src/fernschreiberutils.cpp b/src/fernschreiberutils.cpp index b75734a..d079d59 100644 --- a/src/fernschreiberutils.cpp +++ b/src/fernschreiberutils.cpp @@ -1,10 +1,57 @@ -#include "fernschreiberutils.h" +/* + Copyright (C) 2020-21 Sebastian J. Wolf and other contributors + This file is part of Fernschreiber. + + Fernschreiber 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. + + Fernschreiber 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 Fernschreiber. If not, see . +*/ + +#include "fernschreiberutils.h" #include #include +#include +#include +#include +#include +#include + +#define DEBUG_MODULE FernschreiberUtils +#include "debuglog.h" FernschreiberUtils::FernschreiberUtils(QObject *parent) : QObject(parent) { + LOG("Initializing audio recorder..."); + + QString temporaryDirectoryPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + + "/harbour-fernschreiber"; + QDir temporaryDirectory(temporaryDirectoryPath); + if (!temporaryDirectory.exists()) { + temporaryDirectory.mkpath(temporaryDirectoryPath); + } + + QAudioEncoderSettings encoderSettings; + encoderSettings.setCodec("audio/vorbis"); + encoderSettings.setChannelCount(1); + encoderSettings.setQuality(QMultimedia::LowQuality); + this->audioRecorder.setEncodingSettings(encoderSettings); + this->audioRecorder.setContainerFormat("ogg"); + this->audioRecorder.setOutputLocation(QUrl::fromLocalFile(temporaryDirectoryPath + "/voicenote.ogg")); + + QMediaRecorder::Status audioRecorderStatus = this->audioRecorder.status(); + this->handleAudioRecorderStatusChanged(audioRecorderStatus); + + connect(&audioRecorder, SIGNAL(durationChanged(qlonglong)), this, SIGNAL(voiceNoteDurationChanged(qlonglong))); + connect(&audioRecorder, SIGNAL(statusChanged(QMediaRecorder::Status)), this, SLOT(handleAudioRecorderStatusChanged(QMediaRecorder::Status))); } @@ -128,3 +175,58 @@ QString FernschreiberUtils::getUserName(const QVariantMap &userInformation) const QString lastName = userInformation.value("last_name").toString(); return QString(firstName + " " + lastName).trimmed(); } + +void FernschreiberUtils::startRecordingVoiceNote() +{ + LOG("Start recording voice note..."); + QString voiceNotePath = this->voiceNotePath(); + LOG("Using temporary file at " << voiceNotePath); + if (QFile::exists(voiceNotePath)) { + LOG("Removing old temporary file..."); + QFile::remove(voiceNotePath); + } + this->audioRecorder.setVolume(1); + this->audioRecorder.record(); +} + +void FernschreiberUtils::stopRecordingVoiceNote() +{ + LOG("Stop recording voice note..."); + this->audioRecorder.stop(); +} + +QString FernschreiberUtils::voiceNotePath() +{ + return this->audioRecorder.outputLocation().toLocalFile(); +} + +FernschreiberUtils::VoiceNoteRecordingState FernschreiberUtils::getVoiceNoteRecordingState() +{ + return this->voiceNoteRecordingState; +} + +void FernschreiberUtils::handleAudioRecorderStatusChanged(QMediaRecorder::Status status) +{ + LOG("Audio recorder status changed:" << status); + switch (status) { + case QMediaRecorder::UnavailableStatus: + case QMediaRecorder::UnloadedStatus: + case QMediaRecorder::LoadingStatus: + this->voiceNoteRecordingState = VoiceNoteRecordingState::Unavailable; + break; + case QMediaRecorder::LoadedStatus: + case QMediaRecorder::PausedStatus: + this->voiceNoteRecordingState = VoiceNoteRecordingState::Stopped; + break; + case QMediaRecorder::StartingStatus: + this->voiceNoteRecordingState = VoiceNoteRecordingState::Starting; + break; + case QMediaRecorder::FinalizingStatus: + this->voiceNoteRecordingState = VoiceNoteRecordingState::Stopping; + break; + case QMediaRecorder::RecordingStatus: + this->voiceNoteRecordingState = VoiceNoteRecordingState::Recording; + break; + } + emit voiceNoteRecordingStateChanged(this->voiceNoteRecordingState); +} diff --git a/src/fernschreiberutils.h b/src/fernschreiberutils.h index 35fc8a0..16e80c3 100644 --- a/src/fernschreiberutils.h +++ b/src/fernschreiberutils.h @@ -1,7 +1,27 @@ +/* + Copyright (C) 2020-21 Sebastian J. Wolf and other contributors + + This file is part of Fernschreiber. + + Fernschreiber 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. + + Fernschreiber 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 Fernschreiber. If not, see . +*/ + #ifndef FERNSCHREIBERUTILS_H #define FERNSCHREIBERUTILS_H #include +#include #include "tdlibwrapper.h" class FernschreiberUtils : public QObject @@ -10,12 +30,34 @@ class FernschreiberUtils : public QObject public: explicit FernschreiberUtils(QObject *parent = nullptr); + enum VoiceNoteRecordingState { + Unavailable, + Stopped, + Starting, + Recording, + Stopping + }; + Q_ENUM(VoiceNoteRecordingState) + static QString getMessageShortText(TDLibWrapper *tdLibWrapper, const QVariantMap &messageContent, const bool isChannel, const qlonglong currentUserId, const QVariantMap &messageSender); static QString getUserName(const QVariantMap &userInformation); -signals: + Q_INVOKABLE void startRecordingVoiceNote(); + Q_INVOKABLE void stopRecordingVoiceNote(); + Q_INVOKABLE QString voiceNotePath(); + Q_INVOKABLE VoiceNoteRecordingState getVoiceNoteRecordingState(); + +signals: + void voiceNoteDurationChanged(qlonglong duration); + void voiceNoteRecordingStateChanged(VoiceNoteRecordingState state); + +private slots: + void handleAudioRecorderStatusChanged(QMediaRecorder::Status status); + +private: + QAudioRecorder audioRecorder; + VoiceNoteRecordingState voiceNoteRecordingState; -public slots: }; #endif // FERNSCHREIBERUTILS_H diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp index 6efdf5d..0852fea 100644 --- a/src/harbour-fernschreiber.cpp +++ b/src/harbour-fernschreiber.cpp @@ -82,6 +82,7 @@ int main(int argc, char *argv[]) FernschreiberUtils *fernschreiberUtils = new FernschreiberUtils(view.data()); context->setContextProperty("fernschreiberUtils", fernschreiberUtils); + qmlRegisterUncreatableType(uri, 1, 0, "FernschreiberUtilities", QString()); DBusAdaptor *dBusAdaptor = tdLibWrapper->getDBusAdaptor(); context->setContextProperty("dBusAdaptor", dBusAdaptor); diff --git a/translations/harbour-fernschreiber-de.ts b/translations/harbour-fernschreiber-de.ts index 10db4a5..6894a9e 100644 --- a/translations/harbour-fernschreiber-de.ts +++ b/translations/harbour-fernschreiber-de.ts @@ -1438,6 +1438,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-en.ts b/translations/harbour-fernschreiber-en.ts index ffaad43..e474f3f 100644 --- a/translations/harbour-fernschreiber-en.ts +++ b/translations/harbour-fernschreiber-en.ts @@ -1438,6 +1438,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-es.ts b/translations/harbour-fernschreiber-es.ts index 57c7541..5f812e5 100644 --- a/translations/harbour-fernschreiber-es.ts +++ b/translations/harbour-fernschreiber-es.ts @@ -1417,6 +1417,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-fi.ts b/translations/harbour-fernschreiber-fi.ts index 2739023..cb1004c 100644 --- a/translations/harbour-fernschreiber-fi.ts +++ b/translations/harbour-fernschreiber-fi.ts @@ -1439,6 +1439,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-hu.ts b/translations/harbour-fernschreiber-hu.ts index 630f4ae..a160d2d 100644 --- a/translations/harbour-fernschreiber-hu.ts +++ b/translations/harbour-fernschreiber-hu.ts @@ -1417,6 +1417,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-it.ts b/translations/harbour-fernschreiber-it.ts index 5c18e4c..d0319bc 100644 --- a/translations/harbour-fernschreiber-it.ts +++ b/translations/harbour-fernschreiber-it.ts @@ -1438,6 +1438,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-pl.ts b/translations/harbour-fernschreiber-pl.ts index dd55b46..fc7f215 100644 --- a/translations/harbour-fernschreiber-pl.ts +++ b/translations/harbour-fernschreiber-pl.ts @@ -1459,6 +1459,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-ru.ts b/translations/harbour-fernschreiber-ru.ts index 0edb938..d3b4699 100644 --- a/translations/harbour-fernschreiber-ru.ts +++ b/translations/harbour-fernschreiber-ru.ts @@ -1459,6 +1459,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-sv.ts b/translations/harbour-fernschreiber-sv.ts index 2a159af..0bbb2e4 100644 --- a/translations/harbour-fernschreiber-sv.ts +++ b/translations/harbour-fernschreiber-sv.ts @@ -1438,6 +1438,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber-zh_CN.ts b/translations/harbour-fernschreiber-zh_CN.ts index 44d8a9e..437b5d8 100644 --- a/translations/harbour-fernschreiber-zh_CN.ts +++ b/translations/harbour-fernschreiber-zh_CN.ts @@ -1417,6 +1417,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview diff --git a/translations/harbour-fernschreiber.ts b/translations/harbour-fernschreiber.ts index f0b5aa4..5664771 100644 --- a/translations/harbour-fernschreiber.ts +++ b/translations/harbour-fernschreiber.ts @@ -1438,6 +1438,30 @@ Record a Voice Note + + Press the button to start recording + + + + Unavailable + + + + Stopped + + + + Starting + + + + Recording + + + + Stopping + + WebPagePreview