📄 oggmultithread.cpp
字号:
/*
* Copyright (c) 2005 S. Fisher
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Platform settings
#include <OggOs.h>
// This file is for MULTI_THREAD_PLAYBACK only
#if defined(MULTI_THREAD_PLAYBACK)
#include <e32std.h>
#include "OggLog.h"
#include "OggTremor.h"
#include "OggMultiThread.h"
// Shared data class
TStreamingThreadData::TStreamingThreadData(COggPlayback& aOggPlayback, RThread& aUIThread, RThread& aBufferingThread)
: iOggPlayback(aOggPlayback), iUIThread(aUIThread), iBufferingThread(aBufferingThread),
iNumBuffersRead(0), iNumBuffersPlayed(0), iPrimeBufNum(0), iBufRequestInProgress(EFalse), iLastBuffer(NULL),
iBufferBytesRead(0), iBufferBytesPlayed(0), iTotalBufferBytes(0), iSampleRate(8000), iChannels(1), iBufferingMode(ENoBuffering)
{
}
// Buffering AO (base class for CBufferingThreadAO and CStreamingThreadAO)
CBufferingAO::CBufferingAO(TInt aPriority, TStreamingThreadData& aSharedData)
: CActive(aPriority), iSharedData(aSharedData)
{
}
CBufferingAO::~CBufferingAO()
{
}
// Decode (prime) the next audio buffer
// iSharedData.iPrimeBufNum holds the index of the next buffer
// Set the last buffer ptr if eof is encountered
void CBufferingAO::PrimeNextBuffer()
{
TBool lastBuffer = iSharedData.iOggPlayback.PrimeBuffer(*(iSharedData.iOggPlayback.iBuffer[iSharedData.iPrimeBufNum]));
TInt bufferBytes = iSharedData.iOggPlayback.iBuffer[iSharedData.iPrimeBufNum]->Length();
iSharedData.iTotalBufferBytes += bufferBytes;
iSharedData.iBufferBytesRead += bufferBytes;
iSharedData.iNumBuffersRead++;
if (lastBuffer)
iSharedData.iLastBuffer = iSharedData.iOggPlayback.iBuffer[iSharedData.iPrimeBufNum];
iSharedData.iPrimeBufNum++;
if (iSharedData.iPrimeBufNum == iSharedData.iMaxBuffers)
iSharedData.iPrimeBufNum = 0;
}
// Buffering thread AO (used in MultiThread mode only)
// This AO is owned by the COggPlayback object and runs in the buffering thread
CBufferingThreadAO::CBufferingThreadAO(TStreamingThreadData& aSharedData)
: CBufferingAO(EPriorityIdle, aSharedData)
{
}
CBufferingThreadAO::~CBufferingThreadAO()
{
}
void CBufferingThreadAO::StartListening()
{
// Set the AO active (wait for the streaming thread to make a buffering request)
iStatus = KRequestPending;
SetActive();
}
// Prime the next buffer and self complete to prime more buffers if possible
void CBufferingThreadAO::RunL()
{
// Decode the next buffer
PrimeNextBuffer();
// Stop buffering if we have filled all the buffers (or if we have got to the last buffer)
if ((iSharedData.NumBuffers() == iSharedData.iBuffersToUse) && !iSharedData.iLastBuffer)
{
// Listen for the next buffering request
iStatus = KRequestPending;
SetActive();
iSharedData.iBufRequestInProgress = EFalse;
}
else if (!iSharedData.iLastBuffer)
{
// More buffers are required, so self complete
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
}
else
iSharedData.iBufRequestInProgress = EFalse;
}
// The buffering thread AO is owned by COggPlayback
// The COggPlayback object must ensure that the buffering AO is not cancelled if the streaming thread could be about to make a buffering request
// In other words, the streaming thread must be in a known, "inactive", state before the buffering thread AO is cancelled
void CBufferingThreadAO::DoCancel()
{
// If iSharedData.iBufRequestInProgress is true we will have self completed so there is nothing to do
// If iSharedData.iBufRequestInProgress is false we are waiting for a request from the streaming thread so we must complete the request with KErrCancel
if (!iSharedData.iBufRequestInProgress)
{
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrCancel);
}
iSharedData.iBufRequestInProgress = EFalse;
}
// Streaming thread AO (It is used in SingleThread and MultiThread mode only)
// The streaming thread AO is owned by the playback engine and runs in the streaming thread
// aBufferFlushPending and aBufferingThreadPriority are references to the values held in the playback engine
CStreamingThreadAO::CStreamingThreadAO(TStreamingThreadData& aSharedData, TBool& aBufferFlushPending, TThreadPriority& aBufferingThreadPriority)
: CBufferingAO(EPriorityIdle, aSharedData),iBufferFlushPending(aBufferFlushPending), iBufferingThreadPriority(aBufferingThreadPriority)
{
}
CStreamingThreadAO::~CStreamingThreadAO()
{
}
void CStreamingThreadAO::StartBuffering()
{
// Fetch the pre buffers
for (TInt i = 0 ; i<KPreBuffers ; i++)
PrimeNextBuffer();
// Start the AO
ResumeBuffering();
}
void CStreamingThreadAO::ResumeBuffering()
{
// Schedule the buffering (self complete)
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
}
// Prime the next buffer and self complete to prime more buffers if possible
// In MultiThread mode transfer the buffering to the buffering thread once there are KPrimeBuffers available
void CStreamingThreadAO::RunL()
{
// Decode the next buffer
PrimeNextBuffer();
// If we've got enough buffers and more buffering is required, transfer the buffering to the buffering thread
if ((iSharedData.NumBuffers() > KPrimeBuffers) && !iSharedData.iLastBuffer && (iSharedData.iBufferingMode == EBufferThread))
{
// We can't transfer the buffering if there is a buffer flush pending, so simply return
if (iBufferFlushPending)
return;
// Set the buffering request flag
iSharedData.iBufRequestInProgress = ETrue;
// Increase the buffering thread priority
iBufferingThreadPriority = (iBufferingThreadPriority == EPriorityNormal) ? EPriorityMore : EPriorityAbsoluteHigh;
iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
// Transfer buffering to the buffering thread
TRequestStatus* status = &iSharedData.iBufferingThreadAO->iStatus;
iSharedData.iBufferingThread.RequestComplete(status, KErrNone);
}
else if ((iSharedData.NumBuffers() < iSharedData.iBuffersToUse) && !iSharedData.iLastBuffer)
{
// Self complete (keep buffering)
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
}
}
void CStreamingThreadAO::DoCancel()
{
// There is nothing to do here:
// this AO is either inactive or will have self completed
}
// Streaming thread command handler AO
// The streaming thread command handler is owned by the COggPlayback object and runs in the streaming thread
// Accepts commands from the UI thread (the command thread)
// Executes commands in the streaming thread (the command handler thread)
CStreamingThreadCommandHandler::CStreamingThreadCommandHandler(RThread& aCommandThread, RThread& aStreamingThread, CThreadPanicHandler& aPanicHandler)
: CThreadCommandHandler(EPriorityHigh, aCommandThread, aStreamingThread, aPanicHandler)
{
}
CStreamingThreadCommandHandler::~CStreamingThreadCommandHandler()
{
}
void CStreamingThreadCommandHandler::Volume()
{
SendCommand(EStreamingThreadVolume);
}
void CStreamingThreadCommandHandler::SetVolume()
{
SendCommand(EStreamingThreadSetVolume);
}
TInt CStreamingThreadCommandHandler::SetAudioProperties()
{
return SendCommand(EStreamingThreadSetAudioProperties);
}
void CStreamingThreadCommandHandler::StartStreaming()
{
SendCommand(EStreamingThreadStartStreaming);
}
void CStreamingThreadCommandHandler::StopStreaming()
{
SendCommand(EStreamingThreadStopStreaming);
}
void CStreamingThreadCommandHandler::SetBufferingMode()
{
SendCommand(EStreamingThreadSetBufferingMode);
}
void CStreamingThreadCommandHandler::SetThreadPriority()
{
SendCommand(EStreamingThreadSetThreadPriority);
}
void CStreamingThreadCommandHandler::Position()
{
SendCommand(EStreamingThreadPosition);
}
TBool CStreamingThreadCommandHandler::PrepareToFlushBuffers()
{
return SendCommand(EStreamingThreadPrepareToFlushBuffers) ? ETrue : EFalse;
}
TBool CStreamingThreadCommandHandler::FlushBuffers()
{
return SendCommand(EStreamingThreadFlushBuffers) ? ETrue : EFalse;
}
// Wait for commands
// Commands are passed to the playback engine
void CStreamingThreadCommandHandler::ListenForCommands(CStreamingThreadPlaybackEngine& aPlaybackEngine)
{
iPlaybackEngine = &aPlaybackEngine;
CThreadCommandHandler::ListenForCommands();
}
// Handle commands
// The AO completion status is the command to execute
void CStreamingThreadCommandHandler::RunL()
{
// Get the status
TInt status = iStatus.Int();
// Start listening again
iStatus = KRequestPending;
SetActive();
// Dispatch commands to the playback engine
TInt err = KErrNone;
switch (status)
{
case EStreamingThreadSetAudioProperties:
TRAP(err, iPlaybackEngine->SetAudioPropertiesL());
break;
case EStreamingThreadVolume:
iPlaybackEngine->Volume();
break;
case EStreamingThreadSetVolume:
iPlaybackEngine->SetVolume();
break;
case EStreamingThreadStartStreaming:
iPlaybackEngine->StartStreaming();
break;
case EStreamingThreadStopStreaming:
iPlaybackEngine->StopStreaming();
break;
case EStreamingThreadSetBufferingMode:
iPlaybackEngine->SetBufferingMode();
break;
case EStreamingThreadSetThreadPriority:
iPlaybackEngine->SetThreadPriority();
break;
case EStreamingThreadPosition:
iPlaybackEngine->Position();
break;
case EStreamingThreadPrepareToFlushBuffers:
err = iPlaybackEngine->PrepareToFlushBuffers() ? 1 : 0;
break;
case EStreamingThreadFlushBuffers:
err = iPlaybackEngine->FlushBuffers() ? 1 : 0;
break;
case EThreadShutdown:
iPlaybackEngine->Shutdown();
CActiveScheduler::Stop();
return;
default:
// Panic if we get an unkown command
User::Panic(_L("STCL: RunL"), 0);
break;
}
// Complete the request
RequestComplete(err);
}
void CStreamingThreadCommandHandler::DoCancel()
{
// Stop listening
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -