File indexing completed on 2024-05-12 16:27:14

0001 /*
0002    SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "createsoundmessagewidget.h"
0008 #include <KConfigGroup>
0009 #include <KLocalizedString>
0010 #include <KMessageWidget>
0011 #include <KSharedConfig>
0012 #include <QAudioDevice>
0013 #include <QAudioInput>
0014 #include <QComboBox>
0015 #include <QDir>
0016 #include <QHBoxLayout>
0017 #include <QLabel>
0018 #include <QMediaDevices>
0019 #include <QTemporaryFile>
0020 #include <QToolButton>
0021 
0022 namespace
0023 {
0024 const char mySoundGroupName[] = "Message Sound";
0025 }
0026 
0027 CreateSoundMessageWidget::CreateSoundMessageWidget(QWidget *parent)
0028     : QWidget{parent}
0029     , mRecordButton(new QToolButton(this))
0030     , mPauseButton(new QToolButton(this))
0031     , mStopButton(new QToolButton(this))
0032     , mLabelDuration(new QLabel(this))
0033     , mAudioRecorder(new QMediaRecorder(this))
0034     , mDeviceComboBox(new QComboBox(this))
0035     , mMessageWidget(new KMessageWidget(this))
0036 {
0037     mCaptureSession.setRecorder(mAudioRecorder);
0038     mCaptureSession.setAudioInput(new QAudioInput(this));
0039 
0040     auto mainLayout = new QVBoxLayout(this);
0041     mainLayout->setObjectName(QStringLiteral("mainLayout"));
0042     mainLayout->setContentsMargins({});
0043 
0044     mMessageWidget->setObjectName(QStringLiteral("mMessageWidget"));
0045     mainLayout->addWidget(mMessageWidget);
0046     mMessageWidget->setVisible(false);
0047     mMessageWidget->setCloseButtonVisible(false);
0048     mMessageWidget->setMessageType(KMessageWidget::Information);
0049     mMessageWidget->setWordWrap(true);
0050 
0051     mDeviceComboBox->setObjectName(QStringLiteral("mDeviceComboBox"));
0052     mainLayout->addWidget(mDeviceComboBox);
0053 
0054     auto soundWidgetLayout = new QHBoxLayout;
0055     soundWidgetLayout->setObjectName(QStringLiteral("mainLayout"));
0056     mainLayout->addLayout(soundWidgetLayout);
0057 
0058     mStopButton->setObjectName(QStringLiteral("mStopButton"));
0059     mStopButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop")));
0060     soundWidgetLayout->addWidget(mStopButton);
0061     connect(mStopButton, &QToolButton::clicked, this, &CreateSoundMessageWidget::stop);
0062 
0063     mPauseButton->setObjectName(QStringLiteral("mPauseButton"));
0064     mPauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
0065     soundWidgetLayout->addWidget(mPauseButton);
0066     connect(mPauseButton, &QToolButton::clicked, this, &CreateSoundMessageWidget::pause);
0067 
0068     mRecordButton->setObjectName(QStringLiteral("mRecordButton"));
0069     mRecordButton->setIcon(QIcon::fromTheme(QStringLiteral("media-record")));
0070     soundWidgetLayout->addWidget(mRecordButton);
0071     connect(mRecordButton, &QToolButton::clicked, this, &CreateSoundMessageWidget::record);
0072 
0073     mLabelDuration->setObjectName(QStringLiteral("mLabelDuration"));
0074     mLabelDuration->setTextFormat(Qt::PlainText);
0075     soundWidgetLayout->addWidget(mLabelDuration);
0076 
0077     connect(mAudioRecorder, &QMediaRecorder::durationChanged, this, &CreateSoundMessageWidget::updateRecordTime);
0078     connect(mAudioRecorder, &QMediaRecorder::recorderStateChanged, this, &CreateSoundMessageWidget::updateRecorderState);
0079     connect(mAudioRecorder, &QMediaRecorder::errorChanged, this, &CreateSoundMessageWidget::displayRecorderError);
0080     initializeInput();
0081     updateRecorderState(mAudioRecorder->recorderState());
0082 }
0083 
0084 CreateSoundMessageWidget::~CreateSoundMessageWidget()
0085 {
0086     delete mTemporaryFile;
0087 }
0088 
0089 void CreateSoundMessageWidget::loadSettings()
0090 {
0091     KConfigGroup group(KSharedConfig::openConfig(), QLatin1String(mySoundGroupName));
0092     const QByteArray deviceIdentifier = group.readEntry("SoundDevice", QByteArray());
0093     if (!deviceIdentifier.isEmpty()) {
0094         for (int i = 0; i < mDeviceComboBox->count(); ++i) {
0095             const QAudioDevice audioDevice = mDeviceComboBox->itemData(i).value<QAudioDevice>();
0096             if (audioDevice.id() == deviceIdentifier) {
0097                 mDeviceComboBox->setCurrentIndex(i);
0098                 break;
0099             }
0100         }
0101     }
0102 }
0103 
0104 void CreateSoundMessageWidget::saveSettings()
0105 {
0106     KConfigGroup group(KSharedConfig::openConfig(), QLatin1String(mySoundGroupName));
0107     const auto device = mDeviceComboBox->itemData(mDeviceComboBox->currentIndex()).value<QAudioDevice>();
0108     if (!device.isNull()) {
0109         const QByteArray deviceIdentifier = device.id();
0110         group.writeEntry("SoundDevice", deviceIdentifier);
0111     }
0112 }
0113 
0114 void CreateSoundMessageWidget::displayRecorderError()
0115 {
0116     if (mAudioRecorder->error() != QMediaRecorder::NoError) {
0117         mMessageWidget->setText(mAudioRecorder->errorString());
0118         mMessageWidget->animatedShow();
0119     }
0120 }
0121 
0122 void CreateSoundMessageWidget::initializeInput()
0123 {
0124     mDeviceComboBox->addItem(i18n("Default"), QVariant(QString()));
0125     for (const auto &device : QMediaDevices::audioInputs()) {
0126         const auto name = device.description();
0127         mDeviceComboBox->addItem(name, QVariant::fromValue(device));
0128     }
0129 
0130     mTemporaryFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/ruqola_XXXXXX")); // TODO fix extension
0131     mTemporaryFile->setAutoRemove(false);
0132     mTemporaryFile->open();
0133     //        QMediaFormat format;
0134     //        format.setFileFormat(QMediaFormat::FileFormat::AVI);
0135     //        mMediaRecorder->setMediaFormat(format);
0136     // Define url temporary file.
0137     mAudioRecorder->setOutputLocation(QUrl::fromLocalFile(mTemporaryFile->fileName()));
0138     // qDebug() << " store " << mTemporaryFile->fileName();
0139 }
0140 
0141 void CreateSoundMessageWidget::updateRecordTime(qint64 duration)
0142 {
0143     const QString str = i18n("Recorded %1 sec", duration / 1000);
0144     mLabelDuration->setText(str);
0145 }
0146 
0147 QUrl CreateSoundMessageWidget::temporaryFilePath() const
0148 {
0149     // qDebug() << "output location" << mMediaRecorder->outputLocation() << " dd " << mMediaRecorder->actualLocation();
0150     return mAudioRecorder->actualLocation();
0151 }
0152 
0153 void CreateSoundMessageWidget::stop()
0154 {
0155     mAudioRecorder->stop();
0156     Q_EMIT recordDone();
0157 }
0158 
0159 void CreateSoundMessageWidget::record()
0160 {
0161     mCaptureSession.audioInput()->setDevice(mDeviceComboBox->itemData(mDeviceComboBox->currentIndex()).value<QAudioDevice>());
0162     mAudioRecorder->record();
0163 }
0164 
0165 void CreateSoundMessageWidget::pause()
0166 {
0167     mAudioRecorder->pause();
0168 }
0169 
0170 void CreateSoundMessageWidget::updateRecorderState(QMediaRecorder::RecorderState state)
0171 {
0172     switch (state) {
0173     case QMediaRecorder::StoppedState:
0174         mRecordButton->setEnabled(true);
0175         mPauseButton->setEnabled(true);
0176         mStopButton->setEnabled(false);
0177         break;
0178     case QMediaRecorder::PausedState:
0179         mRecordButton->setEnabled(true);
0180         mPauseButton->setEnabled(false);
0181         mStopButton->setEnabled(true);
0182         break;
0183     case QMediaRecorder::RecordingState:
0184         mRecordButton->setEnabled(false);
0185         mPauseButton->setEnabled(true);
0186         mStopButton->setEnabled(true);
0187         break;
0188     }
0189 }
0190 
0191 #include "moc_createsoundmessagewidget.cpp"