⛏️ index : haiku.git

/*
 * Copyright 2009, Axel DΓΆrfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */

/*
 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files or portions
 * thereof (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 *  * 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
 *    in the  binary, as well as this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided with
 *    the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <Buffer.h>

#include <AppMisc.h>
#include <MediaDefs.h>

#include "MediaDebug.h"
#include "MediaMisc.h"
#include "DataExchange.h"
#include "SharedBufferList.h"


using namespace BPrivate::media;


//	#pragma mark - buffer_clone_info


buffer_clone_info::buffer_clone_info()
{
	CALLED();
	buffer = 0;
	area = 0;
	offset = 0;
	size = 0;
	flags = 0;
}


buffer_clone_info::~buffer_clone_info()
{
	CALLED();
}


//	#pragma mark - public BBuffer


void*
BBuffer::Data()
{
	CALLED();
	return fData;
}


size_t
BBuffer::SizeAvailable()
{
	CALLED();
	return fSize;
}


size_t
BBuffer::SizeUsed()
{
	CALLED();
	return fMediaHeader.size_used;
}


void
BBuffer::SetSizeUsed(size_t size_used)
{
	CALLED();
	fMediaHeader.size_used = min_c(size_used, fSize);
}


uint32
BBuffer::Flags()
{
	CALLED();
	return fFlags;
}


void
BBuffer::Recycle()
{
	CALLED();
	if (fBufferList == NULL)
		return;
	fFlags &= ~BUFFER_TO_RECLAIM;
	if ((fFlags & BUFFER_MARKED_FOR_DELETION) != 0)
		delete this;
	else
		fBufferList->RecycleBuffer(this);
}


buffer_clone_info
BBuffer::CloneInfo() const
{
	CALLED();
	buffer_clone_info info;

	info.buffer = fMediaHeader.buffer;
	info.area = fArea;
	info.offset = fOffset;
	info.size = fSize;
	info.flags = fFlags;

	return info;
}


media_buffer_id
BBuffer::ID()
{
	CALLED();
	return fMediaHeader.buffer;
}


media_type
BBuffer::Type()
{
	CALLED();
	return fMediaHeader.type;
}


media_header*
BBuffer::Header()
{
	CALLED();
	return &fMediaHeader;
}


media_audio_header*
BBuffer::AudioHeader()
{
	CALLED();
	return &fMediaHeader.u.raw_audio;
}


media_video_header*
BBuffer::VideoHeader()
{
	CALLED();
	return &fMediaHeader.u.raw_video;
}


size_t
BBuffer::Size()
{
	CALLED();
	return SizeAvailable();
}


// #pragma mark - private BBuffer


BBuffer::BBuffer(const buffer_clone_info& info)
	:
	fBufferList(NULL),
	fArea(-1),
	fData(NULL),
	fOffset(0),
	fSize(0),
	fFlags(0)
{
	CALLED();

	// Ensure that the media_header is clean
	memset(&fMediaHeader, 0, sizeof(fMediaHeader));
	// special case for BSmallBuffer
	if (info.area == 0 && info.buffer == 0)
		return;

	// Must be -1 if registration fail
	fMediaHeader.buffer = -1;

	fBufferList = BPrivate::SharedBufferList::Get();
	if (fBufferList == NULL) {
		ERROR("BBuffer::BBuffer: BPrivate::SharedBufferList::Get() failed\n");
		return;
	}

	server_register_buffer_request request;
	server_register_buffer_reply reply;

	request.team = BPrivate::current_team();
	request.info = info;

	// ask media_server to register this buffer,
	// either identified by "buffer" or by area information.
	// media_server either has a copy of the area identified
	// by "buffer", or creates a new area.
	// the information and the area is cached by the media_server
	// until the last buffer has been unregistered
	// the area_id of the cached area is passed back to us, and we clone it.

	if (QueryServer(SERVER_REGISTER_BUFFER, &request, sizeof(request), &reply,
			sizeof(reply)) != B_OK) {
		ERROR("BBuffer::BBuffer: failed to register buffer with "
			"media_server\n");
		return;
	}

	ASSERT(reply.info.buffer > 0);
	ASSERT(reply.info.area > 0);
	ASSERT(reply.info.size > 0);

	fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,
		B_READ_AREA | B_WRITE_AREA, reply.info.area);
	if (fArea < 0) {
		ERROR("BBuffer::BBuffer: buffer cloning failed"
			", unregistering buffer\n");
		server_unregister_buffer_command cmd;
		cmd.team = BPrivate::current_team();
		cmd.buffer_id = reply.info.buffer;
		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
		return;
	}

	// the response from media server contains enough information
	// to clone the memory for this buffer
	fSize = reply.info.size;
	fFlags = reply.info.flags;
	fOffset = reply.info.offset;
	fMediaHeader.size_used = 0;
	fMediaHeader.buffer = reply.info.buffer;
	fData = (char*)fData + fOffset;
}


BBuffer::~BBuffer()
{
	CALLED();

	// unmap the BufferList
	if (fBufferList != NULL)
		fBufferList->Put();

	// unmap the Data
	if (fData != NULL) {
		delete_area(fArea);

		// Ask media_server to unregister the buffer when the last clone of
		// this buffer is gone, media_server will also remove its cached area.
		server_unregister_buffer_command cmd;
		cmd.team = BPrivate::current_team();
		cmd.buffer_id = fMediaHeader.buffer;
		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
	}
}


void
BBuffer::SetHeader(const media_header* header)
{
	CALLED();
	ASSERT(header->buffer == fMediaHeader.buffer);
	if (header->buffer != fMediaHeader.buffer)
		debugger("oops");
	fMediaHeader = *header;
}


// #pragma mark - public BSmallBuffer


static const buffer_clone_info sSmallBufferInfo;


BSmallBuffer::BSmallBuffer()
	:
	BBuffer(sSmallBufferInfo)
{
	UNIMPLEMENTED();
	debugger("BSmallBuffer::BSmallBuffer called\n");
}


size_t
BSmallBuffer::SmallBufferSizeLimit()
{
	CALLED();
	return 64;
}