xref: /haiku/src/kits/media/Buffer.cpp (revision 894526b51a3d931c423878fc0eb8da610fa1fb2a)
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 "debug.h"
41 #include "DataExchange.h"
42 #include "SharedBufferList.h"
43 
44 
45 using namespace BPrivate::media;
46 
47 
48 //	#pragma mark - buffer_clone_info
49 
50 
51 buffer_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 
62 buffer_clone_info::~buffer_clone_info()
63 {
64 	CALLED();
65 }
66 
67 
68 //	#pragma mark - public BBuffer
69 
70 
71 void*
72 BBuffer::Data()
73 {
74 	CALLED();
75 	return fData;
76 }
77 
78 
79 size_t
80 BBuffer::SizeAvailable()
81 {
82 	CALLED();
83 	return fSize;
84 }
85 
86 
87 size_t
88 BBuffer::SizeUsed()
89 {
90 	CALLED();
91 	return fMediaHeader.size_used;
92 }
93 
94 
95 void
96 BBuffer::SetSizeUsed(size_t size_used)
97 {
98 	CALLED();
99 	fMediaHeader.size_used = min_c(size_used, fSize);
100 }
101 
102 
103 uint32
104 BBuffer::Flags()
105 {
106 	CALLED();
107 	return fFlags;
108 }
109 
110 
111 void
112 BBuffer::Recycle()
113 {
114 	CALLED();
115 	if (fBufferList == NULL)
116 		return;
117 	fBufferList->RecycleBuffer(this);
118 }
119 
120 
121 buffer_clone_info
122 BBuffer::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 
137 media_buffer_id
138 BBuffer::ID()
139 {
140 	CALLED();
141 	return fMediaHeader.buffer;
142 }
143 
144 
145 media_type
146 BBuffer::Type()
147 {
148 	CALLED();
149 	return fMediaHeader.type;
150 }
151 
152 
153 media_header*
154 BBuffer::Header()
155 {
156 	CALLED();
157 	return &fMediaHeader;
158 }
159 
160 
161 media_audio_header*
162 BBuffer::AudioHeader()
163 {
164 	CALLED();
165 	return &fMediaHeader.u.raw_audio;
166 }
167 
168 
169 media_video_header*
170 BBuffer::VideoHeader()
171 {
172 	CALLED();
173 	return &fMediaHeader.u.raw_video;
174 }
175 
176 
177 size_t
178 BBuffer::Size()
179 {
180 	CALLED();
181 	return SizeAvailable();
182 }
183 
184 
185 // #pragma mark - private BBuffer
186 
187 
188 BBuffer::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 
262 BBuffer::~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 
284 void
285 BBuffer::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 
298 static const buffer_clone_info sSmallBufferInfo;
299 
300 
301 BSmallBuffer::BSmallBuffer()
302 	:
303 	BBuffer(sSmallBufferInfo)
304 {
305 	UNIMPLEMENTED();
306 	debugger("BSmallBuffer::BSmallBuffer called\n");
307 }
308 
309 
310 size_t
311 BSmallBuffer::SmallBufferSizeLimit()
312 {
313 	CALLED();
314 	return 64;
315 }
316 
317 
318