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