在QML API中,目前并没有一个相应的API来进行录音。我们必须使用Qt C++ API QAudioRecorder来进行录音的工作。在这篇文章中,我们来介绍如何使用这个API来进行录音。
首先,我们来创建一个“QML App with C++ plugin (qmake)”模版的应用。注意qmake的项目必须是在15.04及以上的target上才可以运行。
为了录音,我创建了一个叫做“AudioRecorder”的类:
#ifndef AUDIORECORDER_H #define AUDIORECORDER_H #include <QAudioRecorder> #include <QUrl> class AudioRecorder : public QObject { Q_OBJECT Q_PROPERTY ( bool recording READ recording NOTIFY recordingChanged ) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) public: explicit AudioRecorder(QObject *parent = 0); const bool recording() const; QString name() const; Q_INVOKABLE QStringList supportedAudioCodecs(); Q_INVOKABLE QStringList supportedContainers(); Q_INVOKABLE QUrl path() { return m_path; } signals: void recordingChanged(bool); void nameChanged(QUrl); public slots: void setName(QString name); void setRecording(bool recording ); void record(); void stop(); private: QString getFilePath(const QString filename) const; private: QAudioRecorder * m_audioRecorder; bool m_recording; QString m_name; QUrl m_path; }; #endif // AUDIORECORDER_H
#include <QUrl> #include <QStandardPaths> #include <QDir> #include "audiorecorder.h" AudioRecorder::AudioRecorder(QObject *parent) : QObject(parent) { m_audioRecorder = new QAudioRecorder( this ); QAudioEncoderSettings audioSettings; audioSettings.setCodec("audio/PCM"); audioSettings.setQuality(QMultimedia::HighQuality); m_audioRecorder->setEncodingSettings(audioSettings); // https://forum.qt.io/topic/42541/recording-audio-using-qtaudiorecorder/2 m_audioRecorder->setContainerFormat("wav"); m_recording = false; } const bool AudioRecorder::recording() const { return m_recording; } void AudioRecorder::setRecording(bool recording ) { if (m_recording == recording) return; m_recording = recording; emit recordingChanged(m_recording); } void AudioRecorder::record() { qDebug() << "Entering record!"; if ( m_audioRecorder->state() == QMediaRecorder::StoppedState ) { qDebug() << "recording....! "; m_audioRecorder->record ( ); m_recording = true; qDebug() << "m_recording: " << m_recording; emit recordingChanged(m_recording); } } void AudioRecorder::stop() { qDebug() << "Entering stop!"; if ( m_audioRecorder->state() == QMediaRecorder::RecordingState ) { qDebug() << "Stopping...."; m_audioRecorder->stop(); m_recording = false; emit recordingChanged(m_recording); } } QString AudioRecorder::name() const { return m_name; } void AudioRecorder::setName(QString name) { if (m_name == name) return; m_name = name; emit nameChanged(name); // at the same time update the path m_path = QUrl(getFilePath(name)); // set the path m_audioRecorder->setOutputLocation(m_path); } QStringList AudioRecorder::supportedAudioCodecs() { return m_audioRecorder->supportedAudioCodecs(); } QStringList AudioRecorder::supportedContainers() { return m_audioRecorder->supportedContainers(); } QString AudioRecorder::getFilePath(const QString filename) const { QString writablePath = QStandardPaths:: writableLocation(QStandardPaths::DataLocation); qDebug() << "writablePath: " << writablePath; QString absolutePath = QDir(writablePath).absolutePath(); qDebug() << "absoluePath: " << absolutePath; // We need to make sure we have the path for storage QDir dir(absolutePath); if ( dir.mkdir(absolutePath) ) { qDebug() << "Successfully created the path!"; } QString path = absolutePath + "/" + filename; qDebug() << "path: " << path; return path; }
import QtQuick 2.0 import Ubuntu.Components 1.1 import QtMultimedia 5.0 import AudioRecorder 1.0 /*! \brief MainView with a Label and Button elements. */ MainView { // objectName for functional testing purposes (autopilot-qt5) objectName: "mainView" // Note! applicationName needs to match the "name" field of the click manifest applicationName: "audiorecorder.liu-xiao-guo" /* This property enables the application to change orientation when the device is rotated. The default is false. */ //automaticOrientation: true // Removes the old toolbar and enables new features of the new header. useDeprecatedToolbar: false width: units.gu(60) height: units.gu(85) Page { title: i18n.tr("AudioRecorder") AudioRecorder { id: audio name: "sample.wav" onRecordingChanged: { console.log("recording: " + recording); } } MediaPlayer { id: player autoPlay: true volume: 1.0 } Column { anchors.fill: parent spacing: units.gu(1) Label { text: "Supported Audio codecs:" } ListView { id: audiocodecs width: parent.width height: audiocodecs.contentHeight model:audio.supportedAudioCodecs() delegate: Text { text: modelData } } Rectangle { width: parent.width height: units.gu(0.1) } Label { text: "Supported Containers:" } ListView { id: audiocontainer width: parent.width height: audiocontainer.contentHeight model:audio.supportedContainers() delegate: Text { text: modelData } } } Row { anchors.bottom: parent.bottom anchors.bottomMargin: units.gu(2) anchors.horizontalCenter: parent.horizontalCenter anchors.margins: units.gu(2) spacing: units.gu(2) Button { id: record text: "Record Audio" enabled: !audio.recording onClicked: { audio.record(); } } Button { id: stop text: "Stop" onClicked: { audio.stop(); player.stop(); } } Button { id: play text: "Play Audio" onClicked: { console.log("path: " + audio.path() ); player.source = audio.path(); player.play(); } } } } }
AudioRecorder { id: audio name: "sample.wav" onRecordingChanged: { console.log("recording: " + recording); } }