📄 oggmultithread.cpp
字号:
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrCancel);
}
// Playback engine class
// Handles communication with the media server (CMdaAoudioOutputStream) and manages the audio buffering
CStreamingThreadPlaybackEngine* CStreamingThreadPlaybackEngine::NewLC(TStreamingThreadData& aSharedData)
{
CStreamingThreadPlaybackEngine* self = new(ELeave) CStreamingThreadPlaybackEngine(aSharedData);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CStreamingThreadPlaybackEngine::CStreamingThreadPlaybackEngine(TStreamingThreadData& aSharedData)
: iSharedData(aSharedData), iBufferingThreadPriority(EPriorityNormal)
{
// Initialise buffer settings
iSharedData.iBuffersToUse = KNoBuffers;
iSharedData.iMaxBuffers = KNoBuffers;
iMaxStreamBuffers = KNoBuffers;
iBufferLowThreshold = KNoBuffers;
}
void CStreamingThreadPlaybackEngine::ConstructL()
{
// Open the stream
iStream = CMdaAudioOutputStream::NewL(*this);
iStream->Open(&iSettings);
iStreamingThreadAO = new(ELeave) CStreamingThreadAO(iSharedData, iBufferFlushPending, iBufferingThreadPriority);
CActiveScheduler::Add(iStreamingThreadAO);
}
CStreamingThreadPlaybackEngine::~CStreamingThreadPlaybackEngine()
{
if (iStreamingThreadAO)
iStreamingThreadAO->Cancel();
iThread.Close();
delete iStreamingThreadAO;
delete iStream;
}
void CStreamingThreadPlaybackEngine::SetAudioPropertiesL()
{
TMdaAudioDataSettings::TAudioCaps ac = TMdaAudioDataSettings::EChannelsMono;
if (iSharedData.iChannels == 1)
ac = TMdaAudioDataSettings::EChannelsMono;
else
ac = TMdaAudioDataSettings::EChannelsStereo;
TMdaAudioDataSettings::TAudioCaps rt = TMdaAudioDataSettings::ESampleRate8000Hz;
switch (iSharedData.iSampleRate)
{
case 8000:
rt = TMdaAudioDataSettings::ESampleRate8000Hz;
break;
case 11025:
rt = TMdaAudioDataSettings::ESampleRate11025Hz;
break;
case 16000:
rt = TMdaAudioDataSettings::ESampleRate16000Hz;
break;
case 22050:
rt = TMdaAudioDataSettings::ESampleRate22050Hz;
break;
case 32000:
rt = TMdaAudioDataSettings::ESampleRate32000Hz;
break;
case 44100:
rt = TMdaAudioDataSettings::ESampleRate44100Hz;
break;
case 48000:
rt = TMdaAudioDataSettings::ESampleRate48000Hz;
break;
default:
User::Leave(KErrNotSupported);
break;
}
iStream->SetAudioPropertiesL(rt, ac);
}
void CStreamingThreadPlaybackEngine::Volume()
{
iSharedData.iVolume = iStream->Volume();
}
void CStreamingThreadPlaybackEngine::SetVolume()
{
TInt vol = iSharedData.iVolume;
if (vol>KMaxVolume)
vol = KMaxVolume;
else if (vol<0)
vol = 0;
vol = (TInt) (((TReal) vol)/KMaxVolume * iMaxVolume);
if (vol > iMaxVolume)
vol = iMaxVolume;
iStream->SetVolume(vol);
}
void CStreamingThreadPlaybackEngine::StartStreaming()
{
if (iStreaming)
User::Panic(_L("STPE: StartStream"), 0);
// Init streaming values
iBufNum = 0;
iStreaming = ETrue;
if (iSharedData.iBufferingMode == ENoBuffering)
{
// Fetch the first buffer
iStreamingThreadAO->PrimeNextBuffer();
// Stream the first buffer
SendNextBuffer();
}
else
{
// Start the streaming thread AO
iStreamingThreadAO->StartBuffering();
// Stream the pre buffers
for (TInt i = 0 ; i<KPreBuffers ; i++)
SendNextBuffer();
}
}
void CStreamingThreadPlaybackEngine::PauseStreaming()
{
// Stop the stream, but don't reset the position
StopStreaming(EFalse);
}
void CStreamingThreadPlaybackEngine::StopStreaming(TBool aResetPosition)
{
if (iStreaming)
{
// Stop the stream
iStream->Stop();
// Stop the AOs
iStreamingThreadAO->Cancel();
// Reset streaming data
iStreaming = EFalse;
iStreamBuffers = 0;
iBufferFlushPending = EFalse;
// Reset shared data
iSharedData.iNumBuffersRead = 0;
iSharedData.iNumBuffersPlayed = 0;
iSharedData.iPrimeBufNum = 0;
iSharedData.iLastBuffer = NULL;
iSharedData.iBufferBytesRead = 0;
iSharedData.iBufferBytesPlayed = 0;
// Reset the thread priorities
if ((iBufferingThreadPriority != EPriorityNormal) && (iBufferingThreadPriority != EPriorityAbsoluteForeground))
{
iBufferingThreadPriority = (iBufferingThreadPriority == EPriorityMore) ? EPriorityNormal : EPriorityAbsoluteForeground;
iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
}
}
if (aResetPosition)
iSharedData.iTotalBufferBytes = 0;
}
void CStreamingThreadPlaybackEngine::SetBufferingMode()
{
if (iStreaming)
User::Panic(_L("STPE: SBM1"), 0);
// Set the buffering values
switch(iSharedData.iBufferingMode)
{
case ENoBuffering:
iMaxStreamBuffers = KNoBuffers;
iBufferLowThreshold = KNoBuffers;
break;
case EBufferStream:
iMaxStreamBuffers = KSingleThreadStreamBuffers;
iBufferLowThreshold = KSingleThreadLowThreshold;
break;
case EBufferThread:
iMaxStreamBuffers = KMultiThreadStreamBuffers;
iBufferLowThreshold = KMultiThreadLowThreshold;
break;
default:
User::Panic(_L("STPE: SBM2"), 0);
break;
}
}
void CStreamingThreadPlaybackEngine::SetThreadPriority()
{
// Set the thread priorities
switch(iSharedData.iStreamingThreadPriority)
{
case ENormal:
// Use normal (relative) thread priorities
if (iBufferingThreadPriority == EPriorityAbsoluteForeground)
iBufferingThreadPriority = EPriorityNormal;
else if (iBufferingThreadPriority == EPriorityAbsoluteHigh)
iBufferingThreadPriority = EPriorityMore;
else
break;
iThread.SetPriority(EPriorityMore);
iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
break;
case EHigh:
// Use high (absolute) thread priorities
if (iBufferingThreadPriority == EPriorityNormal)
iBufferingThreadPriority = EPriorityAbsoluteForeground;
else if (iBufferingThreadPriority == EPriorityMore)
iBufferingThreadPriority = EPriorityAbsoluteHigh;
else
break;
iThread.SetPriority(EPriorityAbsoluteHigh);
iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
break;
default:
User::Panic(_L("STPE: STP"), 0);
break;
}
}
void CStreamingThreadPlaybackEngine::Position()
{
iSharedData.iStreamingPosition = iStream->Position();
}
TBool CStreamingThreadPlaybackEngine::PrepareToFlushBuffers()
{
// Mark that a buffer flush is pending (this inhibits requests to the buffering thread)
iBufferFlushPending = ETrue;
// Return streaming status
return iStreaming;
}
TBool CStreamingThreadPlaybackEngine::FlushBuffers()
{
// Return the streaming status
// (Get the value before we flush the buffers and possibly change it)
TBool ret = iStreaming;
// Reset the buffer flush pending flag
iBufferFlushPending = EFalse;
// Reset the audio stream (move position / change volume gain)
const TInt64 KConst500 = TInt64(500);
switch (iSharedData.iFlushBufferEvent)
{
case EPlaybackPaused:
case EBufferingModeChanged:
{
// Flush all of the data
TInt bufferBytes = iSharedData.BufferBytes();
if (bufferBytes)
{
iSharedData.iTotalBufferBytes-= bufferBytes;
TInt64 newPositionMillisecs = (KConst500*iSharedData.iTotalBufferBytes)/TInt64(iSharedData.iSampleRate*iSharedData.iChannels);
iSharedData.iOggPlayback.SetDecoderPosition(newPositionMillisecs);
}
// Pause the stream
PauseStreaming();
break;
}
case EVolumeGainChanged:
{
// Calculate how much data needs to be flushed
// Don't flush buffers that are already in the stream and leave another KPreBuffers unflushed
TInt availBuffers = iSharedData.NumBuffers() - iStreamBuffers;
TBool buffersToFlush = availBuffers>KPreBuffers;
TInt numFlushBuffers = (buffersToFlush) ? availBuffers-KPreBuffers : 0;
iSharedData.iNumBuffersRead -= numFlushBuffers;
TInt bytesFlushed = 0;
if (buffersToFlush)
{
TInt bufNum = iBufNum + KPreBuffers;
if (bufNum>=iSharedData.iMaxBuffers)
bufNum -= iSharedData.iMaxBuffers;
iSharedData.iPrimeBufNum = bufNum;
for (TInt i = 0 ; i<numFlushBuffers ; i++)
{
bytesFlushed += iSharedData.iOggPlayback.iBuffer[bufNum]->Length();
bufNum++;
if (bufNum == iSharedData.iMaxBuffers)
bufNum = 0;
}
iSharedData.iBufferBytesRead-= bytesFlushed;
}
// Reset the decoder position
if (bytesFlushed)
{
iSharedData.iTotalBufferBytes-= bytesFlushed;
TInt64 newPositionMillisecs = (KConst500*iSharedData.iTotalBufferBytes)/TInt64(iSharedData.iSampleRate*iSharedData.iChannels);
iSharedData.iOggPlayback.SetDecoderPosition(newPositionMillisecs);
}
// Set the new volume gain (and carry on as if nothing had happened)
iSharedData.iOggPlayback.SetSampleRateConverterVolumeGain(iSharedData.iNewGain);
break;
}
case EPositionChanged:
// Recalculate the number of buffer bytes
iSharedData.iTotalBufferBytes = (iSharedData.iNewPosition*TInt64(iSharedData.iSampleRate*iSharedData.iChannels))/KConst500;
// Set the new position
iSharedData.iOggPlayback.SetDecoderPosition(iSharedData.iNewPosition);
// Pause the stream
PauseStreaming();
break;
default:
User::Panic(_L("STPE: Flush"), 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -