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