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
46 using namespace BPrivate::media;
47
48
49 // #pragma mark - buffer_clone_info
50
51
buffer_clone_info()52 buffer_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
~buffer_clone_info()63 buffer_clone_info::~buffer_clone_info()
64 {
65 CALLED();
66 }
67
68
69 // #pragma mark - public BBuffer
70
71
72 void*
Data()73 BBuffer::Data()
74 {
75 CALLED();
76 return fData;
77 }
78
79
80 size_t
SizeAvailable()81 BBuffer::SizeAvailable()
82 {
83 CALLED();
84 return fSize;
85 }
86
87
88 size_t
SizeUsed()89 BBuffer::SizeUsed()
90 {
91 CALLED();
92 return fMediaHeader.size_used;
93 }
94
95
96 void
SetSizeUsed(size_t size_used)97 BBuffer::SetSizeUsed(size_t size_used)
98 {
99 CALLED();
100 fMediaHeader.size_used = min_c(size_used, fSize);
101 }
102
103
104 uint32
Flags()105 BBuffer::Flags()
106 {
107 CALLED();
108 return fFlags;
109 }
110
111
112 void
Recycle()113 BBuffer::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
126 buffer_clone_info
CloneInfo() const127 BBuffer::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
142 media_buffer_id
ID()143 BBuffer::ID()
144 {
145 CALLED();
146 return fMediaHeader.buffer;
147 }
148
149
150 media_type
Type()151 BBuffer::Type()
152 {
153 CALLED();
154 return fMediaHeader.type;
155 }
156
157
158 media_header*
Header()159 BBuffer::Header()
160 {
161 CALLED();
162 return &fMediaHeader;
163 }
164
165
166 media_audio_header*
AudioHeader()167 BBuffer::AudioHeader()
168 {
169 CALLED();
170 return &fMediaHeader.u.raw_audio;
171 }
172
173
174 media_video_header*
VideoHeader()175 BBuffer::VideoHeader()
176 {
177 CALLED();
178 return &fMediaHeader.u.raw_video;
179 }
180
181
182 size_t
Size()183 BBuffer::Size()
184 {
185 CALLED();
186 return SizeAvailable();
187 }
188
189
190 // #pragma mark - private BBuffer
191
192
BBuffer(const buffer_clone_info & info)193 BBuffer::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
~BBuffer()267 BBuffer::~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
289 void
SetHeader(const media_header * header)290 BBuffer::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
303 static const buffer_clone_info sSmallBufferInfo;
304
305
BSmallBuffer()306 BSmallBuffer::BSmallBuffer()
307 :
308 BBuffer(sSmallBufferInfo)
309 {
310 UNIMPLEMENTED();
311 debugger("BSmallBuffer::BSmallBuffer called\n");
312 }
313
314
315 size_t
SmallBufferSizeLimit()316 BSmallBuffer::SmallBufferSizeLimit()
317 {
318 CALLED();
319 return 64;
320 }
321
322
323