📄 oggplaycontroller.cpp
字号:
/*
* Copyright (c) 2004 OggPlayTeam
*
* 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.
*/
#include "OggPlayController.h"
#include <charconv.h>
#include <utf.h>
#include "OggLog.h"
#include "Plugin\ImplementationUIDs.hrh"
#include "Plugin\OggPlayControllerCustomCommands.h"
#if 1
#include <e32svr.h>
#define PRINT(x) TRACEF(_L(x));
//#define PRINT(x) RDebug::Print _L(x);
#else
#define PRINT()
#endif
// Nokia phones don't seem to like large buffers, so just use one size (4K)
#define USE_FIXED_SIZE_BUFFERS
// Buffer sizes to use
// (approx. 0.1s of audio per buffer)
#if defined(USE_FIXED_SIZE_BUFFERS)
const TInt KBufferSize48K = 4096;
const TInt KBufferSize32K = 4096;
const TInt KBufferSize22K = 4096;
const TInt KBufferSize16K = 4096;
const TInt KBufferSize11K = 4096;
#else
const TInt KBufferSize48K = 16384;
const TInt KBufferSize32K = 12288;
const TInt KBufferSize22K = 8192;
const TInt KBufferSize16K = 6144;
const TInt KBufferSize11K = 4096;
#endif
COggPlayController* COggPlayController::NewL(RFs* aFs, MDecoder *aDecoder)
{
PRINT("COggPlayController::NewL()");
// Take ownership of the file session and the decoder
COggPlayController* self = new COggPlayController(aFs, aDecoder);
if (!self)
{
delete aDecoder;
aFs->Close();
delete aFs;
User::Leave(KErrNoMemory);
}
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
COggPlayController::COggPlayController(RFs* aFs, MDecoder *aDecoder)
: iFs(aFs), iDecoder(aDecoder)
{
}
COggPlayController::~COggPlayController()
{
PRINT("COggPlayController::~COggPlayController In");
iState = EStateDestroying;
delete iStream;
delete iStreamMessage;
if (iOwnSinkBuffer)
delete iSinkBuffer;
delete iOggSource;
if (iAudioOutput)
iAudioOutput->SinkThreadLogoff();
iDecoder->Clear();
if (iFile)
iFile->Close();
delete iFile;
delete iDecoder;
iFs->Close();
delete iFs;
PRINT("COggPlayController::~COggPlayController Out");
COggLog::Exit(); // MUST BE AFTER LAST TRACE, otherwise will leak memory
}
void COggPlayController::ConstructL()
{
PRINT("COggPlayController::ConstructL() In");
// Construct custom command parsers
CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser =
CMMFAudioPlayDeviceCustomCommandParser::NewL(*this);
CleanupStack::PushL(audPlayDevParser);
AddCustomCommandParserL(*audPlayDevParser); //parser now owned by controller framework
CleanupStack::Pop();//audPlayDevParser
CMMFAudioPlayControllerCustomCommandParser* audPlayCtrlParser =
CMMFAudioPlayControllerCustomCommandParser::NewL(*this);
CleanupStack::PushL(audPlayCtrlParser);
AddCustomCommandParserL(*audPlayCtrlParser); //parser now owned by controller framework
CleanupStack::Pop(audPlayCtrlParser);
iState = EStateNotOpened;
// We do not want to look at file duration when discovering the file: it takes too long
// If DurationL is asked before we actually have the information, pretend length is 5 minutes.
iFileLength = TTimeIntervalMicroSeconds(5*60*1000000);
iOggSource = new(ELeave) COggSource(*this);
// Open an audio stream (used for determining audio capabilities)
iStream = CMdaAudioOutputStream::NewL(*this);
iStream->Open(&iSettings);
PRINT("COggPlayController::ConstructL() Out");
}
_LIT(KRandomRingingToneFileName, "random_ringing_tone.ogg");
_LIT(KRandomRingingToneTitle, "this is a random ringing tone");
void COggPlayController::AddDataSourceL(MDataSource& aDataSource)
{
PRINT("COggPlayController::AddDataSourceL In");
if ( iState != EStateNotOpened )
{
User::Leave(KOggPlayPluginErrNotReady);
}
iRandomRingingTone = EFalse;
TUid uid = aDataSource.DataSourceType() ;
if (uid == KUidMmfFileSource)
{
CMMFFile* aFile = STATIC_CAST(CMMFFile*, &aDataSource);
iFileName = aFile->FullName();
TParsePtrC aP(iFileName);
TBool result = aP.NameAndExt().CompareF(KRandomRingingToneFileName) == 0;
if ( result )
{
// Use a random file, for ringing tones
TFileName aPathToSearch = aP.Drive();
aPathToSearch.Append ( aP.Path() );
CDir* dirList;
User::LeaveIfError(iFs->GetDir(aPathToSearch,
KEntryAttMaskSupported,ESortByName,dirList));
TInt nbFound=0;
TInt i;
for (i=0;i<dirList->Count();i++)
{
TParsePtrC aParser((*dirList)[i].iName);
TBool found = ( aParser.Ext().CompareF(_L(".ogg")) == 0 );
TBool theRandomTone = ( ( (*dirList)[i].iName).CompareF(KRandomRingingToneFileName) == 0);
if (found && !theRandomTone)
nbFound++;
}
if (nbFound == 0)
{
// Only the random_ringing_tone.ogg in that directory, leave
User::Leave(KErrNotFound);
}
#if defined(SERIES60V3)
TInt64 rnd64 = Math::Random();
TInt64 maxInt64 = MAKE_TINT64(1, 0);
TInt64 nbFound64 = nbFound;
TInt64 picked64 = (rnd64 * nbFound64) / maxInt64;
TInt picked = I64LOW(picked64);
#else //2.x
TInt64 rnd64 = TInt64(0, Math::Random());
TInt64 maxInt64 = TInt64(1, 0);
TInt64 nbFound64 = nbFound;
TInt64 picked64 = (rnd64 * nbFound64) / maxInt64;
TInt picked = picked64.Low();
#endif
nbFound=-1;
for (i=0;i<dirList->Count();i++)
{
TParsePtrC aParser((*dirList)[i].iName);
TBool found = ( aParser.Ext().CompareF(_L(".ogg")) == 0 );
TBool theRandomTone = ( ( (*dirList)[i].iName).CompareF(KRandomRingingToneFileName) == 0);
if (found && !theRandomTone)
nbFound++;
if (nbFound == picked)
break;
}
iFileName = aPathToSearch;
iFileName.Append ( (*dirList)[i].iName );
TRACEF(COggLog::VA(_L("Random iFileName choosen %S "),&iFileName ));
delete dirList;
iRandomRingingTone = ETrue;
}
}
else
{
User::Leave(KOggPlayPluginErrNotSupported);
}
TRACEF(COggLog::VA(_L("iFileName %S "),&iFileName ));
// Open the file here, in order to get the tags.
OpenFileL(iFileName,ETrue);
// Save the tags.
iDecoder->Clear(); // Close the file. This is required for the ringing tone stuff.
if (iFile)
iFile->Close();
delete iFile;
iFile = NULL;
iState = EStateNotOpened;
PRINT("COggPlayController::AddDataSourceL Out");
}
void COggPlayController::AddDataSinkL(MDataSink& aDataSink)
{
PRINT("COggPlayController::AddDataSinkL In");
if (aDataSink.DataSinkType() != KUidMmfAudioOutput)
User::Leave(KErrNotSupported);
if (iAudioOutput)
User::Leave(KErrNotSupported);
iAudioOutput = static_cast<CMMFAudioOutput*>(&aDataSink);
iAudioOutput->SinkThreadLogon(*this);
iAudioOutput->SetSinkPrioritySettings(iMMFPrioritySettings);
PRINT("COggPlayController::AddDataSinkL Out");
}
void COggPlayController::RemoveDataSourceL(MDataSource& /*aDataSource*/)
{
PRINT("COggPlayController::RemoveDataSourceL");
// Nothing to do
}
void COggPlayController::RemoveDataSinkL(MDataSink& aDataSink)
{
PRINT("COggPlayController::RemoveDataSinkL");
if (iState==EStatePlaying)
User::Leave(KErrNotReady);
if (iAudioOutput==&aDataSink)
iAudioOutput=NULL;
}
void COggPlayController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
{
PRINT("COggPlayController::SetPrioritySettingsL");
// Not implemented yet
iMMFPrioritySettings = aPrioritySettings;
if (iAudioOutput)
iAudioOutput->SetSinkPrioritySettings(aPrioritySettings);
}
TInt COggPlayController::SendEventToClient(const TMMFEvent& aEvent)
{
PRINT("COggPlayController::SendEventToClient");
TRACEF(COggLog::VA(_L("Event %i %i"), aEvent.iEventType,aEvent.iErrorCode ));
TMMFEvent myEvent = aEvent;
if (myEvent.iErrorCode == KErrUnderflow)
myEvent.iErrorCode = KErrNone; // Client expect KErrNone when playing as completed correctly
if (aEvent.iErrorCode == KErrDied)
iState = EStateInterrupted;
return DoSendEventToClient(myEvent);
}
void COggPlayController::ResetL()
{
PRINT("COggPlayController::ResetL");
iAudioOutput=NULL;
iDecoder->Clear();
if (iFile)
iFile->Close();
delete iFile;
iFile = NULL;
iState= EStateNotOpened;
}
TBool COggPlayController::GetNextLowerRate(TInt& usedRate, TMdaAudioDataSettings::TAudioCaps& rt)
{
TBool retValue = ETrue;
switch (usedRate)
{
case 48000:
usedRate = 44100;
rt = TMdaAudioDataSettings::ESampleRate44100Hz;
break;
case 44100:
usedRate = 32000;
rt = TMdaAudioDataSettings::ESampleRate32000Hz;
break;
case 32000:
usedRate = 22050;
rt = TMdaAudioDataSettings::ESampleRate22050Hz;
break;
case 22050:
usedRate = 16000;
rt = TMdaAudioDataSettings::ESampleRate16000Hz;
break;
case 16000:
usedRate = 11025;
rt = TMdaAudioDataSettings::ESampleRate11025Hz;
break;
case 11025:
usedRate = 8000;
rt = TMdaAudioDataSettings::ESampleRate8000Hz;
break;
default:
retValue = EFalse;
break;
}
return retValue;
}
void COggPlayController::SetAudioCapsL(TInt theRate, TInt theChannels)
{
TMdaAudioDataSettings::TAudioCaps ac(TMdaAudioDataSettings::EChannelsMono);
TMdaAudioDataSettings::TAudioCaps rt(TMdaAudioDataSettings::ESampleRate8000Hz);
TBool convertChannel = EFalse;
TBool convertRate = EFalse;
iUsedRate = theRate;
if (theRate==8000) rt= TMdaAudioDataSettings::ESampleRate8000Hz;
else if (theRate==11025) rt= TMdaAudioDataSettings::ESampleRate11025Hz;
else if (theRate==16000) rt= TMdaAudioDataSettings::ESampleRate16000Hz;
else if (theRate==22050) rt= TMdaAudioDataSettings::ESampleRate22050Hz;
else if (theRate==32000) rt= TMdaAudioDataSettings::ESampleRate32000Hz;
else if (theRate==44100) rt= TMdaAudioDataSettings::ESampleRate44100Hz;
else if (theRate==48000) rt= TMdaAudioDataSettings::ESampleRate48000Hz;
else
{
// Rate not supported by the phone
TRACEF(COggLog::VA(_L("SetAudioCaps: Non standard rate: %d"), theRate));
// Convert to nearest rate
convertRate = ETrue;
if (theRate>48000)
{
iUsedRate = 48000;
rt = TMdaAudioDataSettings::ESampleRate48000Hz;
}
else if (theRate>44100)
{
iUsedRate = 44100;
rt = TMdaAudioDataSettings::ESampleRate44100Hz;
}
else if (theRate>32000)
{
iUsedRate = 32000;
rt = TMdaAudioDataSettings::ESampleRate32000Hz;
}
else if (theRate>22050)
{
iUsedRate = 22050;
rt = TMdaAudioDataSettings::ESampleRate22050Hz;
}
else if (theRate>16000)
{
iUsedRate = 16000;
rt = TMdaAudioDataSettings::ESampleRate16000Hz;
}
else if (theRate>11025)
{
iUsedRate = 11025;
rt = TMdaAudioDataSettings::ESampleRate11025Hz;
}
else if (theRate>8000)
{
iUsedRate = 8000;
rt = TMdaAudioDataSettings::ESampleRate8000Hz;
}
else
{
// Frequencies less than 8KHz are not supported
// iEnv->OggErrorMsgL(R_OGG_ERROR_20, R_OGG_ERROR_12);
User::Leave(KErrNotSupported);
}
}
iUsedChannels = theChannels;
if (iUsedChannels == 1)
ac = TMdaAudioDataSettings::EChannelsMono;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -