📄 audiostreamengine.cpp
字号:
/*
* ============================================================================
* Name : CAudioStreamEngine from AudioStreamEngine.cpp
* Part of : AudioStream
* Created : April 28, 2006 by Forum Nokia
* Implementation notes:
*
* Initial content was generated by S60 AppWizard.
* Version : 2.0
* Copyright: Nokia Corporation
* ============================================================================
*/
#include <mda\common\audio.h>
#include <mmf\common\mmfutilities.h>
#include <MdaAudioInputStream.h> // audio input stream
#include <MdaAudioOutputStream.h> // audio output stream
#include <s32file.h> // RFileWriteStream and RFileReadStream
#include "AudioStreamEngine.h"
#include "audiostream.pan"
// Audio data buffer size.
// In both 3rd Edition and 2nd Edition the total buffer (iStreamBuffer) size is
// KFrameSizePCM * KFrameCountPCM = 40960 bytes. This will contain 2560 ms
// of 16-bit audio data.
// In 3rd Edition the KFrameSizePCM is 4096 bytes, because CMdaAudioInputStream::ReadL()
// returns audio data in 4096-byte chunks. In 2nd Edition, ReadL() returns data in 320-byte
// chunks.
#ifdef __SERIES60_3X__ // 3rd Edition
const TInt KFrameSizePCM = 4096;
const TInt KFrameCountPCM = 10;
#else // 2nd Edition
const TInt KFrameSizePCM = 320;
const TInt KFrameCountPCM = 128;
#endif
// Audio data buffer size for AMR encoding. For AMR, the buffer size is the same in
// both 2nd and 3rd Edition devices (20 ms per frame, a total of 2560 ms in 128 frames).
const TInt KFrameSizeAMR = 14;
const TInt KFrameCountAMR = 128;
// Header data for an AMR-encoded audio file
const TInt KAMRHeaderLength=6;
const TUint8 KAMRNBHeader[KAMRHeaderLength] = { 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a };
// Files to store the sample audio clips
_LIT(KAudioFilePCM, "sample.aud");
_LIT(KAudioFileAMR, "sample.amr");
#ifdef __WINS__
// The path to the sample files in 2nd Ed emulator
_LIT(KEmulatorPath, "c:\\system\\apps\\audiostream\\");
#endif
CAudioStreamEngine* CAudioStreamEngine::NewL(CAudioStreamAppUi* aAppUi)
{
CAudioStreamEngine* self = CAudioStreamEngine::NewLC(aAppUi);
CleanupStack::Pop(self);
return self;
}
CAudioStreamEngine* CAudioStreamEngine::NewLC(CAudioStreamAppUi* aAppUi)
{
CAudioStreamEngine* self = new (ELeave) CAudioStreamEngine(aAppUi);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
// Standard EPOC 2nd phase constructor
void CAudioStreamEngine::ConstructL()
{
// Construct streams. We need to construct these here, so that at least the input stream
// exists if SetEncodingL() is called before any recording has taken place
iInputStream = CMdaAudioInputStream::NewL(*this);
iOutputStream = CMdaAudioOutputStream::NewL(*this);
// Get a handle to the RFs session to be used (owned by CEikonEnv, NOT to be closed
// when this application exits!)
iFs = CEikonEnv::Static()->FsSession();
// Save the default encoding for later reference (the encoding is the same for
// both input and output streams).
iDefaultEncoding = iInputStream->DataType();
// At first we are using the default encoding.
iCurrentEncoding = iDefaultEncoding;
// Stream buffer allocation (by default for PCM)
iStreamBuffer = HBufC8::NewMaxL(iFrameSize * iFrameCount);
iStreamStart=0;
iStreamEnd=iFrameCount - 1;
#ifdef __SERIES60_3X__
// Only in 3rd Edition. The sample.aud/amr can be found in \private\<UID3>\ folder.
User::LeaveIfError( iFs.CreatePrivatePath( EDriveC ) );
User::LeaveIfError( iFs.SetSessionToPrivate( EDriveC ) );
#else
#ifndef __WINS__ // don't save settings to z-drive in emulator
// In 2nd Ed device the sample.aud/amr will be in \system\apps\audiostream\ folder.
TFileName appFullName = iAppUi->Application()->AppFullName();
TParsePtr appPath(appFullName);
iAudioFilePath = appPath.DriveAndPath();
#else
// For 2nd Ed emulator
iAudioFilePath.Append(KEmulatorPath);
#endif //__WINS__
#endif
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::CAudioStreamEngine(
// CAudioStreamAppUi* aAppUi)
//
// onstructor
// ----------------------------------------------------------------------------
CAudioStreamEngine::CAudioStreamEngine(CAudioStreamAppUi* aAppUi)
: iAppUi(aAppUi), iUseAMR(EFalse), iAudioFile(KAudioFilePCM), iFrameSize(KFrameSizePCM),
iFrameCount(KFrameCountPCM), iStreamBuffer(0), iFramePtr(0,0), iBufferOK(EFalse)
{
// By default we use PCM and initialise the instance variables accordingly above.
// Initial audio stream properties for input and output, 8KHz mono.
// These settings could also be set/changed using method SetAudioPropertiesL() of
// the input and output streams.
iStreamSettings.iChannels=TMdaAudioDataSettings::EChannelsMono;
iStreamSettings.iSampleRate=TMdaAudioDataSettings::ESampleRate8000Hz;
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::~CAudioStreamEngine()
//
// destructor
// ----------------------------------------------------------------------------
CAudioStreamEngine::~CAudioStreamEngine()
{
// close and delete streams
if (iInputStream)
{
if (iInputStatus!=ENotReady) iInputStream->Stop();
delete iInputStream;
iInputStream=NULL;
}
if (iOutputStream)
{
if (iOutputStatus!=ENotReady) iOutputStream->Stop();
delete iOutputStream;
iOutputStream=NULL;
}
if (iStreamBuffer)
{
delete iStreamBuffer;
iStreamBuffer = NULL;
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::Play()
//
// plays the audio data contained in the buffer
// ----------------------------------------------------------------------------
void CAudioStreamEngine::Play()
{
ShowMessage(_L("Play "), ETrue);
// if either stream is active, return
if (iInputStatus!=ENotReady || iOutputStatus!=ENotReady)
{
ShowMessage(_L("Stream in use, \ncannot play audio."), ETrue);
return;
}
if(!iBufferOK)
{
ShowMessage(_L("Nothing to play - \nrecord or load \na file first."), ETrue);
return;
}
// Open output stream.
// Upon completion will receive callback in
// MMdaAudioOutputStreamCallback::MaoscOpenComplete().
#ifndef __SERIES60_3X__ // Not 3rd Ed
// Some 2nd Edition, FP2 devices (such as Nokia 6630) require the stream to be
// reconstructed each time before calling Open() - otherwise the callback
// never gets called.
if (iOutputStream) delete iOutputStream;
iOutputStream = NULL; // In case the following NewL leaves
TRAPD(err, iOutputStream = CMdaAudioOutputStream::NewL(*this));
PanicIfError(err);
#endif
iOutputStream->Open(&iStreamSettings);
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::Record()
//
// records audio data into the buffer
// ----------------------------------------------------------------------------
void CAudioStreamEngine::Record()
{
// If either stream is active, return
if (iInputStatus!=ENotReady || iOutputStatus!=ENotReady)
{
ShowMessage(_L("Stream in use, \ncannot record audio."), ETrue);
return;
}
// Open input stream.
// Upon completion will receive callback in
// MMdaAudioInputStreamCallback::MaiscOpenComplete().
#ifndef __SERIES60_3X__ // Not 3rd Ed
// Some 2nd Edition, FP2 devices (such as Nokia 6630) require the stream to be
// reconstructed each time before calling Open() - otherwise the callback
// never gets called.
if (iInputStream) delete iInputStream;
iInputStream = NULL; // In case the following NewL leaves
TRAPD(err, iInputStream = CMdaAudioInputStream::NewL(*this));
PanicIfError(err);
#endif
iInputStream->Open(&iStreamSettings);
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::Stop()
//
// stops playing/recording
// ----------------------------------------------------------------------------
void CAudioStreamEngine::Stop()
{
// if input or output streams are active, close them
if (iInputStatus!=ENotReady)
{
iInputStream->Stop();
ShowMessage(_L("\nRecording stopped!"), EFalse);
iBufferOK = ETrue;
}
if (iOutputStatus!=ENotReady)
{
iOutputStream->Stop();
ShowMessage(_L("\nPlayback stopped!"), ETrue);
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::LoadAudioFileL()
//
// loads the audio data from a file into the buffer
// ----------------------------------------------------------------------------
void CAudioStreamEngine::LoadAudioFileL()
{
RFileReadStream audiofile;
// open file
TFileName fileName;
fileName.Copy(iAudioFilePath);
fileName.Append(iAudioFile);
TInt err = audiofile.Open(iFs, fileName, EFileRead|EFileStream);
iStreamBuffer->Des().FillZ(iFrameCount * iFrameSize); // Empty the stream buffer
if (err==KErrNone)
{
// file opened ok, proceed reading
if (iUseAMR)
{
// Read the AMR header (the first 6 bytes). We don't need to save/use the header,
// since while playback we already know it's an AMR-NB encoded stream.
TBuf8<KAMRHeaderLength> temp;
audiofile.ReadL(temp, KAMRHeaderLength);
}
TUint idx=0;
while (idx < iFrameCount)
{
TRAPD(fstatus, audiofile.ReadL(GetFrame(idx), iFrameSize));
if (fstatus!=KErrNone)
break;
idx++;
}
iStreamStart=0;
iStreamEnd=idx-1;
ShowMessage(_L("Loading complete!"), ETrue);
iBufferOK = ETrue;
}
else
{
// failed to open file
ShowMessage(_L("Error loading \naudio sample!"), ETrue);
iBufferOK = EFalse;
}
audiofile.Close();
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::SaveAudioFileL()
//
// saves the audio data in the buffer into a file
// ----------------------------------------------------------------------------
void CAudioStreamEngine::SaveAudioFileL()
{
if (!iBufferOK)
{
// In case the encoding was changed between recording and trying to save the file
ShowMessage(_L("Recorded buffer does not \nmatch current encoding."), ETrue);
ShowMessage(_L("\nPlease re-record and \ntry again."), EFalse);
return;
}
RFileWriteStream audiofile;
// Check for free space for saving the sample
TVolumeInfo volinfo;
TInt err=iFs.Volume(volinfo,EDriveC);
if ( volinfo.iFree<(iFrameCount*iFrameSize))
{
// Not enough free space on drive for saving, report and exit
ShowMessage(_L("Cannot save file:\nnot enough space!"), ETrue);
return;
}
TFileName fileName;
fileName.Copy(iAudioFilePath);
fileName.Append(iAudioFile);
err = audiofile.Replace(iFs, fileName, EFileWrite|EFileStream);
if (err==KErrNone)
{
if (iUseAMR)
{
// Write the six-byte AMR header, so that the file can be used by other
// applications as well.
for (int i = 0; i < KAMRHeaderLength; i++)
audiofile.WriteUint8L(KAMRNBHeader[i]);
}
// File opened ok, proceed writing.
// Write audio data directly from iStreamBuffer
for (TUint idx=iStreamStart; idx<=iStreamEnd; idx++)//iFrameCount; idx++)
{
audiofile.WriteL(GetFrame(idx));
}
ShowMessage(_L("Saving complete!"), ETrue);
}
else
{
// failed to open file
ShowMessage(_L("Error saving \naudio sample!"), ETrue);
}
audiofile.Close();
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::SetEncodingL(TBool aAmr)
//
// If argument is ETrue, AMR-NB encoding will be used in audio input/output.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -