⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oggtremor.cpp

📁 OggPlay for Symbian 是symbian上的一个媒体播放程序的源码。它支持ogg,wav等等多媒体格式。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
 *  Copyright (c) 2003 L. H. Wilden.
 *
 *  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 non PLUGIN_SYSTEM
#if !defined(PLUGIN_SYSTEM)

#ifdef __VC32__
#pragma warning( disable : 4244 ) // conversion from __int64 to unsigned int: Possible loss of data
#endif

#include "OggLog.h"
#include "OggTremor.h"
#include "TremorDecoder.h"
#ifdef MP3_SUPPORT
#include "MadDecoder.h"
#endif

#include <barsread.h>
#include <eikbtpan.h>
#include <eikcmbut.h>
#include <eiklabel.h>
#include <eikmover.h>
#include <eikbtgpc.h>
#include <eikon.hrh>
#include <eikon.rsg>
#include <charconv.h>
#include <hal.h>

#include "ivorbiscodec.h"
#include "ivorbisfile.h"

#include <OggPlay.rsg>

#if defined(MULTI_THREAD_PLAYBACK)
#ifdef __VC32__
#pragma warning( disable : 4355 ) // 'this' used in base member initializer list
#endif
#endif


// COggPlayback
COggPlayback::COggPlayback(COggMsgEnv* anEnv, MPlaybackObserver* anObserver)
#if defined(MULTI_THREAD_PLAYBACK)
:  CAbsPlayback(anObserver), iEnv(anEnv), iSharedData(*this, iUIThread, iBufferingThread)
#else
:  CAbsPlayback(anObserver), iEnv(anEnv)
#endif
{
#if !defined(MULTI_THREAD_PLAYBACK)
    // These basic rates should be supported by all Symbian OS
    // Higher quality might not be supported.
    iSettings.iChannels  = TMdaAudioDataSettings::EChannelsMono;
    iSettings.iSampleRate= TMdaAudioDataSettings::ESampleRate8000Hz;
	iSettings.iFlags = TMdaAudioDataSettings::ENoNetworkRouting;
#endif
}

void COggPlayback::ConstructL()
{
  // Set up the session with the file server
  User::LeaveIfError(iFs.Connect());

#if defined(MULTI_THREAD_PLAYBACK)
#if defined(SERIES60V3)
  User::LeaveIfError(iFs.ShareAuto());
#else
  User::LeaveIfError(iFs.Share());
#endif

  User::LeaveIfError(AttachToFs());
#endif

#if defined(MULTI_THREAD_PLAYBACK)
  // Create at least one audio buffer
  iBuffer[0] = HBufC8::NewL(KBufferSize48K);

  // Open thread handles to the UI thread and the buffering thread
  // Currently the UI and buffering threads are the same (this thread)
  TThreadId uiThreadId = iThread.Id();
  User::LeaveIfError(iUIThread.Open(uiThreadId));
  User::LeaveIfError(iBufferingThread.Open(uiThreadId));

  // Create the streaming thread
  User::LeaveIfError(iStreamingThread.Create(_L("OggPlayStream"), StreamingThread, KDefaultStackSize, NULL, &iSharedData));

  // Create the streaming thread panic handler
  iStreamingThreadPanicHandler = new(ELeave) CThreadPanicHandler(EPriorityHigh, iStreamingThread, *this);

  // Create the streaming thread command handler
  iStreamingThreadCommandHandler = new(ELeave) CStreamingThreadCommandHandler(iUIThread, iStreamingThread, *iStreamingThreadPanicHandler);
  iSharedData.iStreamingThreadCommandHandler = iStreamingThreadCommandHandler;

  // Create the streaming thread listener
  iStreamingThreadListener = new(ELeave) CStreamingThreadListener(*this, iSharedData);
  iSharedData.iStreamingThreadListener = iStreamingThreadListener;

  // Launch the streaming thread
  User::LeaveIfError(iStreamingThreadCommandHandler->ResumeCommandHandlerThread());

  // Record the fact that the streaming thread started ok
  iStreamingThreadRunning = ETrue;

  // Create the buffering active object
  iBufferingThreadAO = new(ELeave) CBufferingThreadAO(iSharedData);
  iSharedData.iBufferingThreadAO = iBufferingThreadAO;

  // Add it to the buffering threads active scheduler (this thread)
  CActiveScheduler::Add(iBufferingThreadAO);
#else
  iStream = CMdaAudioOutputStream::NewL(*this);
  iStream->Open(&iSettings);

  for (TInt i=0; i<KBuffers; i++)
	iBuffer[i] = HBufC8::NewL(KBufferSize);
#endif

  iStartAudioStreamingTimer = new (ELeave) COggTimer(TCallBack(StartAudioStreamingCallBack, this));
  iRestartAudioStreamingTimer = new (ELeave) COggTimer(TCallBack(RestartAudioStreamingCallBack, this));
  iStopAudioStreamingTimer = new (ELeave) COggTimer(TCallBack(StopAudioStreamingCallBack, this));

  iOggSampleRateConverter = new (ELeave) COggSampleRateConverter;

  // Read the device uid
  HAL::Get(HALData::EMachineUid, iMachineUid);
  TRACEF(COggLog::VA(_L("Phone UID: %x"), iMachineUid ));
}

COggPlayback::~COggPlayback()
{
  __ASSERT_ALWAYS((iState <= EStopped), User::Panic(_L("~COggPlayback"), 0));
	
  delete iDecoder; 
  delete iStartAudioStreamingTimer;
  delete iRestartAudioStreamingTimer;
  delete iStopAudioStreamingTimer;
  delete iOggSampleRateConverter;

#if defined(MULTI_THREAD_PLAYBACK)
  if (iBufferingThreadAO)
	iBufferingThreadAO->Cancel();

  if (iStreamingThreadListener)
	iStreamingThreadListener->Cancel();

  if (iStreamingThreadRunning)
	iStreamingThreadCommandHandler->ShutdownCommandHandlerThread();

  if (iStreamingThreadCommandHandler)
	  iStreamingThreadCommandHandler->Cancel();
	
  if (iStreamingThreadPanicHandler)
	  iStreamingThreadPanicHandler->Cancel();

  iThread.Close();
  iUIThread.Close();
  iBufferingThread.Close();
  iStreamingThread.Close();

  delete iBufferingThreadAO;
  delete iStreamingThreadListener;
  delete iStreamingThreadCommandHandler;
  delete iStreamingThreadPanicHandler;

  for (TInt i = 0 ; i<KMultiThreadBuffers ; i++)
  	delete iBuffer[i];
#else
  delete iStream;

  for (TInt i=0; i<KBuffers; i++)
	delete iBuffer[i];
#endif

  iFs.Close();
}

MDecoder* COggPlayback::GetDecoderL(const TDesC& aFileName)
{
  MDecoder* decoder = NULL;

  TParsePtrC p( aFileName);
  if(p.Ext().Compare( _L(".ogg"))==0 || p.Ext().Compare( _L(".OGG"))==0) {
      decoder=new(ELeave)CTremorDecoder(iFs);
  }
#if defined(MP3_SUPPORT)
  else if(p.Ext().Compare( _L(".mp3"))==0 || p.Ext().Compare( _L(".MP3"))==0) {
    decoder=new(ELeave)CMadDecoder;
  }
#endif
  else {
    _LIT(KPanic,"Panic:");
    _LIT(KNotSupported,"File type not supported");
    iEnv->OggErrorMsgL(KPanic,KNotSupported);
  }

  return decoder;
}

TInt COggPlayback::Open(const TDesC& aFileName)
{
  TRACEF(COggLog::VA(_L("OPEN") ));
  if (iFile)
  {
    iDecoder->Close();
    iFile->Close();
	
	delete iFile;
	iFile = NULL;

	delete iDecoder;
	iDecoder = NULL;
  }

  iTime= 0;

  if (aFileName.Length() == 0) {
    //OGGLOG.Write(_L("Oggplay: Filenamelength is 0 (Error20 Error8"));
    iEnv->OggErrorMsgL(R_OGG_ERROR_20,R_OGG_ERROR_8);
    return -100;
  }

  iFile = new(ELeave) RFile;
  if ((iFile->Open(iFs, aFileName, EFileShareReadersOnly)) != KErrNone)
  {
    delete iFile;
    iFile = NULL;

    //OGGLOG.Write(_L("Oggplay: File open returns 0 (Error20 Error14)"));
    TRACE(COggLog::VA(_L("COggPlayback::Open(%S). Failed"), &aFileName ));
    iEnv->OggErrorMsgL(R_OGG_ERROR_20, R_OGG_ERROR_14);
    return KErrOggFileNotFound;
  }

  iDecoder = GetDecoderL(aFileName);
  if(iDecoder->Open(iFile, aFileName) < 0)
  {
    iDecoder->Close();
    iFile->Close();
	delete iFile;
	iFile = NULL;
    
	delete iDecoder;
	iDecoder = NULL;

	//OGGLOG.Write(_L("Oggplay: ov_open not successful (Error20 Error9)"));
    iEnv->OggErrorMsgL(R_OGG_ERROR_20,R_OGG_ERROR_9);
    return -102;
  }

  iDecoder->ParseTags(iTitle, iArtist, iAlbum, iGenre, iTrackNumber);

  iFileName= aFileName;
  iRate= iDecoder->Rate();
  iChannels=iDecoder->Channels();
  iTime=iDecoder->TimeTotal();
  iBitRate=iDecoder->Bitrate();
  iFileSize= iDecoder->FileSize();
  
  TInt err= SetAudioCaps(iDecoder->Channels(), iDecoder->Rate());
  if (err == KErrNone)
	iState= EStopped;
  else
  {
	iDecoder->Close();
	iFile->Close();
  
	delete iFile;
	iFile = NULL;

	delete iDecoder;
	iDecoder = NULL;
  }

  return err;
}

TBool COggPlayback::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;
}

TInt COggPlayback::SetAudioCaps(TInt theChannels, TInt theRate)
{
  TMdaAudioDataSettings::TAudioCaps ac;
  TMdaAudioDataSettings::TAudioCaps rt;
  TBool convertChannel = EFalse;
  TBool convertRate = EFalse;

  TInt usedRate = 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)
	  {
		  usedRate = 48000;
	      rt = TMdaAudioDataSettings::ESampleRate48000Hz;
	  }
	  else if (theRate>44100)
	  {
		  usedRate = 44100;
	      rt = TMdaAudioDataSettings::ESampleRate44100Hz;
	  }
	  else if (theRate>32000)
	  {
		  usedRate = 32000;
	      rt = TMdaAudioDataSettings::ESampleRate32000Hz;
	  }
	  else if (theRate>22050)
	  {
		  usedRate = 22050;
	      rt = TMdaAudioDataSettings::ESampleRate22050Hz;
	  }
	  else if (theRate>16000)
	  {
		  usedRate = 16000;
	      rt = TMdaAudioDataSettings::ESampleRate16000Hz;
	  }
	  else if (theRate>11025)
	  {
		  usedRate = 11025;
	      rt = TMdaAudioDataSettings::ESampleRate11025Hz;
	  }
	  else if (theRate>8000)
	  {
		  usedRate = 8000;
	      rt = TMdaAudioDataSettings::ESampleRate8000Hz;
	  }
	  else
	  {
		  // Frequencies less than 8KHz are not supported
	      iEnv->OggErrorMsgL(R_OGG_ERROR_20, R_OGG_ERROR_12);
		  return KErrNotSupported;
	  }
  }

  TInt usedChannels = theChannels;
  if (usedChannels == 1)
	  ac = TMdaAudioDataSettings::EChannelsMono;
  else if (usedChannels == 2)
	  ac = TMdaAudioDataSettings::EChannelsStereo;
  else
  {
    iEnv->OggErrorMsgL(R_OGG_ERROR_12, R_OGG_ERROR_10);
    return KErrNotSupported;
  }

  // Note current settings
  TInt bestRate = usedRate;
  TInt convertingRate = convertRate;
  TMdaAudioDataSettings::TAudioCaps bestRT = rt;

  // Try the current settings.
  // Adjust sample rate and channels if necessary
  TInt err = KErrNotSupported;
  while (err == KErrNotSupported)
	{
	#if defined(MULTI_THREAD_PLAYBACK)
	err = SetAudioProperties(usedRate, usedChannels);
	#else
	TRAP(err, iStream->SetAudioPropertiesL(rt, ac));
	#endif

	if (err == KErrNotSupported)
	{
		// Frequency is not supported
		// Try dropping the frequency
		convertRate = GetNextLowerRate(usedRate, rt);

		// If that doesn't work, try changing stereo to mono
		if (!convertRate && (usedChannels == 2))
		{
			// Reset the sample rate
			convertRate = convertingRate;
			usedRate = bestRate;
			rt = bestRT;

			// Drop channels to 1
			usedChannels = 1;
			ac = TMdaAudioDataSettings::EChannelsMono;
			convertChannel = ETrue;
		}
		else if (!convertRate)
			break; // Give up, nothing supported :-(
	}
  }

  TBuf<256> buf,tbuf;
  if (err != KErrNone)
  {
	CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_16);
	CEikonEnv::Static()->ReadResource(tbuf, R_OGG_ERROR_12);
	buf.AppendNum(err);
	iEnv->OggErrorMsgL(tbuf,buf);

	return err;
  }

  // Trace the settings
  TRACEF(COggLog::VA(_L("SetAudioCaps: theRate: %d, theChannels: %d, usedRate: %d, usedChannels: %d"), theRate, theChannels, usedRate, usedChannels));

  if ((convertRate || convertChannel) && iEnv->WarningsEnabled())
  {
	  // Display a warning message
      SamplingRateSupportedMessage(convertRate, theRate, convertChannel, theChannels);

	  // Put the audio properties back the way they were 
	  #if defined(MULTI_THREAD_PLAYBACK)
	  err = SetAudioProperties(usedRate, usedChannels);
	  #else
	  TRAP(err, iStream->SetAudioPropertiesL(rt, ac));
	  #endif

	  // Check that it worked (it should have)
	  if (err != KErrNone)
	  {
		CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_16);
		CEikonEnv::Static()->ReadResource(tbuf, R_OGG_ERROR_12);
		buf.AppendNum(err);
		iEnv->OggErrorMsgL(tbuf,buf);

		return err;
	  }
  }

  // Determine buffer sizes so that we make approx 10-15 calls to the mediaserver per second
  // + another 10-15 calls for position if the frequency analyzer is on screen
  TInt bufferSize = 0;
  switch (usedRate)
  {
	case 48000:
	case 44100:
		bufferSize = KBufferSize48K;
		break;

	case 32000:
		bufferSize = KBufferSize32K;
		break;

	case 22050:
		bufferSize = KBufferSize22K;
		break;

	case 16000:
		bufferSize = KBufferSize16K;
		break;

	case 11025:
	case 8000:
		bufferSize = KBufferSize11K;
		break;

	default:
		User::Panic(_L("COggPlayback:SAC"), 0);
		break;
  }

  if (usedChannels == 1)
	  bufferSize /= 2;

  iOggSampleRateConverter->Init(this, bufferSize, bufferSize-1024, theRate, usedRate, theChannels, usedChannels);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -