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

📄 oggmultithread.cpp

📁 OggPlay for Symbian 是symbian上的一个媒体播放程序的源码。它支持ogg,wav等等多媒体格式。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	}

	// Start the streaming thread AO
	if (iStreaming && !iStreamingThreadAO->IsActive() && (iSharedData.iBufferingMode != ENoBuffering))
	{
		// Reset the buffering thread priority
		if ((iBufferingThreadPriority != EPriorityNormal) && (iBufferingThreadPriority != EPriorityAbsoluteForeground))
		{
			iBufferingThreadPriority = (iBufferingThreadPriority == EPriorityMore) ? EPriorityNormal : EPriorityAbsoluteForeground;
			iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
		}

		iStreamingThreadAO->ResumeBuffering();
	}

	return ret;
}

void CStreamingThreadPlaybackEngine::Shutdown()
{
	// We can't shutdown if we are streaming, so panic
	if (iStreaming)
		User::Panic(_L("STPE: Shutdown"), 0);
}

// Send the next audio buffer to the stream
// iBufNum holds the index of the next buffer
void CStreamingThreadPlaybackEngine::SendNextBuffer()
{
	TRAPD(err, iStream->WriteL(*iSharedData.iOggPlayback.iBuffer[iBufNum]));
	if (err != KErrNone)
	{
		// If an error occurs notify the UI thread
		TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
		iSharedData.iUIThread.RequestComplete(status, err);
	}

	// Increment the number of stream buffers (we have one more now)
	iStreamBuffers++;

	// Move on to the next buffer
	iBufNum++;
	if (iBufNum == iSharedData.iMaxBuffers)
		iBufNum = 0;
}

void CStreamingThreadPlaybackEngine::MaoscOpenComplete(TInt aErr)
{ 
	TRACEF(COggLog::VA(_L("MaoscOpenComplete: %d"), aErr));
	if (aErr != KErrNone)
	{
		// Notify the UI thread
		TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
		iSharedData.iUIThread.RequestComplete(status, aErr);
		return;
	}

	// Determine the maximum volume
	iMaxVolume = iStream->MaxVolume();

	// Set our audio priority
	iStream->SetPriority(KAudioPriority, EMdaPriorityPreferenceTimeAndQuality);

	// Notify the UI thread
	TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
	iSharedData.iUIThread.RequestComplete(status, KErrNone);
}

// MaoscBufferCopied does all of the work to manage the buffering
void CStreamingThreadPlaybackEngine::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)

	// Debug trace, if error
	if (aErr != KErrNone)
		{ TRACEF(COggLog::VA(_L("MaoscBufferCopied:%d"), aErr)); }
		
	// Decrement the stream buffers (we have one less now)
	iStreamBuffers--;

	// Adjust the number of bytes we have in buffers
	iSharedData.iBufferBytesPlayed += aBuffer.Length();

	// Increment the total number of buffers played
	iSharedData.iNumBuffersPlayed++;

	// Ignore most of the error codes
	if ((aErr == KErrAbort) || (aErr == KErrInUse) || (aErr == KErrDied)  || (aErr == KErrCancel))
		return;

	if ((aErr != KErrNone) && (aErr != KErrUnderflow))
	{
		// Notify the UI thread (unknown error)
		TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
		if (status->Int() == KRequestPending)
			iSharedData.iUIThread.RequestComplete(status, aErr);

		return;
	}

	// If we have reached the last buffer, notify the UI thread
	if (iSharedData.iLastBuffer == &aBuffer)
	{
		// Notify the UI thread that we have copied the last buffer to the stream
		TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
		iSharedData.iUIThread.RequestComplete(status, ELastBufferCopied);
		return;
	}

	// Dynamically adjust the buffering thread priority
	TBool streamingThreadActive = iStreamingThreadAO->IsActive();
	if (iSharedData.iBufferingMode == EBufferThread)
	{
		TInt numBuffers = iSharedData.NumBuffers();
		if (numBuffers < KBufferThreadLowThreshold)
		{
			if ((iBufferingThreadPriority != EPriorityMore) && (iBufferingThreadPriority != EPriorityAbsoluteHigh))
			{
				if (!streamingThreadActive && !iSharedData.iLastBuffer)
				{
					iBufferingThreadPriority = (iBufferingThreadPriority == EPriorityNormal) ? EPriorityMore : EPriorityAbsoluteHigh;
					iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
				}
			}
		}
		else if (numBuffers > KBufferThreadHighThreshold)
		{
			if ((iBufferingThreadPriority != EPriorityNormal) && (iBufferingThreadPriority != EPriorityAbsoluteForeground))
			{
				iBufferingThreadPriority = (iBufferingThreadPriority == EPriorityMore) ? EPriorityNormal : EPriorityAbsoluteForeground;
				iSharedData.iBufferingThread.SetPriority(iBufferingThreadPriority);
			}
		}
	}
 
	// Ignore underflow if there are stream buffers left
	if ((aErr == KErrUnderflow) && iStreamBuffers)
		return;

	// Check if we have available buffers
	TInt availBuffers = iSharedData.NumBuffers() - iStreamBuffers;
	if (!availBuffers)
	{
		// If the streaming thread is doing the buffering, prime another buffer now 
		if ((streamingThreadActive || (iSharedData.iBufferingMode == ENoBuffering)) && (aErr != KErrUnderflow))
			iStreamingThreadAO->PrimeNextBuffer();
		else
		{
			// If we still have stream buffers, ignore the fact there are no buffers left
			if (iStreamBuffers)
				return;

			// Otherwise try to re-start playback
			TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
			iSharedData.iUIThread.RequestComplete(status, EPlayUnderflow);
			return;
		}
	}

	// Stream the next buffer
	SendNextBuffer();

	availBuffers = iSharedData.NumBuffers() - iStreamBuffers;
	if ((iStreamBuffers<iMaxStreamBuffers) && availBuffers)
	{
		// Try to catch up by writing another buffer
		SendNextBuffer();
	}

	// If the number of buffers has dropped below a certain threshold, request the buffering thread to start buffering
	if (iSharedData.NumBuffers()<iBufferLowThreshold) 
	{
		// Nothing to do if the streaming thread is already buffering
		// If a buffer flush is pending we don't want to start any more buffering
		if (streamingThreadActive || iBufferFlushPending)
		{
			if (streamingThreadActive)
			{
				// Deschedule the streaming thread for a little while (1ms)
				// This gives other threads a chance to run and really helps
				// on phones where the thread scheduling doesn't work properly
				#if !defined(__VC32__)
				User::After(1000);
				#endif
			}

			return;
		}

		switch (iSharedData.iBufferingMode)
		{
			case ENoBuffering:
				break;

			case EBufferStream:
				if (!iSharedData.iLastBuffer)
					iStreamingThreadAO->ResumeBuffering();
				break;

			case EBufferThread:
				{
					// Nothing to do if the buffering thread is already buffering
					if (iSharedData.iBufRequestInProgress)
						break;

					// Nothing to do if we have reached eof
					if (iSharedData.iLastBuffer)
						break;

					// Issue a buffering request
					iSharedData.iBufRequestInProgress = ETrue;
					TRequestStatus* status = &iSharedData.iBufferingThreadAO->iStatus;
					iSharedData.iBufferingThread.RequestComplete(status, KErrNone);
				}
				break;

			default:
				User::Panic(_L("STPE: MaoscBC"), 0);
				break;
		}
	}

	if (streamingThreadActive)
	{
		// Deschedule the streaming thread for a little while (1ms)
		// This gives other threads a chance to run and really helps
		// on phones where the thread scheduling doesn't work properly
		#if !defined(__VC32__)
		User::After(1000);
		#endif
	}
}

// Handle play complete
// There are five possibilities possibilities:
// 1. Playback is stopped by the user
// In this case there is nothing to do, the UI thread will handle everything

// 2. KErrUnderflow
// MaoscBufferCopied will have scheduled the restart timer, so we ignore KErrUnderflow

// 3. KErrDied
// I'm not sure what causes this, but we simply inform the UI thread
// The UI thread will make a number of attempts to restart playback
// (This behaviour is the same as OggPlay 1.07 and earlier)

// 4. KErrInUse
// This is caused when another application takes the sound device from us (real player does this)
// OggPlay will stop playback and display a message informing the user.
// OggPlay will attempt to restart playback when the user presses "back"

// 5. Unknown error
// This is handled in the same way as KErrInUse, except that the UI thread will display the error code
void CStreamingThreadPlaybackEngine::MaoscPlayComplete(TInt aErr)
{
	// Error codes:
	// KErrNone         0 (stopped by user)
	// KErrCancel      -3 (also stopped by user)
	// KErrUnderflow  -10 (ran out of audio, EOF or lack of cpu power)
	// KErrDied       -13 (interrupted by higher priority)
	// KErrInUse      -14 (the sound device was stolen from us)

	// Trace the reason for the play complete
	TRACEF(COggLog::VA(_L("MaoscPlayComplete:%d"), aErr));
  
	// Stopped by the user
	if ((aErr == KErrNone) || (aErr == KErrCancel))
		return;

	// Ignore underflow, underflow is handled by MaoscBufferCopied
	if (aErr == KErrUnderflow)
		return;

	// Expect KErrDied if interrupted
	if (aErr == KErrDied)
	{
		TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
		if (status->Int() == KRequestPending)
			iSharedData.iUIThread.RequestComplete(status, EPlayInterrupted);

		return;
	}

	// Unknown error (or KErrInUse)
	TRequestStatus* status = &iSharedData.iStreamingThreadListener->iStatus;
	if (status->Int() == KRequestPending)
		iSharedData.iUIThread.RequestComplete(status, aErr);
}


// Streaming thread listener AO
// This AO is owned by the COggPlayback object and runs in the UI thread
// It handles events from the audio stream (CMdaAudioOutputStream events from the streaming thread)
CStreamingThreadListener::CStreamingThreadListener(COggPlayback& aOggPlayback, TStreamingThreadData& aSharedData)
: CActive(EPriorityHigh), iOggPlayback(aOggPlayback), iSharedData(aSharedData), iListeningState(EListeningForOpenComplete)
{
	CActiveScheduler::Add(this);

	// Start listening
	iStatus = KRequestPending;
	SetActive();
}

CStreamingThreadListener::~CStreamingThreadListener()
{
}

void CStreamingThreadListener::RunL()
{
	// Get the status
	TInt status = iStatus.Int();

	// Start listening again
	iStatus = KRequestPending;
	SetActive();

	// Handle the message
	switch (iListeningState)
	{
	case EListeningForOpenComplete:
		iOggPlayback.NotifyOpenComplete(status);
		iListeningState = EListeningForStreamingStatus;
		break;

	case EListeningForStreamingStatus:
		iOggPlayback.NotifyStreamingStatus(status);
		break;
	}
}

void CStreamingThreadListener::DoCancel()
{
	// Stop listening
	TRequestStatus* status = &iStatus;
	User::RequestComplete(status, KErrCancel);
}

#endif /* MULTI_THREAD_PLAYBACK */

⌨️ 快捷键说明

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