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 "MediaMisc.h"
42#include "DataExchange.h"
43#include "SharedBufferList.h"
44
45
46using namespace BPrivate::media;
47
48
49//	#pragma mark - buffer_clone_info
50
51
52buffer_clone_info::buffer_clone_info()
53{
54	CALLED();
55	buffer = 0;
56	area = 0;
57	offset = 0;
58	size = 0;
59	flags = 0;
60}
61
62
63buffer_clone_info::~buffer_clone_info()
64{
65	CALLED();
66}
67
68
69//	#pragma mark - public BBuffer
70
71
72void*
73BBuffer::Data()
74{
75	CALLED();
76	return fData;
77}
78
79
80size_t
81BBuffer::SizeAvailable()
82{
83	CALLED();
84	return fSize;
85}
86
87
88size_t
89BBuffer::SizeUsed()
90{
91	CALLED();
92	return fMediaHeader.size_used;
93}
94
95
96void
97BBuffer::SetSizeUsed(size_t size_used)
98{
99	CALLED();
100	fMediaHeader.size_used = min_c(size_used, fSize);
101}
102
103
104uint32
105BBuffer::Flags()
106{
107	CALLED();
108	return fFlags;
109}
110
111
112void
113BBuffer::Recycle()
114{
115	CALLED();
116	if (fBufferList == NULL)
117		return;
118	fFlags &= ~BUFFER_TO_RECLAIM;
119	if ((fFlags & BUFFER_MARKED_FOR_DELETION) != 0)
120		delete this;
121	else
122		fBufferList->RecycleBuffer(this);
123}
124
125
126buffer_clone_info
127BBuffer::CloneInfo() const
128{
129	CALLED();
130	buffer_clone_info info;
131
132	info.buffer = fMediaHeader.buffer;
133	info.area = fArea;
134	info.offset = fOffset;
135	info.size = fSize;
136	info.flags = fFlags;
137
138	return info;
139}
140
141
142media_buffer_id
143BBuffer::ID()
144{
145	CALLED();
146	return fMediaHeader.buffer;
147}
148
149
150media_type
151BBuffer::Type()
152{
153	CALLED();
154	return fMediaHeader.type;
155}
156
157
158media_header*
159BBuffer::Header()
160{
161	CALLED();
162	return &fMediaHeader;
163}
164
165
166media_audio_header*
167BBuffer::AudioHeader()
168{
169	CALLED();
170	return &fMediaHeader.u.raw_audio;
171}
172
173
174media_video_header*
175BBuffer::VideoHeader()
176{
177	CALLED();
178	return &fMediaHeader.u.raw_video;
179}
180
181
182size_t
183BBuffer::Size()
184{
185	CALLED();
186	return SizeAvailable();
187}
188
189
190// #pragma mark - private BBuffer
191
192
193BBuffer::BBuffer(const buffer_clone_info& info)
194	:
195	fBufferList(NULL),
196	fArea(-1),
197	fData(NULL),
198	fOffset(0),
199	fSize(0),
200	fFlags(0)
201{
202	CALLED();
203
204	// Ensure that the media_header is clean
205	memset(&fMediaHeader, 0, sizeof(fMediaHeader));
206	// special case for BSmallBuffer
207	if (info.area == 0 && info.buffer == 0)
208		return;
209
210	// Must be -1 if registration fail
211	fMediaHeader.buffer = -1;
212
213	fBufferList = BPrivate::SharedBufferList::Get();
214	if (fBufferList == NULL) {
215		ERROR("BBuffer::BBuffer: BPrivate::SharedBufferList::Get() failed\n");
216		return;
217	}
218
219	server_register_buffer_request request;
220	server_register_buffer_reply reply;
221
222	request.team = BPrivate::current_team();
223	request.info = info;
224
225	// ask media_server to register this buffer,
226	// either identified by "buffer" or by area information.
227	// media_server either has a copy of the area identified
228	// by "buffer", or creates a new area.
229	// the information and the area is cached by the media_server
230	// until the last buffer has been unregistered
231	// the area_id of the cached area is passed back to us, and we clone it.
232
233	if (QueryServer(SERVER_REGISTER_BUFFER, &request, sizeof(request), &reply,
234			sizeof(reply)) != B_OK) {
235		ERROR("BBuffer::BBuffer: failed to register buffer with "
236			"media_server\n");
237		return;
238	}
239
240	ASSERT(reply.info.buffer > 0);
241	ASSERT(reply.info.area > 0);
242	ASSERT(reply.info.size > 0);
243
244	fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,
245		B_READ_AREA | B_WRITE_AREA, reply.info.area);
246	if (fArea < 0) {
247		ERROR("BBuffer::BBuffer: buffer cloning failed"
248			", unregistering buffer\n");
249		server_unregister_buffer_command cmd;
250		cmd.team = BPrivate::current_team();
251		cmd.buffer_id = reply.info.buffer;
252		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
253		return;
254	}
255
256	// the response from media server contains enough information
257	// to clone the memory for this buffer
258	fSize = reply.info.size;
259	fFlags = reply.info.flags;
260	fOffset = reply.info.offset;
261	fMediaHeader.size_used = 0;
262	fMediaHeader.buffer = reply.info.buffer;
263	fData = (char*)fData + fOffset;
264}
265
266
267BBuffer::~BBuffer()
268{
269	CALLED();
270
271	// unmap the BufferList
272	if (fBufferList != NULL)
273		fBufferList->Put();
274
275	// unmap the Data
276	if (fData != NULL) {
277		delete_area(fArea);
278
279		// Ask media_server to unregister the buffer when the last clone of
280		// this buffer is gone, media_server will also remove its cached area.
281		server_unregister_buffer_command cmd;
282		cmd.team = BPrivate::current_team();
283		cmd.buffer_id = fMediaHeader.buffer;
284		SendToServer(SERVER_UNREGISTER_BUFFER, &cmd, sizeof(cmd));
285	}
286}
287
288
289void
290BBuffer::SetHeader(const media_header* header)
291{
292	CALLED();
293	ASSERT(header->buffer == fMediaHeader.buffer);
294	if (header->buffer != fMediaHeader.buffer)
295		debugger("oops");
296	fMediaHeader = *header;
297}
298
299
300// #pragma mark - public BSmallBuffer
301
302
303static const buffer_clone_info sSmallBufferInfo;
304
305
306BSmallBuffer::BSmallBuffer()
307	:
308	BBuffer(sSmallBufferInfo)
309{
310	UNIMPLEMENTED();
311	debugger("BSmallBuffer::BSmallBuffer called\n");
312}
313
314
315size_t
316BSmallBuffer::SmallBufferSizeLimit()
317{
318	CALLED();
319	return 64;
320}
321
322
323