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

📄 oggtremor.cpp

📁 OggPlay for Symbian 是symbian上的一个媒体播放程序的源码。它支持ogg,wav等等多媒体格式。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
 
  // Set buffering values and allocate or free buffers
  TInt err = BufferingModeChanged();
  if (err != KErrNone)
  {
	  // Reset back to the old mode
	  iSharedData.iBufferingMode = oldMode;

	  // Free any buffers that got allocated
	  BufferingModeChanged();

	  // Restart the stream
	  if (streamStopped)
		iRestartAudioStreamingTimer->Wait(KStreamStartDelay);

	  return err;
  }

  // Set the new buffering mode values in the streaming thread
  iStreamingThreadCommandHandler->SetBufferingMode();

  // Restart the stream
  if (streamStopped)
	iRestartAudioStreamingTimer->Wait(KStreamStartDelay);

  return KErrNone;
}

void COggPlayback::SetThreadPriority(TStreamingThreadPriority aNewThreadPriority)
{
  // Set the thread priorities (Normal or High)
  iSharedData.iStreamingThreadPriority = aNewThreadPriority;
  iStreamingThreadCommandHandler->SetThreadPriority();
}

TBool COggPlayback::FlushBuffers(TFlushBufferEvent aFlushBufferEvent)
{
  __ASSERT_DEBUG((aFlushBufferEvent == EBufferingModeChanged) || (aFlushBufferEvent == EPlaybackPaused), User::Panic(_L("COggPlayback::FB"), 0));

  // Set the flush buffer event
  iSharedData.iFlushBufferEvent = aFlushBufferEvent;

  iStreamingThreadCommandHandler->PrepareToFlushBuffers();
  iBufferingThreadAO->Cancel();

  return iStreamingThreadCommandHandler->FlushBuffers();
}

TBool COggPlayback::FlushBuffers(TInt64 aNewPosition)
{
  // The position has been changed so flush the buffers (and set the new position)
  iSharedData.iFlushBufferEvent = EPositionChanged;
  iSharedData.iNewPosition = aNewPosition;

  iStreamingThreadCommandHandler->PrepareToFlushBuffers();
  iBufferingThreadAO->Cancel();

  return iStreamingThreadCommandHandler->FlushBuffers();
}

void COggPlayback::FlushBuffers(TGainType aNewGain)
{
  // The volume gain has been changed so flush the buffers (and set the new gain)
  iSharedData.iFlushBufferEvent = EVolumeGainChanged;
  iSharedData.iNewGain = aNewGain;

  TBool streaming = iStreamingThreadCommandHandler->PrepareToFlushBuffers();
  iBufferingThreadAO->Cancel();

  if (streaming && (iSharedData.iBufferingMode == EBufferThread))
	iBufferingThreadAO->StartListening();

  iStreamingThreadCommandHandler->FlushBuffers();
}

void COggPlayback::SetDecoderPosition(TInt64 aPos)
{
  // Set the deocder position (aPos is in milliseconds)
  iDecoder->Setposition(aPos);
}

void COggPlayback::SetSampleRateConverterVolumeGain(TGainType aGain)
{
  // Set the volume gain (called by the streaming thread after the buffers have been flushed)
  iOggSampleRateConverter->SetVolumeGain(aGain);
}

TInt COggPlayback::StreamingThread(TAny* aThreadData)
{
  // Access the shared data / command handler
  TStreamingThreadData& sharedData = *((TStreamingThreadData *) aThreadData);
  CStreamingThreadCommandHandler& streamingThreadCommandHandler = *sharedData.iStreamingThreadCommandHandler;

  // Create a cleanup stack
  CTrapCleanup* cleanupStack = CTrapCleanup::New();
  if (!cleanupStack)
  {
	// Inform the UI thread that starting the streaming thread failed
	streamingThreadCommandHandler.ResumeComplete(KErrNoMemory);
	return KErrNoMemory;
  }

  // Set the thread priority
  RThread streamingThread;
  streamingThread.SetPriority(EPriorityMore);
  streamingThread.Close();

  // Allocate resources and start the active scheduler
  TRAPD(err, StreamingThreadL(sharedData));

  // Cleanup
  COggLog::Exit();  
  delete cleanupStack;

  // Complete the shutdown request
  streamingThreadCommandHandler.ShutdownComplete(err);
  return err;
}

void COggPlayback::StreamingThreadL(TStreamingThreadData& aSharedData)
{
  // Attach to the file session
  User::LeaveIfError(aSharedData.iOggPlayback.AttachToFs());

  // Create a scheduler
  CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
  CleanupStack::PushL(scheduler);

  // Install the scheduler
  CActiveScheduler::Install(scheduler);

  // Add the streaming command handler to the scheduler
  CStreamingThreadCommandHandler& streamingThreadCommandHandler = *aSharedData.iStreamingThreadCommandHandler;
  CActiveScheduler::Add(&streamingThreadCommandHandler);

  // Create the audio playback engine
  CStreamingThreadPlaybackEngine* playbackEngine = CStreamingThreadPlaybackEngine::NewLC(aSharedData);

  // Listen for commands and dispatch them to the playback engine
  streamingThreadCommandHandler.ListenForCommands(*playbackEngine);

  // Inform the UI thread that the streaming thread has started
  streamingThreadCommandHandler.ResumeComplete(KErrNone);

  // Start the scheduler
  CActiveScheduler::Start();

  // Cancel the command handler
  streamingThreadCommandHandler.Cancel();

  // Uninstall the scheduler
  CActiveScheduler::Install(NULL);

  // Delete the scheduler and audio engine
  CleanupStack::PopAndDestroy(2, scheduler);
}

TBool COggPlayback::PrimeBuffer(HBufC8& buf)
{
  // Read and decode the next buffer
  TPtr8 bufPtr(buf.Des());
  iOggSampleRateConverter->FillBuffer(bufPtr);
  return iEof;
}

void COggPlayback::NotifyOpenComplete(TInt aErr)
{
  // Called by the streaming thread listener when CMdaAudioOutputStream::Open() completes
  if (aErr == KErrNone)
	iState = EStreamOpen;

  iObserver->NotifyStreamOpen(aErr);
}

TInt COggPlayback::BufferingModeChanged()
{
  // The buffering mode has changed so allocate or free buffers
  TInt i;
  TInt allocError = KErrNone;
  switch (iSharedData.iBufferingMode)
  {
	case ENoBuffering:
		iSharedData.iBuffersToUse = KNoBuffers;
		iSharedData.iMaxBuffers = KNoBuffers;

		// Delete all the buffers
		for (i = 1 ; i<KMultiThreadBuffers ; i++)
		{
			delete iBuffer[i];
			iBuffer[i] = NULL;
		}
		break;

	case EBufferStream:
		iSharedData.iBuffersToUse = KSingleThreadBuffersToUse;
		iSharedData.iMaxBuffers = KSingleThreadBuffers;

		if (iBuffer[KNoBuffers])
		{
			// The previous mode was EBufferThread so free some buffers
			for (i = KSingleThreadBuffers ; i<KMultiThreadBuffers ; i++)
			{
				delete iBuffer[i];
				iBuffer[i] = NULL;
			}
		}
		else
		{
			// Allocate the buffers
			for (i = 1 ; i<KSingleThreadBuffers ; i++)
			{
				iBuffer[i] = HBufC8::New(KBufferSize48K);
				if (!iBuffer[i])
				{
					allocError = KErrNoMemory;
					break;
				}
			}
		}
		break;

	case EBufferThread:
		iSharedData.iBuffersToUse = KMultiThreadBuffersToUse;
		iSharedData.iMaxBuffers = KMultiThreadBuffers;

		if (iBuffer[KNoBuffers])
		{
			// The previous mode was EBufferStream so allocate some more buffers
			for (i = KSingleThreadBuffers ; i<KMultiThreadBuffers ; i++)
			{
				iBuffer[i] = HBufC8::New(KBufferSize48K);
				if (!iBuffer[i])
				{
					allocError = KErrNoMemory;
					break;
				}
			}
		}
		else
		{
			// Allocate the buffers
			for (i = 1 ; i<KMultiThreadBuffers ; i++)
			{
				iBuffer[i] = HBufC8::New(KBufferSize48K);
				if (!iBuffer[i])
				{
					allocError = KErrNoMemory;
					break;
				}
			}
		}
		break;
  }

  return allocError;
}

void COggPlayback::NotifyStreamingStatus(TInt aErr)
{
  // Called by the streaming thread listener when the last buffer has been copied or play has been interrupted
  // Theoretically it's possible for a restart to be in progress, so make sure it doesn't complete
  // (i.e. when the streaming thread generates an event at the same time as the UI thread has started processing a RW\FW key press)
  iRestartAudioStreamingTimer->Cancel();

  // Ignore streaming status if we are already handling an error
  if (iStreamingErrorDetected)
	return;

  // Check for an error
  if (aErr < 0)
  {
	// Pause the stream
    FlushBuffers(EPlaybackPaused);
	iStreamingErrorDetected = ETrue;

	// Notify the user
	TBuf<256> buf, tbuf;
	if (aErr == KErrInUse)
		{
		CEikonEnv::Static()->ReadResource(tbuf, R_OGG_ERROR_18);
		CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_30);
		}
	else
		{
		CEikonEnv::Static()->ReadResource(tbuf, R_OGG_ERROR_18);
		CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_16);	
		buf.AppendNum(aErr);
		}

	// Display the message and wait for the user
	iEnv->OggErrorMsgL(tbuf, buf);

	// Notify the UI, try to restart
	iObserver->NotifyPlayInterrupted();
	iStreamingErrorDetected = EFalse;
	return;
  }

  // Handle stream events
  TStreamingThreadStatus status = (TStreamingThreadStatus) aErr;
  switch (status)
  {
	case ELastBufferCopied:
		// Not all phones call MaoscPlayComplete,
		// so start a timer that will stop playback afer a delay 
		iStopAudioStreamingTimer->Wait(KStreamStopDelay);
		break;

	case EPlayInterrupted:
		// Playback has been interrupted so notify the observer
		iObserver->NotifyPlayInterrupted();
		break;

	case EPlayUnderflow:
		// Flush buffers (and pause the stream)
		FlushBuffers(EPlaybackPaused);
		iRestartAudioStreamingTimer->Wait(KStreamRestartDelay);
		break;

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

void COggPlayback::HandleThreadPanic(RThread& /* aPanicThread */, TInt /* aErr */)
{
  // Great, the streaming thread has panic'd, now what do we do!?
  iStreamingThreadRunning = EFalse;
  iState = EClosed;
  
  // Try to exit cleanly
  iObserver->NotifyFatalPlayError();
}

#else
void COggPlayback::SendBuffer(HBufC8& buf)
{
  if (iEof) return;
  if (iState==EPaused) return;

  long ret=0;
  TInt cnt = 0;
  TPtr8 bufPtr(buf.Des());
  if (iFirstBuffers)  {
      cnt = 4000;
      bufPtr.FillZ(cnt);
      ret = cnt;
      iLastPlayBufferBytes+= cnt;
      iFirstBuffers--;
  
  } else {
    
     ret = iOggSampleRateConverter->FillBuffer(bufPtr);
  }

  if (ret < 0) {
    // Error in the stream. Bad luck, we will continue anyway.
  } else {
    TRAPD( err, iStream->WriteL(buf) );
    if (err!=KErrNone) {
      // This should never ever happen.
      TBuf<256> cbuf,tbuf;
      CEikonEnv::Static()->ReadResource(cbuf,R_OGG_ERROR_16);
      CEikonEnv::Static()->ReadResource(tbuf,R_OGG_ERROR_17);
      cbuf.AppendNum(err);
      iEnv->OggErrorMsgL(tbuf,cbuf);
      User::Leave(err);
    }
    iSentIdx++;
    if (iSentIdx>=KBuffers) iSentIdx=0;
    iSent[iSentIdx]= &buf;
  }
}

void COggPlayback::MaoscPlayComplete(TInt aErr)
{
  // Error codes:
  // KErrCancel      -3
  // KErrUnderflow  -10
  // KErrDied       -13  (interrupted by higher priority)
  // KErrInUse      -14

    
  TRACEF(COggLog::VA(_L("MaoscPlayComplete:%d"), aErr ));
  if (iState==EPaused || iState==EStopped) return;

  if (aErr == KErrUnderflow) 
      return;
  if (aErr == KErrInUse) aErr= KErrNone;

  if (aErr == KErrCancel)
      return;

  if (aErr == KErrDied) {
    iObserver->NotifyPlayInterrupted();
    return;
  }

  if (aErr != KErrNone) {
    TBuf<256> buf,tbuf;
    CEikonEnv::Static()->ReadResource(tbuf,R_OGG_ERROR_18);
    CEikonEnv::Static()->ReadResource(buf,R_OGG_ERROR_16);
    buf.AppendNum(aErr);
    iEnv->OggErrorMsgL(tbuf,buf);
    if (iObserver )
    {
        if (!iEof ) 
            iObserver->NotifyPlayInterrupted();
    }
  }

  
}

void COggPlayback::MaoscBufferCopied(TInt aErr, const TDesC8& aBuffer)
{
  // Error codes:
  // KErrCancel      -3  (not sure when this happens, but ignore for now)
  // KErrUnderflow  -10  (ignore this, do as if nothing has happend, and live happily ever after)
  // KErrDied       -13  (interrupted by higher priority)
  // KErrInUse      -14  (the sound device was stolen from us)
  // KErrAbort      -39  (stream was stopped before this buffer was copied)

    
  if (aErr != KErrNone)
    { TRACEF(COggLog::VA(_L("MaoscBufferCopied:%d"), aErr )); }
  if (aErr == KErrCancel) aErr= KErrNone;

  if (aErr == KErrAbort ||
      aErr == KErrInUse ||
      aErr == KErrDied  ||
      aErr == KErrCancel) return;

  if (iState != EPlaying) return;

  TInt b;
  for (b=0; b<KBuffers; b++) if (&aBuffer == iBuffer[b]) break;
  if ( (iEof) && (iSent[iSentIdx] == &aBuffer) )
  {
      // All the buffers have been sent, stop the playback
      // We cannot rely on a MaoscPlayComplete from the CMdaAudioOutputStream
      // since not all phone supports that.
	  iUnderflowing = EFalse;

	  iRestartAudioStreamingTimer->Cancel();
      iStopAudioStreamingTimer->Wait(KStreamStopDelay);
	  return;
  }
  else if (aErr == KErrUnderflow)
  {
#ifdef DELAY_AUDIO_STREAMING_START
      if (!iUnderflowing)
      {
          iFirstUnderflowBuffer = b;
          iLastUnderflowBuffer = b;
          iUnderflowing = ETrue;
      }
      else
          iLastUnderflowBuffer = b;

	  iRestartAudioStreamingTimer->Wait(KStreamRestartDelay);
	  return;
#else
	  aErr = KErrNone;
#endif
  }

  if (aErr == KErrNone)
  {
	  if (iUnderflowing)
	  {
		  iRestartAudioStreamingTimer->Cancel();
		  RestartAudioStreamingCallBack(this);
	  }

	  SendBuffer(*iBuffer[b]); 
  }
  else {
    // An unknown error condition. This should never ever happen.
	TBuf<256> buf,tbuf;
    CEikonEnv::Static()->ReadResource(tbuf, R_OGG_ERROR_18);
    CEikonEnv::Static()->ReadResource(buf, R_OGG_ERROR_16);
    buf.AppendNum(aErr);
    iEnv->OggErrorMsgL(tbuf,buf);
  }
}

void COggPlayback::MaoscOpenComplete(TInt aErr) 
{ 
  if (aErr == KErrNone)
  {
    iState = EStreamOpen;

	iMaxVolume=iStream->MaxVolume();
    iStream->SetPriority(KAudioPriority, EMdaPriorityPreferenceTimeAndQuality);
  }

  iObserver->NotifyStreamOpen(aErr);
}

void COggPlayback::RestartAudioStreamingCallBack()
{
  iUnderflowing = EFalse;
  TInt firstUnderflowBuffer = iFirstUnderflowBuffer;
  TInt lastUnderflowBuffer = iLastUnderflowBuffer;
  TInt i;
  if (lastUnderflowBuffer>=firstUnderflowBuffer)
  {
	for (i = firstUnderflowBuffer ; i<=lastUnderflowBuffer ; i++)
		SendBuffer(*(iBuffer[i]));
  }
  else
  {
	for (i = firstUnderflowBuffer ; i<KBuffers ; i++)
		SendBuffer(*(iBuffer[i]));

	for (i = 0 ; i<=lastUnderflowBuffer ; i++)
		SendBuffer(*(iBuffer[i]));
  }
}

#endif
#endif /* !PLUGIN_SYSTEM */

⌨️ 快捷键说明

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