1/*
2 * Copyright 2009, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6/*
7 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files or portions
11 * thereof (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so, subject
15 * to the following conditions:
16 *
17 *  * Redistributions of source code must retain the above copyright notice,
18 *    this list of conditions and the following disclaimer.
19 *
20 *  * Redistributions in binary form must reproduce the above copyright notice
21 *    in the  binary, as well as this list of conditions and the following
22 *    disclaimer in the documentation and/or other materials provided with
23 *    the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 * THE SOFTWARE.
32 */
33
34
35#include <Buffer.h>
36
37#include <AppMisc.h>
38#include <MediaDefs.h>
39
40#include "MediaDebug.h"
41#include "DataExchange.h"
42#include "SharedBufferList.h"
43
44
45using namespace BPrivate::media;
46
47
48//	#pragma mark - buffer_clone_info
49
50
51buffer_clone_info::buffer_clone_info()
52{
53	CALLED();
54	buffer = 0;
55	area = 0;
56	offset = 0;
57	size = 0;
58	flags = 0;
59}
60
61
62buffer_clone_info::~buffer_clone_info()
63{
64	CALLED();
65}
66
67
68//	#pragma mark - public BBuffer
69
70
71void*
72BBuffer::Data()
73{
74	CALLED();
75	return fData;
76}
77
78
79size_t
80BBuffer::SizeAvailable()
81{
82	CALLED();
83	return fSize;
84}
85
86
87size_t
88BBuffer::SizeUsed()
89{
90	CALLED();
91	return fMediaHeader.size_used;
92}
93
94
95void
96BBuffer::SetSizeUsed(size_t size_used)
97{
98	CALLED();
99	fMediaHeader.size_used = min_c(size_used, fSize);
100}
101
102
103uint32
104BBuffer::Flags()
105{
106	CALLED();
107	return fFlags;
108}
109
110
111void
112BBuffer::Recycle()
113{
114	CALLED();
115	if (fBufferList == NULL)
116		return;
117	fBufferList->RecycleBuffer(this);
118}
119
120
121buffer_clone_info
122BBuffer::CloneInfo() const
123{
124	CALLED();
125	buffer_clone_info info;
126
127	info.buffer = fMediaHeader.buffer;
128	info.area = fArea;
129	info.offset = fOffset;
130	info.size = fSize;
131	info.flags = fFlags;
132
133	return info;
134}
135
136
137media_buffer_id
138BBuffer::ID()
139{
140	CALLED();
141	return fMediaHeader.buffer;
142}
143
144
145media_type
146BBuffer::Type()
147{
148	CALLED();
149	return fMediaHeader.type;
150}
151
152
153media_header*
154BBuffer::Header()
155{
156	CALLED();
157	return &fMediaHeader;
158}
159
160
161media_audio_header*
162BBuffer::AudioHeader()
163{
164	CALLED();
165	return &fMediaHeader.u.raw_audio;
166}
167
168
169media_video_header*
170BBuffer::VideoHeader()
171{
172	CALLED();
173	return &fMediaHeader.u.raw_video;
174}
175
176
177size_t
178BBuffer::Size()
179{
180	CALLED();
181	return SizeAvailable();
182}
183
184
185// #pragma mark - private BBuffer
186
187
188BBuffer::BBuffer(const buffer_clone_info& info)
189	:
190	fBufferList(NULL),
191	fArea(-1),
192	fData(NULL),
193	fOffset(0),
194	fSize(0),
195	fFlags(0)
196{
197	CALLED();
198
199	// Ensure that the media_header is clean
200	memset(&fMediaHeader, 0, sizeof(fMediaHeader));
201	// special case for BSmallBuffer
202	if (info.area == 0 && info.buffer == 0)
203		return;
204
205	// Must be -1 if registration fail
206	fMediaHeader.buffer = -1;
207
208	fBufferList = BPrivate::SharedBufferList::Get();
209	if (fBufferList == NULL) {
210		ERROR("BBuffer::BBuffer: BPrivate::SharedBufferList::Get() failed\n");
211		return;
212	}
213
214	server_register_buffer_request request;
215	server_register_buffer_reply reply;
216
217	request.team = BPrivate::current_team();
218	request.info = info;
219
220	// ask media_server to register this buffer,
221	// either identified by "buffer" or by area information.
222	// media_server either has a copy of the area identified
223	// by "buffer", or creates a new area.
224	// the information and the area is cached by the media_server
225	// until the last buffer has been unregistered
226	// the area_id of the cached area is passed back to us, and we clone it.
227
228	if (QueryServer(SERVER_REGISTER_BUFFER, &request, sizeof(request), &reply,
229			sizeof(reply)) != B_OK) {
230		ERROR("BBuffer::BBuffer: failed to register buffer with "
231			"media_server\n");
232		return;
233	}
234
235	ASSERT(reply.info.buffer > 0);
236	ASSERT(reply.info.area > 0);
237	ASSERT(reply.info.size > 0);
238
239	fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,
240		B_READ_AREA | B_WRITE_AREA, reply.info.area);
241	if (fArea < 0) {
242		ERROR("BBuffer::BBuffer: buffer cloning failed"
243			", unregistering buffer\n");
244		server_unregister_buffer_command cmd;
245		cmd.team = BPrivate::current_team();
246		cmd.buffer_id = reply.info.buffer;
247		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
248		return;
249	}
250
251	// the response from media server contains enough information
252	// to clone the memory for this buffer
253	fSize = reply.info.size;
254	fFlags = reply.info.flags;
255	fOffset = reply.info.offset;
256	fMediaHeader.size_used = 0;
257	fMediaHeader.buffer = reply.info.buffer;
258	fData = (char*)fData + fOffset;
259}
260
261
262BBuffer::~BBuffer()
263{
264	CALLED();
265
266	// unmap the BufferList
267	if (fBufferList != NULL)
268		fBufferList->Put();
269
270	// unmap the Data
271	if (fData != NULL) {
272		delete_area(fArea);
273
274		// Ask media_server to unregister the buffer when the last clone of
275		// this buffer is gone, media_server will also remove its cached area.
276		server_unregister_buffer_command cmd;
277		cmd.team = BPrivate::current_team();
278		cmd.buffer_id = fMediaHeader.buffer;
279		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
280	}
281}
282
283
284void
285BBuffer::SetHeader(const media_header* header)
286{
287	CALLED();
288	ASSERT(header->buffer == fMediaHeader.buffer);
289	if (header->buffer != fMediaHeader.buffer)
290		debugger("oops");
291	fMediaHeader = *header;
292}
293
294
295// #pragma mark - public BSmallBuffer
296
297
298static const buffer_clone_info sSmallBufferInfo;
299
300
301BSmallBuffer::BSmallBuffer()
302	:
303	BBuffer(sSmallBufferInfo)
304{
305	UNIMPLEMENTED();
306	debugger("BSmallBuffer::BSmallBuffer called\n");
307}
308
309
310size_t
311BSmallBuffer::SmallBufferSizeLimit()
312{
313	CALLED();
314	return 64;
315}
316
317
318