📄 shoutcastadapter.cpp
字号:
/*
* ==============================================================================
* Name : ShoutcastAdapter.cpp
* Part of : Shoutcast Engine
* Description : This class implements the shoutcast adapter interface.
* Version : 1
*
* Copyright (c) 2006, Nokia Corporation All rights reserved. Redistribution
* and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: Redistributions
* of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. Redistributions in binary form
* must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided
* with the distribution. Neither the name of the Nokia Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. THIS
* SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ==============================================================================
*/
// INCLUDE FILES
#include <eikmenup.h>
#include <eikapp.h>
#include <AknGlobalNote.h>
#include <ImplementationProxy.h>
#include <S60InternetRadio.rsg>
#include "MInternetRadioAdapterObserver.h"
#include "S60InternetRadio.hrh"
#include "ShoutcastDefs.h"
#include "ShoutcastErrors.h"
#include "ShoutcastUIDs.hrh"
#include "ShoutcastAdapter.h"
#include "ShoutcastStream.h"
#include "scmetadata.h"
// Identifying string for this audio utility
_LIT(KShoutcastAdapter, "Internet Radio");
const TInt KDefaultVolumeLevel = 2;
const TInt KMaxFileSize = 65535;
const TInt KLineFeed = 0x0A;
const TInt KCarriageReturn = 0x0D;
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CShoutcastAdapter::CShoutcastAdapter
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CShoutcastAdapter::CShoutcastAdapter(
MInternetRadioAdapterObserver *aObserver )
: CPluginAdapter(aObserver)
{
iState = ENotReady;
iPrimed = EFalse;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CShoutcastAdapter* CShoutcastAdapter::NewL(
MInternetRadioAdapterObserver *aObserver )
{
CShoutcastAdapter* self = new (ELeave) CShoutcastAdapter(aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::ConstructL()
{
LOG_START;
//TParse parse;
_LIT(dir, "\\Shoutcast\\");
_LIT(wildName,"*.pls");
FindPlayListsL(dir, wildName);
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::FindPlayLists
// Open the requested URL and create the stream
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::FindPlayListsL(
const TDesC& aDir,
const TDesC& aWildname )
{
RFs fs;
//RFile file;
TBuf<50> text;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
text.Copy(_L("Building Playlist"));
iWaitingNote = CAknGlobalNote::NewL();
iWaitingNoteId = iWaitingNote->ShowNoteL(EAknGlobalWaitNote,text);
TFindFile file_finder(fs);
CDir* file_list;
TInt err = file_finder.FindWildByDir(aWildname, aDir, file_list);
while ( err == KErrNone )
{
TInt i;
for (i=0; i<file_list->Count(); i++)
{
TParse fullentry;
fullentry.Set((*file_list)[i].iName,& file_finder.File(),NULL);
// It's ok if the parse fail leave on this file, we'll try to parse the next one.
TRAPD(r,ParsePlaylistFileL(fs, fullentry.FullName()));
}
delete file_list;
err=file_finder.FindWild(file_list);
}
CleanupStack::Pop();
fs.Close();
iWaitingNote->CancelNoteL(iWaitingNoteId);
iWaitingNoteId=0;
delete iWaitingNote;
iWaitingNote=NULL;
CAknGlobalNote *note = CAknGlobalNote::NewLC();
text.Copy(_L("Select a station to listen."));
note->ShowNoteL(EAknGlobalInformationNote ,text);
CleanupStack::PopAndDestroy(note);
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::OpenUrlL
// Open the requested URL and create the stream
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::OpenUrlL(
TInt aUrl )
{
LOG("OpenUrlL");
iStreamSource = CShoutcastStream::NewL(*iURLs[aUrl], *this);
iStreamSource->SetVolume(KDefaultVolumeLevel);
iNrMetadata = iStreamSource->GetNumberOfMetaDataEntries();
iState=EReadyToPlay;
iPrimed=EFalse;
iObserver->ResetMetadata();
LOG("OpenUrlL OK");
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::CloseUrl
// Closes the currently opened URL and delete the stream
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::CloseUrl()
{
LOG("CloseUrl");
delete iStreamSource;
iStreamSource = NULL;
iState = ENotReady;
LOG("CloseUrl OK");
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::~CShoutcastAdapter
// -----------------------------------------------------------------------------
//
CShoutcastAdapter::~CShoutcastAdapter()
{
LOG("Destructor");
CloseUrl();
delete iWaitingNote;
iWaitingNote = NULL;
delete iErrorNote;
iErrorNote = NULL;
delete iWaitDialog;
iWaitDialog = NULL;
iURLs.ResetAndDestroy();
LOG("Destructor OK");
LOG_END;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::GetMenuText
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::GetMenuText(
TDes &aName )
{
LOG("GetMenuText")
aName.Copy(KShoutcastAdapter);
LOG("GetMenuText OK")
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::GetMenuCommand
// This menu command number is used on the UI level. When the user selects a
// utility on the menu, this command number is used to find this adapter.
// The usage is like the hard-coded command values in the menu resource (rss).
// -----------------------------------------------------------------------------
//
TInt CShoutcastAdapter::GetMenuCommand()
{
return 0x2001; //Should be a defined constant
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::AddExtraMenu
// Add each item in the playlist as an entry to the "Stations" menu.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::AddExtraMenu(
CEikMenuPane* aMenuPane )
{
LOG("AddExtraMenu")
CEikMenuPaneItem::SData sd;
//LOG1("URL count %d", iURLs.Count());
for ( TInt i = 0; i< iURLs.Count(); i+=2 )
{
sd.iCommandId = 0x2010 + (TInt)(i/2);
sd.iText.Copy(iURLs[i+1]->Left(30));
sd.iFlags = 0;
sd.iCascadeId = 0;
TRAPD(r,aMenuPane->AddMenuItemL(sd));
}
LOG("AddExtraMenu OK")
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::HandleCommandL
// When a station is selected from the UI, it is translated into a command which
// is mapped to a URL. The command index is used to lookup the URL.
// -----------------------------------------------------------------------------
//
TBool CShoutcastAdapter::HandleCommandL(
TInt aCommand )
{
LOG("HandleCommandL")
for ( TInt i=0; i < iURLs.Count(); i+=2 )
if ( aCommand == 0x2010 + (TInt)(i/2) )
{
if ( iState == EPlaying )
{
StopL();
}
CloseUrl();
OpenUrlL(i);//this method can leave
PlayL();
return ETrue;
}
LOG("HandleCommandL OK")
return EFalse;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::UpdateMenuL
// The menu pane is updated to show only options available in the current state
// of the adapter.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::UpdateMenuL(CEikMenuPane* aMenuPane)
{
LOG("UpdateMenuL")
aMenuPane->SetItemDimmed(ES60InternetRadioCmdPlay, ETrue);
aMenuPane->SetItemDimmed(ES60InternetRadioCmdStop, ETrue);
aMenuPane->SetItemDimmed(ES60InternetRadioCmdChange, ETrue);
aMenuPane->SetItemDimmed(ES60InternetRadioCmdFileSelect, ETrue);
switch ( iState )
{
case ENotReady:
aMenuPane->SetItemDimmed(ES60InternetRadioCmdChange, EFalse);
break;
case EReadyToPlay:
//aMenuPane->SetItemDimmed(ES60InternetRadioCmdPlay, EFalse);
aMenuPane->SetItemDimmed(ES60InternetRadioCmdChange, EFalse);
break;
case EPlaying:
aMenuPane->SetItemDimmed(ES60InternetRadioCmdStop, EFalse);
break;
default:
User::Panic(KShoutcastAdapter, 0);
break;
}
//the extra menu is available to shoutcast
aMenuPane->SetItemDimmed(ES60InternetRadioCmdExtra,EFalse);
aMenuPane->SetItemTextL(ES60InternetRadioCmdExtra,_L("Stations"));
LOG("UpdateMenuL OK")
}
// -----------------------------------------------------------------------------
// CShoutcastStream::PlayL
// Starts the stream playback
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::PlayL()
{
LOG("CShoutcastAdapter::PlayL")
TInt err;
if ( iState != EReadyToPlay )
{
User::Leave(KErrNotReady);
}
if ( !iPrimed )
{
// The source is not primed, so prime it first
TRAP(err, iStreamSource->PrimeL());
if ( err )
{
HandleError(err, EOpPrime);
iStreamSource->Stop();
CloseUrl();
return;
}
//the actual play command is given when we are connected
}
else
{
//the shoutcast stream was only paused
//issue PLay command
TRAP(err, iStreamSource->PlayL());
if ( err )
{
HandleError(err, EOpPlay);
iStreamSource->Stop();
return;
}
iState = EPlaying;
//update metadata
CMetaDataEntry *mdEntry = NULL;
TRAP(err, mdEntry = iStreamSource->GetMetaDataEntryL(3));
if ( !err )
{
if ( iObserver )
{
iObserver->SetMetadata(3, mdEntry->Value(), ETrue);
}
delete mdEntry;
mdEntry = NULL;
}
}
LOG("CShoutcastAdapter::PlayL OK")
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::PauseL
// This implementation pauses the playback but doesn't stop receiving
// streaming data thus allowing the playback to resume quickly.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::PauseL()
{
LOG("CShoutcastAdapter::PauseL")
if ( iState == EPlaying )
{
iStreamSource->Pause();
iState = EReadyToPlay;
TBufC<10> buf=_L("Paused");
DeleteLabels(EFalse,&buf);
}
LOG("CShoutcastAdapter::PauseL OK")
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::RecordL
// This is not supported.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::RecordL()
{
User::Leave(KErrNotSupported);
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::StopL
// Stops the playback and the URL is also closed.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::StopL()
{
LOG("CShoutcastAdapter::StopL")
if ( iState == EPlaying )
{
iStreamSource->Stop();
iState = EReadyToPlay;
iPrimed = EFalse;
TBufC<10> buf=_L("Stopped");
DeleteLabels(EFalse,&buf);
}
LOG("CShoutcastAdapter::StopL OK")
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::Identify
// Returned the identity of the adapter.
// -----------------------------------------------------------------------------
//
const TDesC& CShoutcastAdapter::Identify() const
{
return KShoutcastAdapter;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::SupportMetadata
//
// -----------------------------------------------------------------------------
//
TInt CShoutcastAdapter::SupportMetadata() const
{
return iNrMetadata;
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::TogglePlayPause
// Toggles play and stop.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::TogglePlayPause()
{
if ( iState == EReadyToPlay )
{
PlayL();
}
else if ( iState == EPlaying )
{
PauseL();
}
}
// -----------------------------------------------------------------------------
// CShoutcastAdapter::HandleEvent
// Handle events from the shoutcast stream.
// -----------------------------------------------------------------------------
//
void CShoutcastAdapter::HandleEvent(
TUid aEvent,
TInt aError)
{
TInt r;
LOG2("HandleEvent: We got an Event: %x %d", aEvent, aError);
// Metadata update event
if ( aEvent == TUid::Uid(KShoutcastStreamUid) && aError > 0x0100 && aError < 0x0200 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -