📄 oggtremor.cpp
字号:
iOutStreamByteRate= usedChannels * usedRate * sizeof(short);
iMaxBytesBetweenFrequencyBins= iOutStreamByteRate / KOggControlFreq;
return KErrNone;
}
void COggPlayback::SamplingRateSupportedMessage(TBool aConvertRate, TInt aRate, TBool aConvertChannel, TInt /*aNbOfChannels*/)
{
// Print an error/info msg displaying all supported rates by this HW
const TInt rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
#if !defined(MULTI_THREAD_PLAYBACK)
const TInt ratesMask[] =
{TMdaAudioDataSettings::ESampleRate8000Hz, TMdaAudioDataSettings::ESampleRate11025Hz,
TMdaAudioDataSettings::ESampleRate16000Hz, TMdaAudioDataSettings::ESampleRate22050Hz,
TMdaAudioDataSettings::ESampleRate32000Hz, TMdaAudioDataSettings::ESampleRate44100Hz, TMdaAudioDataSettings::ESampleRate48000Hz };
#endif
HBufC * hBufMsg = HBufC::NewL(1000);
CleanupStack::PushL(hBufMsg);
HBufC * hTmpBuf = HBufC::NewL(500);
CleanupStack::PushL(hTmpBuf);
TPtr bufMsg = hBufMsg->Des();
TPtr tmpBuf = hTmpBuf->Des();
if (aConvertRate)
{
TBuf<128> buf;
CEikonEnv::Static()->ReadResource(tmpBuf, R_OGG_ERROR_24);
TBool first = ETrue;
TInt err;
for (TInt i=0; i<7; i++)
{
#if defined(MULTI_THREAD_PLAYBACK)
err = SetAudioProperties(rates[i], 1);
#else
TRAP(err, iStream->SetAudioPropertiesL(ratesMask[i], TMdaAudioDataSettings::EChannelsMono));
#endif
if (err == KErrNone)
{
if (!first)
{
// Append a comma
buf.Append(_L(", "));
}
// Append the audio rate
buf.AppendNum(rates[i]);
first = EFalse;
}
}
bufMsg.Format(tmpBuf, aRate, &buf);
}
if (aConvertChannel)
{
CEikonEnv::Static()->ReadResource(tmpBuf, R_OGG_ERROR_25);
bufMsg.Append(tmpBuf);
}
CEikonEnv::Static()->ReadResource(tmpBuf, R_OGG_ERROR_26);
bufMsg.Append(tmpBuf);
iEnv->OggWarningMsgL(bufMsg);
CleanupStack::PopAndDestroy(2, hBufMsg);
}
TInt COggPlayback::Volume()
{
#if defined (MULTI_THREAD_PLAYBACK)
iStreamingThreadCommandHandler->Volume();
return iSharedData.iVolume;
#else
return iStream->Volume();
#endif
}
void COggPlayback::SetVolume(TInt aVol)
{
#if defined(MULTI_THREAD_PLAYBACK)
iSharedData.iVolume = aVol;
iStreamingThreadCommandHandler->SetVolume();
#else
if (aVol>KMaxVolume) aVol= KMaxVolume;
else if(aVol<0) aVol= 0;
TInt volume = (TInt) (((TReal) aVol)/KMaxVolume * iMaxVolume);
if (volume > iMaxVolume)
volume = iMaxVolume;
iStream->SetVolume(volume);
#endif
}
void COggPlayback::SetVolumeGain(TGainType aGain)
{
#if defined(MULTI_THREAD_PLAYBACK)
FlushBuffers(aGain);
#else
iOggSampleRateConverter->SetVolumeGain(aGain);
#endif
}
void COggPlayback::SetPosition(TInt64 aPos)
{
if(iDecoder)
{
// Limit FF to five seconds before the end of the track
if (aPos>iTime)
aPos = iTime - TInt64(5000);
// And don't allow RW past the beginning either
if (aPos<0)
aPos = 0;
#if defined(MULTI_THREAD_PLAYBACK)
// Pause/Restart the stream instead of just flushing buffers
// This works better with FF/RW because, like next/prev track, key repeats are possible (and very likely on FF/RW)
TBool streamStopped = FlushBuffers(aPos);
// Restart streaming
if (streamStopped)
iRestartAudioStreamingTimer->Wait(KStreamStartDelay);
#else
iDecoder->Setposition(aPos);
#endif
}
}
TInt64 COggPlayback::Position()
{
#if defined(MULTI_THREAD_PLAYBACK)
// Approximate position will do here
const TInt64 KConst500 = TInt64(500);
TInt64 positionBytes = iSharedData.iTotalBufferBytes - iSharedData.BufferBytes();
TInt64 positionMillisecs = (KConst500*positionBytes)/TInt64(iSharedData.iSampleRate*iSharedData.iChannels);
return positionMillisecs;
#else
// TO DO: Also take into account the buffers (see comments in GetFrequencyBins)
if(iDecoder) return iDecoder->Position();
return 0;
#endif
}
TInt64 COggPlayback::Time()
{
return iTime;
}
#ifdef MDCT_FREQ_ANALYSER
const TInt32 * COggPlayback::GetFrequencyBins()
{
#if defined(MULTI_THREAD_PLAYBACK)
// Get the precise position from the streaming thread
iStreamingThreadCommandHandler->Position();
const TInt64 KConst500000 = TInt64(500000);
TInt64 streamPositionBytes = (iSharedData.iStreamingPosition.Int64()*TInt64(iSharedData.iSampleRate*iSharedData.iChannels))/KConst500000;
TInt64 positionBytes = iLastPlayTotalBytes + streamPositionBytes;
#else
TInt64 positionBytes= iStream->Position().Int64() * iOutStreamByteRate / 1000000; // convert usec to pcm bytes
#endif
TInt idx = iLastFreqArrayIdx;
for (TInt i=0; i<KFreqArrayLength; i++)
{
if (iFreqArray[idx].iPcmByte <= positionBytes)
break;
idx--;
if (idx < 0)
idx = KFreqArrayLength-1;
}
return iFreqArray[idx].iFreqCoefs;
}
#else
const void* COggPlayback::GetDataChunk()
{
TInt idx= iSentIdx;
if( iSent[idx] )
return iSent[idx]->Ptr();
else
return NULL;
}
#endif
TInt COggPlayback::Info(const TDesC& aFileName, TBool silent)
{
if (aFileName.Length()==0) return -100;
RFile* f = new RFile;
if ((f->Open(iFs, aFileName, EFileShareReadersOnly)) != KErrNone) {
if (!silent) {
TBuf<128> buf;
CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_14);
iEnv->OggErrorMsgL(buf,aFileName);
}
return KErrOggFileNotFound;
}
MDecoder* decoder = GetDecoderL(aFileName);
if(decoder->OpenInfo(f, aFileName) < 0) {
decoder->Close();
delete decoder;
f->Close();
delete f;
if (!silent) {
iEnv->OggErrorMsgL(R_OGG_ERROR_20, R_OGG_ERROR_9);
}
return -102;
}
decoder->ParseTags(iTitle, iArtist, iAlbum, iGenre, iTrackNumber);
iFileName = aFileName;
iRate = decoder->Rate();
iChannels = decoder->Channels();
iBitRate = decoder->Bitrate();
decoder->Close();
delete decoder;
f->Close();
delete f;
return KErrNone;
}
void COggPlayback::Play()
{
TRACEF(COggLog::VA(_L("PLAY %i "), iState ));
switch(iState)
{
case EPaused:
break;
case EStopped:
iEof=0;
break;
default:
iEnv->OggErrorMsgL(R_OGG_ERROR_20, R_OGG_ERROR_15);
RDebug::Print(_L("Oggplay: Tremor - State not Open"));
return;
}
iLastPlayBufferBytes= 0;
#ifdef MDCT_FREQ_ANALYSER
iLastFreqArrayIdx= 0;
iBytesSinceLastFrequencyBin= 0;
// Clear the frequency analyser
Mem::FillZ(&iFreqArray, sizeof(iFreqArray));
#endif
// There is something wrong how Nokia audio streaming handles the
// first buffers. They are somehow swallowed.
// To avoid that, send few (4) almost empty buffers
if (iMachineUid != EMachineUid_SendoX) // Sendo X doesn't need this fix.
iFirstBuffers = 4;
#if defined(DELAY_AUDIO_STREAMING_START)
// Also to avoid the first buffer problem, wait a short time before streaming,
// so that Application drawing have been done. Processor should then
// be fully available for doing audio thingies.
#if !defined(MULTI_THREAD_PLAYBACK)
// A longer delay is necessary if MULTI_THREAD_PLAYBACK is not defined
if (iMachineUid == EMachineUid_SendoX) // Latest 1.198.8.2 Sendo X firmware needs a little more time
iStartAudioStreamingTimer->Wait(KSendoStreamStartDelay);
else
#endif
iStartAudioStreamingTimer->Wait(KStreamStartDelay);
#else
#if defined(MULTI_THREAD_PLAYBACK)
StartStreaming();
#else
for (TInt i=0; i<KBuffers; i++) SendBuffer(*iBuffer[i]);
#endif
#endif
iState = EPlaying;
iObserver->ResumeUpdates();
#if defined(DELAY_AUDIO_STREAMING_START)
iObserver->NotifyPlayStarted();
#endif
}
void COggPlayback::Pause()
{
TRACEF(COggLog::VA(_L("PAUSE")));
if (iState != EPlaying) return;
iState = EPaused;
CancelTimers();
#if defined(MULTI_THREAD_PLAYBACK)
// Flush buffers (and pause the stream)
FlushBuffers(EPlaybackPaused);
#else
iStream->Stop();
#endif
}
void COggPlayback::Resume()
{
//Resume is equivalent of Play()
Play();
}
void COggPlayback::Stop()
{
TRACEF(COggLog::VA(_L("STOP") ));
if ((iState == EStopped) || (iState == EClosed))
return;
iState = EStopped;
CancelTimers();
#if defined(MULTI_THREAD_PLAYBACK)
StopStreaming();
#else
iStream->Stop();
#endif
if (iFile)
{
iDecoder->Close();
iFile->Close();
delete iFile;
iFile = NULL;
delete iDecoder;
iDecoder = NULL;
}
ClearComments();
iTime= 0;
iEof= EFalse;
#if !defined(MULTI_THREAD_PLAYBACK)
iUnderflowing = EFalse;
#endif
if (iObserver) iObserver->NotifyUpdate();
}
void COggPlayback::CancelTimers()
{
iStartAudioStreamingTimer->Cancel();
iRestartAudioStreamingTimer->Cancel();
iStopAudioStreamingTimer->Cancel();
}
TInt COggPlayback::GetNewSamples(TDes8 &aBuffer, TBool /*aRequestFrequencyBins*/)
{
if (iEof)
return(KErrNotReady);
#ifdef MDCT_FREQ_ANALYSER
if ((iBytesSinceLastFrequencyBin >= iMaxBytesBetweenFrequencyBins) && !iRequestingFrequencyBins)
{
// Make a request for frequency data
iDecoder->GetFrequencyBins(iFreqArray[iLastFreqArrayIdx].iFreqCoefs, KNumberOfFreqBins);
// Mark that we have issued the request
iRequestingFrequencyBins = ETrue;
}
#endif
TInt len = aBuffer.Length();
TInt ret = iDecoder->Read(aBuffer,len);
if (ret >0)
{
aBuffer.SetLength(len + ret);
iLastPlayBufferBytes+= ret;
#ifdef MDCT_FREQ_ANALYSER
iBytesSinceLastFrequencyBin+= ret;
if (iRequestingFrequencyBins)
{
// Determine the status of the request
TInt requestingFrequencyBins = iDecoder->RequestingFrequencyBins();
if (!requestingFrequencyBins)
{
// The frequency request has completed
iBytesSinceLastFrequencyBin= 0;
iLastFreqArrayIdx++;
if (iLastFreqArrayIdx >= KFreqArrayLength)
iLastFreqArrayIdx = 0;
#if defined(MULTI_THREAD_PLAYBACK)
iFreqArray[iLastFreqArrayIdx].iPcmByte= iSharedData.iTotalBufferBytes;
#else
iFreqArray[iLastFreqArrayIdx].iPcmByte= iLastPlayBufferBytes;
#endif
iRequestingFrequencyBins = EFalse;
}
}
#endif
}
if (ret == 0)
iEof= ETrue;
return ret;
}
void COggPlayback::StartAudioStreamingCallBack()
{
#if defined(MULTI_THREAD_PLAYBACK)
StartStreaming();
#else
for (TInt i=0; i<KBuffers; i++)
SendBuffer(*(iBuffer[i]));
#endif
}
#if defined(MULTI_THREAD_PLAYBACK)
void COggPlayback::RestartAudioStreamingCallBack()
{
StartStreaming();
}
#endif
void COggPlayback::StopAudioStreamingCallBack()
{
Stop();
iObserver->NotifyPlayComplete();
}
TInt COggPlayback::StartAudioStreamingCallBack(TAny* aPtr)
{
COggPlayback* self= (COggPlayback*) aPtr;
self->StartAudioStreamingCallBack();
return 0;
}
TInt COggPlayback::RestartAudioStreamingCallBack(TAny* aPtr)
{
COggPlayback* self= (COggPlayback*) aPtr;
self->RestartAudioStreamingCallBack();
return 0;
}
TInt COggPlayback::StopAudioStreamingCallBack(TAny* aPtr)
{
COggPlayback* self= (COggPlayback*) aPtr;
self->StopAudioStreamingCallBack();
return 0;
}
#if defined(MULTI_THREAD_PLAYBACK)
TInt COggPlayback::AttachToFs()
{
#if defined(SERIES60V3)
return KErrNone;
#else
return iFs.Attach();
#endif
}
TInt COggPlayback::SetAudioProperties(TInt aSampleRate, TInt aChannels)
{
iSharedData.iSampleRate = aSampleRate;
iSharedData.iChannels = aChannels;
return iStreamingThreadCommandHandler->SetAudioProperties();
}
void COggPlayback::StartStreaming()
{
#ifdef MDCT_FREQ_ANALYSER
// Reset the frequency analyser
iLastFreqArrayIdx = 0;
Mem::FillZ(&iFreqArray, sizeof(iFreqArray));
iLastPlayTotalBytes = iSharedData.iTotalBufferBytes;
#endif
// Start the buffering listener
if (iSharedData.iBufferingMode == EBufferThread)
iBufferingThreadAO->StartListening();
// The NGage has a poor memory and always forgets the audio settings
if ((iMachineUid == EMachineUid_NGage) || (iMachineUid == EMachineUid_NGageQD))
iStreamingThreadCommandHandler->SetAudioProperties();
// Start the streaming
iStreamingThreadCommandHandler->StartStreaming();
}
void COggPlayback::StopStreaming()
{
// Stop the streaming
iStreamingThreadCommandHandler->StopStreaming();
// Cancel the buffering AO
iBufferingThreadAO->Cancel();
}
TInt COggPlayback::SetBufferingMode(TBufferingMode aNewBufferingMode)
{
if (aNewBufferingMode == iSharedData.iBufferingMode)
return KErrNone;
// Flush the buffers (and stop the stream)
TBool streamStopped = FlushBuffers(EBufferingModeChanged);
// Set the new buffering mode
TBufferingMode oldMode = iSharedData.iBufferingMode;
iSharedData.iBufferingMode = aNewBufferingMode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -