📄 mediarecorder.cpp
字号:
/******************************************************************************** Copyright (C) 2000-2006 TROLLTECH ASA. All rights reserved.**** This file is part of the Phone Edition of the Qtopia Toolkit.**** Licensees holding a valid license agreement from Trolltech or any of its** authorized distributors may use this file in accordance with** the License Agreement provided with the Licensed Software.**** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for** information about Trolltech's Commercial License Agreements.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.********** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "mediarecorder.h"#include "samplebuffer.h"#include "pluginlist.h"#include "timeprogressbar.h"#include "confrecorder.h"#include "waveform.h"#include <qtopia/qdocumentselector.h>#include <qtopia/qcontent.h>#include <qsettings.h>#include <qtopia/qstorage.h>#include <qtopia/qstoragedeviceselector.h>#include <qtopia/qtopiaapplication.h>#include <qtopia/qmimetype.h>#include <qtopia/qdocumentselector.h>#include <qtopia/qcategorymanager.h>#include <qtopiaaudio/qaudioinput.h>#ifdef Q_WS_QWS#include <qtopia/qcopenvelope.h>#endif#include <qaction.h>#include <qbuttongroup.h>#include <qcombobox.h>#include <qmessagebox.h>#include <qfile.h>#include <qtoolbar.h>#include <qmenubar.h>#include <qmenu.h>#include <qevent.h>#include <QDebug>#ifdef QTOPIA_PHONE#include <qtopia/qsoftmenubar.h>#endif#include <stdlib.h>#define MR_BUFSIZE 1024MediaRecorder::MediaRecorder(QWidget *parent, Qt::WFlags f): QMainWindow(parent, f), contentsWidget(NULL), config( 0 ), recorderPlugins(NULL), m_audioInput(new QAudioInput), audioDeviceIsReady(false), startWhenAudioDeviceReady(false), m_sound(NULL), recordingsCategory("_Recordings"), requestMode(false), m_position(0){ // We remove some of the UI if the screen is too small to hold it. smallScreen = height() < 120; // Adjust window decorations setWindowTitle(tr("Voice Notes")); setWindowIcon(QIcon( ":image/SoundPlayer")); // We don't need an input method with this application. QtopiaApplication::setInputMethodHint(this, QtopiaApplication::AlwaysOff); // Make sure that the "Recordings" category is registered. QCategoryManager cats("Documents", 0); if (!cats.contains(recordingsCategory)) { if (!cats.add(recordingsCategory, tr("Recordings"))) recordingsCategory = cats.addTr(tr("Recordings")); } // Create stack widget stack = new QStackedWidget(this); stack->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); setCentralWidget(stack); // Add the Document selector selector = new QDocumentSelector("audio/*", QCategoryFilter(recordingsCategory), stack); selector->setNewEnabled(true); selector->setSortMode(QDocumentSelector::ReverseChronological); selector->setFocus( Qt::OtherFocusReason ); stack->addWidget(selector); connect(selector, SIGNAL(documentSelected(const QContent&)), this, SLOT(documentSelected(const QContent&))); connect(selector, SIGNAL(newSelected()), this, SLOT(newSelected())); // Listen for app messages, particularly the "recordSound" request. connect(qApp, SIGNAL(appMessage(const QString&,const QByteArray&)), this, SLOT(appMessage(const QString&,const QByteArray&))); // Listen for "VoiceRecording" service messages. new VoiceRecordingService(this); // extra config sampleBuffer = 0; recordTime = 0; recording = false; playing = false; io = 0; recordLightState = false;#ifdef RECORD_THEN_SAVE samples = 0;#endif#ifndef QTOPIA_PHONE // Make a timer to flash the light lightTimer = new QTimer(this); connect(lightTimer, SIGNAL(timeout()), this, SLOT(recordLightBlink())); // Listen on the system tray for clicks on the record light so that // we can raise the application when the user clicks on it. trayChannel = new QCopChannel("Tray", this); connect(trayChannel, SIGNAL(received(const QString&,const QByteArray&)), this, SLOT(traySocket(const QString&,const QByteArray&)));#endif}MediaRecorder::~MediaRecorder(){ delete m_audioInput; delete recorderPlugins;#ifdef RECORD_THEN_SAVE if ( samples ) delete samples;#endif if (sampleBuffer) delete[] sampleBuffer; if (io ) delete io;#ifndef QTOPIA_PHONE delete lightTimer;#endif delete m_sound;}void MediaRecorder::initializeContents(){ // The progress bar initially has no time display. This will be fixed // up when we start recording. contents->progress->setMaximum( 10 ); contents->progress->setValue( -1 ); // Cannot replay yet, because there is no recorded sound. setReplayEnabled(false); setDeleteEnabled(false); if (recorderPlugins == NULL) recorderPlugins = new MediaRecorderPluginList(); // Load the initial quality settings. config = new ConfigureRecorder(qualities, recorderPlugins, this); contents->qualityCombo->setCurrentIndex(config->currentQuality()); setQualityDisplay(qualities[config->currentQuality()]); connect( contents->qualityCombo, SIGNAL( activated(int) ), this, SLOT( qualityChanged(int) ) ); connect( contents->storageLocation, SIGNAL(newPath()), this, SLOT(newLocation()) ); recomputeMaxTime();#ifdef QTOPIA_PHONE // Create a menu with "Help" on the dialog. QSoftMenuBar::menuFor( config ); // Disable the settings boxes in phone mode. contents->GroupBox1->hide(); contents->GroupBox2->hide();#else if ( smallScreen ) contents->GroupBox1->hide();#endif}void MediaRecorder::setQualityDisplay( const QualitySetting& quality ){ QString str; QString format; int index; // Map the MIME type to a format name. Do the best we can with // the MIME type and tag if that is all we have. index = recorderPlugins->indexFromType ( quality.mimeType, quality.formatTag ); if( index >= 0 ) { format = recorderPlugins->formatNameAt( (uint)index ); } else if( quality.mimeType.startsWith( "audio/" ) ) { format = quality.mimeType.mid(6) + " [" + quality.formatTag + "]"; } else { format = quality.mimeType + " [" + quality.formatTag + "]"; } // Format the details and display them. int khz = (quality.frequency / 1000); if ( quality.channels == 1 ) { str = tr("%1 kHz Mono - %2").arg(khz).arg(format); } else { str = tr("%1 kHz Stereo - %2").arg(khz).arg(format); } contents->details->setText( str );}void MediaRecorder::recomputeMaxTime(){ // Determine the maximum available space on the device. const QFileSystem *fs = contents->storageLocation->fileSystem(); long availBlocks; long blockSize; if ( fs ) { availBlocks = fs->availBlocks(); blockSize = fs->blockSize(); } else { availBlocks = 0; blockSize = 512; } // Calculate the number of bytes per second for the current quality, // by asking the plugin for an estimate. MediaRecorderEncoder *encoder = recorderPlugins->fromType ( qualities[config->currentQuality()].mimeType, qualities[config->currentQuality()].formatTag ); long bytesPerSec; if( encoder ) { bytesPerSec = encoder->estimateAudioBps ( qualities[config->currentQuality()].frequency, qualities[config->currentQuality()].channels, qualities[config->currentQuality()].formatTag ); if ( bytesPerSec <= 0) bytesPerSec = 1; } else { // We don't have an encoder, so make an estimate based on // assuming that the format is wav. bytesPerSec = qualities[config->currentQuality()].frequency * qualities[config->currentQuality()].channels * 2; } // Get an estimate of the maximum number of seconds that we can record. // Use "double" to avoid truncation errors with 32-bit arithmetic. long maxSecs = (long)(((double)availBlocks) * ((double)blockSize) / (double)bytesPerSec); // Truncate the maximum to a reasonable human-grokkable time boundary, // as there is no point displaying things like "5 hrs 23 mins 6 secs". if ( maxSecs >= (60 * 60 * 24) ) { // Truncate to a 1 hour boundary. maxSecs -= (maxSecs % (60 * 60)); } else if ( maxSecs >= (60 * 60 * 10) ) { // Truncate to a 15 minute boundary. maxSecs -= (maxSecs % (15 * 60)); } else if ( maxSecs >= (60 * 10) ) { // Tuncate to a 1 minute boundary. maxSecs -= (maxSecs % 60); } else if ( maxSecs > 60 ) { // Truncate to a 15 second boundary. maxSecs -= (maxSecs % 15); }#ifndef QTOPIA_PHONE // will never be seen // Format the string for the max time field. QString str; if ( maxSecs >= (60 * 60 * 24) ) { if ( (maxSecs % (60 * 60 * 24)) == 0 ) { str = tr("%1 days").arg((int)(maxSecs / (60 * 60 * 24))); } else { str = tr("%1 days %2 hrs") .arg((int)(maxSecs / (60 * 60 * 24))) .arg((int)((maxSecs / (60 * 60)) % 24)); } } else if ( maxSecs >= (60 * 60) ) { if ( (maxSecs % (60 * 60)) == 0 ) { str = tr("%1 hrs").arg((int)(maxSecs / (60 * 60))); } else { str = tr("%1 hrs %2 mins") .arg((int)(maxSecs / (60 * 60))) .arg((int)((maxSecs / 60) % 60)); } } else if ( maxSecs >= 60 ) { if ( (maxSecs % 60) == 0 ) { str = tr("%1 mins").arg((int)(maxSecs / 60)); } else { str = tr("%1 mins %2 secs").arg((int)(maxSecs / 60)).arg((int)(maxSecs % 60)); } } else { str = tr("%1 secs").arg((int)maxSecs); } // Update the max time field. contents->maxTime->setText( str );#endif maxRecordTime = maxSecs;}void MediaRecorder::qualityChanged( int id ){ config->setQuality( id ); config->saveConfig(); setQualityDisplay( qualities[id] ); recomputeMaxTime();}void MediaRecorder::newLocation(){ recomputeMaxTime();}bool MediaRecorder::startSave(){ // Find the plugin to use to save the data. encoder = recorderPlugins->fromType(recordQuality.mimeType, recordQuality.formatTag); // Open the document. QContent doc; QString name = tr("%1 %2","date,time") .arg(QTimeString::localYMD(QDate::currentDate(),QTimeString::Short)) .arg(QTimeString::localHM(QTime::currentTime())); doc.setName(name); doc.setType( encoder->pluginMimeType() ); QList<QString> cats; cats.append(recordingsCategory); doc.setCategories(cats); io = doc.open(QIODevice::WriteOnly); // Write the sample data using the encoder. encoder->begin(io, recordQuality.formatTag); encoder->setAudioChannels(m_audioInput->channels()); encoder->setAudioFrequency(m_audioInput->frequency()); // Record the location of the file that we are saving. lastSaved = doc.file(); doc.commit(); return true;}void MediaRecorder::endSave(){ // Flush the samples if we recorded to memory.#ifdef RECORD_THEN_SAVE samples->rewind(); short *buf; unsigned int length; while ( samples->nextReadBuffer( buf, length ) ) { if ( !encoder->writeAudioSamples( buf, (long)length ) ) break; }#endif // Terminate the encode process. encoder->end(); // Close the document. io->close();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -