mediarecorder.cpp
来自「Trolltech公司发布的图形界面操作系统。可在qt-embedded-2.3」· C++ 代码 · 共 1,099 行 · 第 1/3 页
CPP
1,099 行
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.** ** This program 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 2 of the License, or (at your** option) any later version.** ** A copy of the GNU GPL license version 2 is included in this package as ** LICENSE.GPL.**** This program 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.**** In addition, as a special exception Trolltech gives permission to link** the code of this program with Qtopia applications copyrighted, developed** and distributed by Trolltech under the terms of the Qtopia Personal Use** License Agreement. You must comply with the GNU General Public License** in all respects for all of the code used other than the applications** licensed under the Qtopia Personal Use License Agreement. If you modify** this file, you may extend this exception to your version of the file,** but you are not obligated to do so. If you do not wish to do so, delete** this exception statement from your version.** ** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#define QTOPIA_INTERNAL_MIMEEXT#include "mediarecorder.h"#include "mediarecorderbase.h"#include "audioinput.h"#include "audiodevice.h"#include "samplebuffer.h"#include "pluginlist.h"#include "timeprogressbar.h"#include "confrecorder.h"#include "waveform.h"#include <qtopia/global.h>#include <qtopia/fileselector.h>#include <qtopia/applnk.h>#include <qtopia/resource.h>#include <qtopia/config.h>#include <qtopia/storage.h>#include <qtopia/locationcombo.h>#include <qtopia/qpeapplication.h>#include <qtopia/qpemenubar.h>#include <qtopia/qpetoolbar.h>#include <qtopia/mimetype.h>#include <qtopia/fileselector.h>#include <qtopia/categories.h>#ifdef Q_WS_QWS#include <qtopia/qcopenvelope_qws.h>#endif#include <qaction.h>#include <qbuttongroup.h>#include <qcombobox.h>#include <qmessagebox.h>#include <qfile.h>#ifdef QTOPIA_PHONE#include <qtopia/contextmenu.h>#include <qtopia/contextbar.h>#endif#include <stdlib.h>MediaRecorder::MediaRecorder( QWidget *parent, const char *name, WFlags f ) : QMainWindow( parent, name, f ){ audioDeviceIsReady = false; startWhenAudioDeviceReady = false; requestMode = false; // Load the media plugins. recorderPlugins = new MediaRecorderPluginList(); playerPlugins = new MediaPlayerPluginList(); setToolBarsMovable( FALSE ); setBackgroundMode( PaletteButton ); setCaption( tr("Voice Notes") ); setIcon( Resource::loadPixmap( "SoundPlayer" ) ); // We don't need an input method with this application. QPEApplication::setInputMethodHint( this, QPEApplication::AlwaysOff ); // Make sure that the "Recordings" category is registered. Categories cats; cats.load(categoryFileName()); recordingsCategory = cats.id("Document View","_Recordings"); // No tr if ( !recordingsCategory ) { recordingsCategory = cats.addCategory("Document View","_Recordings"); // No tr cats.save(categoryFileName()); } stack = new QWidgetStack( this ); stack->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); setCentralWidget( stack ); contents = new MediaRecorderBase( stack ); stack->addWidget( contents, 0 ); selector = new FileSelector( "audio/*", stack, "fileselector", TRUE, FALSE ); selector->setCurrentCategory( recordingsCategory ); selector->setSortMode( FileSelector::ReverseChronological ); stack->addWidget( selector, 1 ); connect( selector, SIGNAL(fileSelected(const DocLnk&)), this, SLOT(fileSelected(const DocLnk&)) ); connect( selector, SIGNAL(newSelected(const DocLnk&)), this, SLOT(newSelected(const DocLnk&)) );#ifdef QTOPIA_PHONE // Create the context menu for the file selector screen. ContextMenu *options = new ContextMenu( selector ); selector->addOptions( options ); // Create the context menu for the record/playback screen. options = new ContextMenu( contents );#else QPEToolBar *bar = new QPEToolBar( this ); bar->setHorizontalStretchable( TRUE ); menu = bar; QPEMenuBar *mb = new QPEMenuBar( bar ); QPopupMenu *options = new QPopupMenu( this ); mb->insertItem( tr( "Options" ), options );#endif configureAction = new QAction(tr( "Settings..."), Resource::loadIconSet("settings"), QString::null, 0, this, 0 ); connect( configureAction, SIGNAL( activated() ), this, SLOT( configure() ) ); configureAction->setWhatsThis( tr("Configure the recording quality settings.") ); configureAction->addTo( options ); configureAction->setEnabled( TRUE ); initializeContents(); switchToFileSelector(); audioInput = 0; audioOutput = 0;#ifdef RECORD_THEN_SAVE samples = 0;#endif sampleBuffer = 0; recordTime = 0; recording = FALSE; playing = FALSE; io = 0; recordLightState = FALSE; lightTimer = new QTimer( this ); // Hook up interesting signals. connect( contents->recordButton, SIGNAL( clicked() ), this, SLOT( recordClicked() ) ); connect( contents->replayButton, SIGNAL( clicked() ), this, SLOT( replayClicked() ) ); connect( contents->deleteButton, SIGNAL( clicked() ), this, SLOT( deleteClicked() ) ); connect( lightTimer, SIGNAL( timeout() ), this, SLOT( recordLightBlink() ) );#ifdef QTOPIA_PHONE // Don't display the buttons in Qtopia Phone Edition, because // they take up too much screen real estate and have confusing // key navigation behaviours. //contents->recordButton->hide(); contents->replayButton->hide(); contents->deleteButton->hide(); // Make the context key say "Record". setContextKey( TRUE );#endif // 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( "Qt/Tray", this ); connect( trayChannel, SIGNAL(received(const QCString&,const QByteArray&)), this, SLOT(traySocket(const QCString&,const QByteArray&)) ); // Listen for app messages, particularly the "recordSound" request. connect( qApp, SIGNAL(appMessage(const QCString&,const QByteArray&)), this, SLOT(appMessage(const QCString&,const QByteArray&)) ); // Force the MIME type handling system to preload the list // of extensions. If we don't do this, then "startRecording" // ends up being _very_ slow. MimeType type("audio/x-wav");}MediaRecorder::~MediaRecorder(){ delete recorderPlugins; delete playerPlugins; if ( audioInput ) delete audioInput; if ( audioOutput ) delete audioOutput;#ifdef RECORD_THEN_SAVE if ( samples ) delete samples;#endif if ( sampleBuffer ) delete[] sampleBuffer; if ( io ) delete io; if ( lightTimer ) delete lightTimer;}void MediaRecorder::initializeContents(){ // Set the waveform background to black. contents->waveform->setBackgroundColor ( black ); // The progress bar initially has no time display. This will be fixed // up when we start recording. contents->progress->setTotalSteps( 10 ); contents->progress->setProgress( -1 ); // Cannot replay yet, because there is no recorded sound. setReplayEnabled( FALSE ); setDeleteEnabled( FALSE ); // Load the initial quality settings. config = new ConfigureRecorder( qualities, recorderPlugins, this ); contents->qualityCombo->setCurrentItem(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 // Disable the settings boxes in phone mode. contents->GroupBox1->hide(); contents->GroupBox2->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 FileSystem *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); } // 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 ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?