/*
 * Copyright 2001-2012 Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Christopher ML Zumwalt May (zummy@users.sf.net)
 *		Jérôme Duval
 */
 
 
#include <PushGameSound.h>
 
#include <List.h>
#include <string.h>
 
#include "GSUtility.h"
 
 
BPushGameSound::BPushGameSound(size_t inBufferFrameCount,
	const gs_audio_format *format, size_t inBufferCount,
	BGameSoundDevice *device)
	:
	BStreamingGameSound(inBufferFrameCount, format, inBufferCount, device),
	fLockPos(0),
	fPlayPos(0)
{
	fPageLocked = new BList;
 
	size_t frameSize = get_sample_size(format->format) * format->channel_count;
 
	fPageCount = inBufferCount;
	fPageSize = frameSize * inBufferFrameCount;
	fBufferSize = fPageSize * fPageCount;
 
	fBuffer = new char[fBufferSize];
}
 
 
BPushGameSound::BPushGameSound(BGameSoundDevice * device)
		:	BStreamingGameSound(device),
			fLockPos(0),
			fPlayPos(0),
			fBuffer(NULL),
			fPageSize(0),
			fPageCount(0),
			fBufferSize(0)
{
	fPageLocked = new BList;
}
 
 
BPushGameSound::~BPushGameSound()
{
	delete [] fBuffer;
	delete fPageLocked;
}
 
 
BPushGameSound::lock_status
BPushGameSound::LockNextPage(void **out_pagePtr, size_t *out_pageSize)
{
	// the user can not lock every page
	if (fPageLocked->CountItems() > fPageCount - 1)
		return lock_failed;
 
	// the user can't lock a page being played
	if (fLockPos < fPlayPos
		&& fLockPos + fPageSize > fPlayPos)
		return lock_failed;
 
	// lock the page
	char * lockPage = &fBuffer[fLockPos];
	fPageLocked->AddItem(lockPage);
 
	// move the locker to the next page
	fLockPos += fPageSize;
	if (fLockPos >= fBufferSize)
		fLockPos = 0;
 
	*out_pagePtr = lockPage;
	*out_pageSize = fPageSize;
 
	return lock_ok;
}
 
 
status_t
BPushGameSound::UnlockPage(void *in_pagePtr)
{
	return (fPageLocked->RemoveItem(in_pagePtr)) ? B_OK : B_ERROR;
}
 
 
BPushGameSound::lock_status
BPushGameSound::LockForCyclic(void **out_basePtr, size_t *out_size)
{
	*out_basePtr = fBuffer;
	*out_size = fBufferSize;
	return lock_ok;
}
 
 
status_t
BPushGameSound::UnlockCyclic()
{
	return B_OK;
}
 
 
size_t
BPushGameSound::CurrentPosition()
{
	return fPlayPos;
}
 
 
BGameSound *
BPushGameSound::Clone() const
{
	gs_audio_format format = Format();
	size_t frameSize = get_sample_size(format.format) * format.channel_count;
	size_t bufferFrameCount = fPageSize / frameSize;
 
	return new BPushGameSound(bufferFrameCount, &format, fPageCount, Device());
}
 
 
status_t
BPushGameSound::Perform(int32 selector, void *data)
{
	return BStreamingGameSound::Perform(selector, data);
}
 
 
status_t
BPushGameSound::SetParameters(size_t inBufferFrameCount,
	const gs_audio_format *format, size_t inBufferCount)
{
	return B_UNSUPPORTED;
}
 
 
status_t
BPushGameSound::SetStreamHook(void (*hook)(void * inCookie, void * inBuffer,
	size_t inByteCount, BStreamingGameSound * me), void * cookie)
{
	return B_UNSUPPORTED;
}
 
 
void
BPushGameSound::FillBuffer(void *inBuffer, size_t inByteCount)
{
	size_t bytes = inByteCount;
 
	if (!BytesReady(&bytes))
		return;
 
	if (fPlayPos + bytes > fBufferSize) {
		size_t remainder = fBufferSize - fPlayPos;
			// Space left in buffer
		char * buffer = (char*)inBuffer;
 
		// fill the buffer with the samples left at the end of our buffer
		memcpy(buffer, &fBuffer[fPlayPos], remainder);
		fPlayPos = 0;
 
		// fill the remainder of the buffer by looping to the start
		// of the buffer if it isn't locked
		bytes -= remainder;
		if (BytesReady(&bytes)) {
			memcpy(&buffer[remainder], fBuffer, bytes);
			fPlayPos += bytes;
		}
	} else {
		memcpy(inBuffer, &fBuffer[fPlayPos], bytes);
		fPlayPos += bytes;
	}
 
	BStreamingGameSound::FillBuffer(inBuffer, inByteCount);
}
 
 
bool
BPushGameSound::BytesReady(size_t * bytes)
{
	if (fPageLocked->CountItems() <= 0)
		return true;
 
	size_t start = fPlayPos;
	size_t ready = fPlayPos;
	int32 page = int32(start / fPageSize);
 
	// return if there is nothing to do
	if (fPageLocked->HasItem(&fBuffer[page * fPageSize]))
		return false;
 
	while (ready < *bytes) {
		ready += fPageSize;
		page = int32(ready / fPageSize);
 
		if (fPageLocked->HasItem(&fBuffer[page * fPageSize])) {
			// we have found a locked page
			*bytes = ready - start - (ready - page * fPageSize);
			return true;
		}
	}
 
	// all of the bytes are ready
	return true;
}
 
 
/* unimplemented for protection of the user:
 *
 * BPushGameSound::BPushGameSound()
 * BPushGameSound::BPushGameSound(const BPushGameSound &)
 * BPushGameSound &BPushGameSound::operator=(const BPushGameSound &)
 */
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_0(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_1(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_2(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_3(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_4(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_5(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_6(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_7(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_8(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_9(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_10(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_11(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_12(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_13(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_14(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_15(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_16(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_17(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_18(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_19(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_20(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_21(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_22(int32 arg, ...)
{
	return B_ERROR;
}
 
 
status_t
BPushGameSound::_Reserved_BPushGameSound_23(int32 arg, ...)
{
	return B_ERROR;
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fLock, _reserved.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fLock, _reserved.