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