📄 audiostreamengine.cpp
字号:
// If EFalse, the default PCM is used. If the platform does not support AMR-NB,
// PCM will be used no matter what the argument's value is.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::SetEncodingL(TBool aAmr)
{
// Act only if the new encoding differs from the current one
if (iUseAMR != aAmr)
{
iUseAMR = aAmr;
if (iUseAMR)
{
// Try to set AMR-NB encoding, this will indicate whether it is supported
// by the platform or not.
TRAPD(err, iInputStream->SetDataTypeL(KMMFFourCCCodeAMR));
if (err != KErrNone)
{
ShowMessage(_L("AMR-NB not supported,\nusing PCM."), ETrue);
iCurrentEncoding = iDefaultEncoding;
iUseAMR = EFalse;
// We do not need to invalidate the buffer or change buffer settings,
// since the encoding was not changed -> just return.
return;
}
else
{
iCurrentEncoding = KMMFFourCCCodeAMR;
iAudioFile.Zero(); // Empty the audio file name
iAudioFile.Append(KAudioFileAMR);
iFrameCount = KFrameCountAMR;
iFrameSize = KFrameSizeAMR;
ShowMessage(_L("Encoding set to AMR-NB."), ETrue);
}
}
else
{
// If we get here, the encoding has previously been changed to AMR. Switch back to
// PCM.
iCurrentEncoding = iDefaultEncoding;
iAudioFile.Zero(); // Empty the audio file name
iAudioFile.Append(KAudioFilePCM);
iFrameCount = KFrameCountPCM;
iFrameSize = KFrameSizePCM;
ShowMessage(_L("Encoding set to PCM."), ETrue);
}
// Make sure the user re-records or reloads the audio file, so that we do not
// accidentally try to play PCM data using AMR or vice versa.
iBufferOK = EFalse;
if (iStreamBuffer) delete iStreamBuffer;
iStreamBuffer = NULL; // In case the following NewL leaves
iStreamBuffer = HBufC8::NewMaxL(iFrameSize * iFrameCount);
iStreamStart=0;
iStreamEnd=iFrameCount - 1;
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::ShowMessage(
// const TDesC& aMsg, TBool aReset=EFalse)
//
// displays text referenced by aMsg in the label, will append the aMsg in the
// existing text in label if aReset is EFalse, otherwise will reset the label
// text.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::ShowMessage(const TDesC& aMsg, TBool aReset=EFalse)
{
if (aReset) // if ETrue, clear the message on the label prior to output
iMsg.Zero();
iMsg.Append(aMsg);
TRAPD(error, iAppUi->GetView()->ShowMessageL(iMsg));
PanicIfError(error);
}
// ----------------------------------------------------------------------------
// TPtr8& CAudioStreamEngine::GetFrame(TUint aFrameIdx)
//
// Returns a modifiable pointer to a single frame inside the audio buffer
// ----------------------------------------------------------------------------
TPtr8& CAudioStreamEngine::GetFrame(TUint aFrameIdx)
{
__ASSERT_ALWAYS(aFrameIdx < iFrameCount,
User::Panic(_L("AudioStreamEx"), 1));
iFramePtr.Set((TUint8*)(iStreamBuffer->Ptr() + (aFrameIdx * iFrameSize)),
iFrameSize,
iFrameSize);
return iFramePtr;
}
// ----------------------------------------------------------------------------
// TPtr8& CAudioStreamEngine::GetPlaybackFrames(TUint aLastFrame)
//
// Returns a modifiable pointer to the requested frames inside the audio buffer
// (from the first frame to aLastFrame).
// ----------------------------------------------------------------------------
TPtr8& CAudioStreamEngine::GetPlaybackFrames(TUint aLastFrame)
{
__ASSERT_ALWAYS(aLastFrame < iFrameCount,
User::Panic(_L("AudioStreamEx"), 2));
iFramePtr.Set((TUint8*)(iStreamBuffer->Ptr()),
(aLastFrame + 1) * iFrameSize,
(aLastFrame + 1) * iFrameSize);
return iFramePtr;
}
//
// MMdaAudioInputStream callbacks (MMdaAudioInputStreamCallback)
//
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaiscOpenComplete(
// TInt aError)
//
// called upon completion of CMdaAudioInputStream::Open(),
// if the stream was opened succesfully (aError==KErrNone), it's ready for use.
// upon succesful open, the first audio data block will be read from the input
// stream.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaiscOpenComplete(TInt aError)
{
if (aError==KErrNone)
{
// Input stream opened succesfully, set status
iInputStatus = EOpen;
// Set the data type (encoding)
TRAPD(error, iInputStream->SetDataTypeL(iCurrentEncoding));
PanicIfError(error);
// set stream input gain to maximum
iInputStream->SetGain(iInputStream->MaxGain());
// set stream priority to normal and time sensitive
iInputStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceTime);
ShowMessage(_L("Recording..."), ETrue);
// Emtpy the buffer and issue ReadL() to read the first audio data block,
// subsequent calls to ReadL() will be issued
// in MMdaAudioInputStreamCallback::MaiscBufferCopied()
iStreamBuffer->Des().FillZ(iFrameCount * iFrameSize);
iStreamIdx=0;
TRAPD(error2, iInputStream->ReadL(GetFrame(iStreamIdx)));
PanicIfError(error2);
}
else
{
// input stream open failed
iInputStatus = ENotReady;
ShowMessage(_L("Recording failed!"), ETrue);
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaiscBufferCopied(
// TInt aError, const TDesC8& aBuffer)
//
// called when a block of audio data has been read and is available at the
// buffer reference *aBuffer. calls to ReadL() will be issued until all blocks
// in the audio data buffer (iStreamBuffer) are filled.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaiscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
{
if (aError==KErrNone)
{
// stop recording if at the end of the buffer
iStreamIdx++;
if (iStreamIdx == iFrameCount)
{
ShowMessage(_L("\nRecording complete!"), EFalse);
iStreamEnd = iStreamIdx - 1;
iBufferOK = ETrue;
iInputStatus = ENotReady;
// NOTE: In 2nd Edition we MUST NOT call iInputStream->Stop() here, because
// this will cause a crash on 2nd Edition, FP1 devices.
// Since iInputStream->Stop() is not called, the callback method
// MaiscRecordComplete() will not be called either after exiting this method.
// In 3rd Edition, however, iInputStream->Stop() MUST be called in order to reach
// MaiscRecordComplete(), otherwise the stream will "hang".
#ifdef __SERIES60_3X__
iInputStream->Stop();
#endif
return;
}
// issue ReadL() for next frame
TRAPD(error, iInputStream->ReadL(GetFrame(iStreamIdx)));
PanicIfError(error);
}
else if (aError==KErrAbort)
{
// Recording was aborted, due to call to CMdaAudioInputStream::Stop()
// This KErrAbort will occur each time the Stop() method in this class is executed.
// Also, MaiscRecordComplete() will be called after exiting this method.
iStreamEnd = iStreamIdx - 1;
iBufferOK = ETrue;
iInputStatus = ENotReady;
}
else
{
ShowMessage(_L("\nError reading data \nfrom input"), EFalse);
iInputStatus = ENotReady;
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaiscRecordComplete(
// TInt aError)
//
// called when input stream is closed by CMdaAudioInputStream::Stop()
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaiscRecordComplete(TInt aError)
{
iInputStatus = ENotReady;
if (aError==KErrNone)
{
// normal stream closure
}
else
{
// completed with error(s)
}
}
// MMdaAudioOutputStream callbacks (MMdaAudioOutputStreamCallback)
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaoscOpenComplete(
// TInt aError)
//
// called upon completion of CMdaAudioOutputStream::Open(),
// if the stream was opened succesfully (aError==KErrNone), it's ready for use.
// upon succesful open, the first audio data block will be written to the
// output stream.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaoscOpenComplete(TInt aError)
{
if (aError==KErrNone)
{
// output stream opened succesfully, set status
iOutputStatus = EOpen;
// Set the data type (encoding). Should not fail, since we already
// have tested support for this encoding in SetEncodingL with the
// corresponding input stream!
TRAPD(error, iOutputStream->SetDataTypeL(iCurrentEncoding));
PanicIfError(error);
// set volume to 1/4th of stream max volume
iOutputStream->SetVolume(iOutputStream->MaxVolume()/4);
// set stream priority to normal and time sensitive
iOutputStream->SetPriority(EPriorityNormal,
EMdaPriorityPreferenceTime);
ShowMessage(_L("Playing "), ETrue);
if (iUseAMR)
{
// In case of AMR, the whole recorded/loaded buffer is played back at once, not frame by frame.
// The buffer might not be fully recorded, so we will only play back the part
// that is filled with data.
iStreamIdx = iStreamEnd;
TRAPD(error2, iOutputStream->WriteL(GetPlaybackFrames(iStreamEnd)));
PanicIfError(error2);
}
else
{
// PCM needs to be played back frame by frame, otherwise some older devices might
// run into buffer overflow situations.
iStreamIdx = 0;
TRAPD(error3, iOutputStream->WriteL(GetFrame(iStreamIdx)));
PanicIfError(error3);
}
}
else
{
// output stream open failed
iOutputStatus = ENotReady;
ShowMessage(_L("Playback failed!"), ETrue);
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaoscBufferCopied(
// TInt aError, const TDesC8& aBuffer)
//
// called when a block of audio data has been written to MMF. calls to WriteL()
// will be issued until all blocks in the audio data buffer (iStreamBuffer) are
// written.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaoscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
{
if (aError==KErrNone)
{
if (iStreamIdx==iStreamEnd)
{
ShowMessage(_L("\nPlayback complete!"), EFalse);
iOutputStatus = ENotReady;
// NOTE: In 2nd Edition we MUST NOT call iOutputStream->Stop() here, because
// this will cause a crash on 2nd Edition, FP1 devices.
// Since iOutputStream->Stop() is not called, the callback method
// MaiscRecordComplete() will not be called either after exiting this method.
// In 3rd Edition, however, iOutputStream->Stop() MUST be called in order to reach
// MaiscRecordComplete(), otherwise the stream will "hang".
#ifdef __SERIES60_3X__
iOutputStream->Stop();
#endif
}
else
{
iStreamIdx++;
TRAPD(error, iOutputStream->WriteL(GetFrame(iStreamIdx)));
PanicIfError(error);
}
}
else if (aError==KErrAbort)
{
// Playing was aborted, due to call to CMdaAudioOutputStream::Stop().
// MaoscRecordComplete() will be called after exiting this method.
iOutputStatus = ENotReady;
}
else
{
ShowMessage(_L("\nError writing data \nto output"), EFalse);
iOutputStatus = ENotReady;
}
}
// ----------------------------------------------------------------------------
// CAudioStreamEngine::MaoscPlayComplete(
// TInt aError)
//
// called when output stream is closed by CMdaAudioOutputStream::Stop() or if
// end of audio data has been reached, in this case KErrUnderflow will be
// returned.
// ----------------------------------------------------------------------------
void CAudioStreamEngine::MaoscPlayComplete(TInt aError)
{
iOutputStatus = ENotReady;
if (aError==KErrNone)
{
// normal stream closure
}
else if (aError==KErrUnderflow)
{
// end of audio data stream was reached because of stream underflow,
}
else
{
// completed with error(s)
}
}
// END OF FILE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -