1 /* 2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files or portions 6 * thereof (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, merge, 8 * publish, distribute, sublicense, and/or sell copies of the Software, 9 * and to permit persons to whom the Software is furnished to do so, subject 10 * to the following conditions: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * * Redistributions in binary form must reproduce the above copyright notice 16 * in the binary, as well as this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided with 18 * the distribution. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 */ 28 29 30 #include "BufferCache.h" 31 #include <BufferConsumer.h> 32 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include <AutoDeleter.h> 37 #include <BufferProducer.h> 38 #include <BufferGroup.h> 39 #include <Buffer.h> 40 #include <TimeSource.h> 41 42 #include <debug.h> 43 #include <MediaMisc.h> 44 #include <DataExchange.h> 45 46 47 48 BBufferConsumer::~BBufferConsumer() 49 { 50 CALLED(); 51 delete fBufferCache; 52 delete fDeleteBufferGroup; 53 } 54 55 56 // #pragma mark - public BBufferConsumer 57 58 59 media_type 60 BBufferConsumer::ConsumerType() 61 { 62 CALLED(); 63 return fConsumerType; 64 } 65 66 67 /*static*/ status_t 68 BBufferConsumer::RegionToClipData(const BRegion* region, int32* _format, 69 int32 *_size, void* data) 70 { 71 CALLED(); 72 73 int count = *_size / sizeof(int16); 74 status_t status = BBufferProducer::clip_region_to_shorts(region, 75 static_cast<int16 *>(data), count, &count); 76 77 *_size = count * sizeof(int16); 78 *_format = BBufferProducer::B_CLIP_SHORT_RUNS; 79 80 return status; 81 } 82 83 84 // #pragma mark - protected BBufferConsumer 85 86 87 BBufferConsumer::BBufferConsumer(media_type consumerType) 88 : 89 BMediaNode("called by BBufferConsumer"), 90 fConsumerType(consumerType), 91 fBufferCache(new BPrivate::BufferCache), 92 fDeleteBufferGroup(0) 93 { 94 CALLED(); 95 96 AddNodeKind(B_BUFFER_CONSUMER); 97 } 98 99 100 /*static*/ void 101 BBufferConsumer::NotifyLateProducer(const media_source& whatSource, 102 bigtime_t howMuch, bigtime_t performanceTime) 103 { 104 CALLED(); 105 if (IS_INVALID_SOURCE(whatSource)) 106 return; 107 108 producer_late_notice_received_command command; 109 command.source = whatSource; 110 command.how_much = howMuch; 111 command.performance_time = performanceTime; 112 113 SendToPort(whatSource.port, PRODUCER_LATE_NOTICE_RECEIVED, &command, 114 sizeof(command)); 115 } 116 117 118 status_t 119 BBufferConsumer::SetVideoClippingFor(const media_source& output, 120 const media_destination& destination, const int16* shorts, int32 shortCount, 121 const media_video_display_info& display, void* userData, int32* _changeTag, 122 void *_reserved_) 123 { 124 CALLED(); 125 if (IS_INVALID_SOURCE(output)) 126 return B_MEDIA_BAD_SOURCE; 127 if (IS_INVALID_DESTINATION(destination)) 128 return B_MEDIA_BAD_DESTINATION; 129 if (shortCount > int(B_MEDIA_MESSAGE_SIZE 130 - sizeof(producer_video_clipping_changed_command)) / 2) { 131 debugger("BBufferConsumer::SetVideoClippingFor short_count too large " 132 "(8000 limit)\n"); 133 } 134 135 producer_video_clipping_changed_command* command; 136 size_t size = sizeof(producer_video_clipping_changed_command) 137 + shortCount * sizeof(short); 138 command 139 = static_cast<producer_video_clipping_changed_command*>(malloc(size)); 140 if (command == NULL) 141 return B_NO_MEMORY; 142 143 command->source = output; 144 command->destination = destination; 145 command->display = display; 146 command->user_data = userData; 147 command->change_tag = NewChangeTag(); 148 command->short_count = shortCount; 149 memcpy(command->shorts, shorts, shortCount * sizeof(short)); 150 if (_changeTag != NULL) 151 *_changeTag = command->change_tag; 152 153 status_t status = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, 154 command, size); 155 156 free(command); 157 return status; 158 } 159 160 161 status_t 162 BBufferConsumer::SetOutputEnabled(const media_source &source, 163 const media_destination &destination, 164 bool enabled, 165 void *user_data, 166 int32 *change_tag, 167 void *_reserved_) 168 { 169 CALLED(); 170 if (IS_INVALID_SOURCE(source)) 171 return B_MEDIA_BAD_SOURCE; 172 if (IS_INVALID_DESTINATION(destination)) 173 return B_MEDIA_BAD_DESTINATION; 174 175 producer_enable_output_command command; 176 177 command.source = source; 178 command.destination = destination; 179 command.enabled = enabled; 180 command.user_data = user_data; 181 command.change_tag = NewChangeTag(); 182 if (change_tag != NULL) 183 *change_tag = command.change_tag; 184 185 return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command)); 186 } 187 188 189 status_t 190 BBufferConsumer::RequestFormatChange(const media_source &source, 191 const media_destination &destination, 192 const media_format &to_format, 193 void *user_data, 194 int32 *change_tag, 195 void *_reserved_) 196 { 197 CALLED(); 198 if (IS_INVALID_SOURCE(source)) 199 return B_MEDIA_BAD_SOURCE; 200 if (IS_INVALID_DESTINATION(destination)) 201 return B_MEDIA_BAD_DESTINATION; 202 203 producer_format_change_requested_command command; 204 205 command.source = source; 206 command.destination = destination; 207 command.format = to_format; 208 command.user_data = user_data; 209 command.change_tag = NewChangeTag(); 210 if (change_tag != NULL) 211 *change_tag = command.change_tag; 212 213 return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command)); 214 } 215 216 217 status_t 218 BBufferConsumer::RequestAdditionalBuffer(const media_source &source, 219 BBuffer *prev_buffer, 220 void *_reserved) 221 { 222 CALLED(); 223 if (IS_INVALID_SOURCE(source)) 224 return B_MEDIA_BAD_SOURCE; 225 226 producer_additional_buffer_requested_command command; 227 228 command.source = source; 229 command.prev_buffer = prev_buffer->ID(); 230 command.prev_time = 0; 231 command.has_seek_tag = false; 232 //command.prev_tag = 233 234 return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command)); 235 } 236 237 238 status_t 239 BBufferConsumer::RequestAdditionalBuffer(const media_source& source, 240 bigtime_t startTime, void *_reserved) 241 { 242 CALLED(); 243 if (IS_INVALID_SOURCE(source)) 244 return B_MEDIA_BAD_SOURCE; 245 246 producer_additional_buffer_requested_command command; 247 248 command.source = source; 249 command.prev_buffer = 0; 250 command.prev_time = startTime; 251 command.has_seek_tag = false; 252 253 return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, 254 &command, sizeof(command)); 255 } 256 257 258 status_t 259 BBufferConsumer::SetOutputBuffersFor(const media_source &source, 260 const media_destination &destination, BBufferGroup *group, void *user_data, 261 int32 *change_tag, bool will_reclaim, void *_reserved_) 262 { 263 CALLED(); 264 265 if (IS_INVALID_SOURCE(source)) 266 return B_MEDIA_BAD_SOURCE; 267 if (IS_INVALID_DESTINATION(destination)) 268 return B_MEDIA_BAD_DESTINATION; 269 270 int32 buffer_count = 0; 271 272 if (group > 0) { 273 if (group->CountBuffers(&buffer_count) != B_OK) 274 return B_ERROR; 275 } 276 277 size_t size = sizeof(producer_set_buffer_group_command) 278 + buffer_count * sizeof(media_buffer_id); 279 280 producer_set_buffer_group_command *command 281 = static_cast<producer_set_buffer_group_command *>(malloc(size)); 282 MemoryDeleter deleter(command); 283 284 command->source = source; 285 command->destination = destination; 286 command->user_data = user_data; 287 command->change_tag = NewChangeTag(); 288 289 BBuffer *buffers[buffer_count]; 290 if (buffer_count != 0) { 291 if (group->GetBufferList(buffer_count, buffers) != B_OK) 292 return B_ERROR; 293 for (int32 i = 0; i < buffer_count; i++) 294 command->buffers[i] = buffers[i]->ID(); 295 } 296 297 command->buffer_count = buffer_count; 298 299 if (change_tag != NULL) 300 *change_tag = command->change_tag; 301 302 status_t status = SendToPort(source.port, PRODUCER_SET_BUFFER_GROUP, 303 command, size); 304 305 if (status == B_OK) { 306 // XXX will leak memory if port write failed 307 delete fDeleteBufferGroup; 308 fDeleteBufferGroup = will_reclaim ? NULL : group; 309 } 310 return status; 311 } 312 313 314 status_t 315 BBufferConsumer::SendLatencyChange(const media_source& source, 316 const media_destination& destination, bigtime_t newLatency, uint32 flags) 317 { 318 CALLED(); 319 if (IS_INVALID_SOURCE(source)) 320 return B_MEDIA_BAD_SOURCE; 321 if (IS_INVALID_DESTINATION(destination)) 322 return B_MEDIA_BAD_DESTINATION; 323 324 producer_latency_changed_command command; 325 326 command.source = source; 327 command.destination = destination; 328 command.latency = newLatency; 329 command.flags = flags; 330 331 TRACE("###### BBufferConsumer::SendLatencyChange: latency from %ld/%ld to " 332 "%ld/%ld changed to %Ld\n", source.port, source.id, destination.port, 333 destination.id, newLatency); 334 335 return SendToPort(source.port, PRODUCER_LATENCY_CHANGED, &command, 336 sizeof(command)); 337 } 338 339 340 status_t 341 BBufferConsumer::HandleMessage(int32 message, const void* data, size_t size) 342 { 343 PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message, ID()); 344 status_t rv; 345 switch (message) { 346 case CONSUMER_ACCEPT_FORMAT: 347 { 348 const consumer_accept_format_request* request 349 = static_cast<const consumer_accept_format_request*>(data); 350 351 consumer_accept_format_reply reply; 352 reply.format = request->format; 353 status_t status = AcceptFormat(request->dest, &reply.format); 354 request->SendReply(status, &reply, sizeof(reply)); 355 return B_OK; 356 } 357 358 case CONSUMER_GET_NEXT_INPUT: 359 { 360 const consumer_get_next_input_request *request = static_cast<const consumer_get_next_input_request *>(data); 361 consumer_get_next_input_reply reply; 362 reply.cookie = request->cookie; 363 rv = GetNextInput(&reply.cookie, &reply.input); 364 request->SendReply(rv, &reply, sizeof(reply)); 365 return B_OK; 366 } 367 368 case CONSUMER_DISPOSE_INPUT_COOKIE: 369 { 370 const consumer_dispose_input_cookie_request *request = static_cast<const consumer_dispose_input_cookie_request *>(data); 371 consumer_dispose_input_cookie_reply reply; 372 DisposeInputCookie(request->cookie); 373 request->SendReply(B_OK, &reply, sizeof(reply)); 374 return B_OK; 375 } 376 377 case CONSUMER_BUFFER_RECEIVED: 378 { 379 const consumer_buffer_received_command* command 380 = static_cast<const consumer_buffer_received_command*>(data); 381 382 BBuffer* buffer = fBufferCache->GetBuffer(command->buffer); 383 if (buffer == NULL) { 384 ERROR("BBufferConsumer::CONSUMER_BUFFER_RECEIVED can't" 385 "find the buffer\n"); 386 } else { 387 buffer->SetHeader(&command->header); 388 389 PRINT(4, "calling BBufferConsumer::BufferReceived buffer %ld " 390 "at perf %Ld and TimeSource()->Now() is %Ld\n", 391 buffer->Header()->buffer, buffer->Header()->start_time, 392 TimeSource()->Now()); 393 394 BufferReceived(buffer); 395 } 396 return B_OK; 397 } 398 399 case CONSUMER_PRODUCER_DATA_STATUS: 400 { 401 const consumer_producer_data_status_command *command = static_cast<const consumer_producer_data_status_command *>(data); 402 ProducerDataStatus(command->for_whom, command->status, command->at_performance_time); 403 return B_OK; 404 } 405 406 case CONSUMER_GET_LATENCY_FOR: 407 { 408 const consumer_get_latency_for_request *request = static_cast<const consumer_get_latency_for_request *>(data); 409 consumer_get_latency_for_reply reply; 410 rv = GetLatencyFor(request->for_whom, &reply.latency, &reply.timesource); 411 request->SendReply(rv, &reply, sizeof(reply)); 412 return B_OK; 413 } 414 415 case CONSUMER_CONNECTED: 416 { 417 const consumer_connected_request *request = static_cast<const consumer_connected_request *>(data); 418 consumer_connected_reply reply; 419 reply.input = request->input; 420 rv = Connected(request->input.source, request->input.destination, request->input.format, &reply.input); 421 request->SendReply(rv, &reply, sizeof(reply)); 422 return B_OK; 423 } 424 425 case CONSUMER_DISCONNECTED: 426 { 427 const consumer_disconnected_request *request = static_cast<const consumer_disconnected_request *>(data); 428 consumer_disconnected_reply reply; 429 Disconnected(request->source, request->destination); 430 request->SendReply(B_OK, &reply, sizeof(reply)); 431 return B_OK; 432 } 433 434 case CONSUMER_FORMAT_CHANGED: 435 { 436 const consumer_format_changed_request *request = static_cast<const consumer_format_changed_request *>(data); 437 consumer_format_changed_reply reply; 438 rv = FormatChanged(request->producer, request->consumer, request->change_tag, request->format); 439 request->SendReply(rv, &reply, sizeof(reply)); 440 441 // XXX is this RequestCompleted() correct? 442 node_request_completed_command completedcommand; 443 completedcommand.info.what = media_request_info::B_FORMAT_CHANGED; 444 completedcommand.info.change_tag = request->change_tag; 445 completedcommand.info.status = reply.result; 446 //completedcommand.info.cookie 447 completedcommand.info.user_data = 0; 448 completedcommand.info.source = request->producer; 449 completedcommand.info.destination = request->consumer; 450 completedcommand.info.format = request->format; 451 SendToPort(request->consumer.port, NODE_REQUEST_COMPLETED, &completedcommand, sizeof(completedcommand)); 452 return B_OK; 453 } 454 455 case CONSUMER_SEEK_TAG_REQUESTED: 456 { 457 const consumer_seek_tag_requested_request *request = static_cast<const consumer_seek_tag_requested_request *>(data); 458 consumer_seek_tag_requested_reply reply; 459 rv = SeekTagRequested(request->destination, request->target_time, request->flags, &reply.seek_tag, &reply.tagged_time, &reply.flags); 460 request->SendReply(rv, &reply, sizeof(reply)); 461 return B_OK; 462 } 463 } 464 return B_ERROR; 465 } 466 467 status_t 468 BBufferConsumer::SeekTagRequested(const media_destination &destination, 469 bigtime_t in_target_time, 470 uint32 in_flags, 471 media_seek_tag *out_seek_tag, 472 bigtime_t *out_tagged_time, 473 uint32 *out_flags) 474 { 475 CALLED(); 476 // may be implemented by derived classes 477 return B_ERROR; 478 } 479 480 481 // #pragma mark - private BBufferConsumer 482 483 484 /* 485 not implemented: 486 BBufferConsumer::BBufferConsumer() 487 BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone) 488 BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone) 489 */ 490 491 492 /*! Deprecated function for BeOS R4. 493 */ 494 /* static */ status_t 495 BBufferConsumer::SetVideoClippingFor(const media_source &output, 496 const int16 *shorts, 497 int32 short_count, 498 const media_video_display_info &display, 499 int32 *change_tag) 500 { 501 CALLED(); 502 if (IS_INVALID_SOURCE(output)) 503 return B_MEDIA_BAD_SOURCE; 504 if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(producer_video_clipping_changed_command)) / 2) 505 debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n"); 506 507 producer_video_clipping_changed_command *command; 508 size_t size; 509 status_t rv; 510 511 size = sizeof(producer_video_clipping_changed_command) + short_count * sizeof(short); 512 command = static_cast<producer_video_clipping_changed_command *>(malloc(size)); 513 command->source = output; 514 command->destination = media_destination::null; 515 command->display = display; 516 command->user_data = 0; 517 command->change_tag = NewChangeTag(); 518 command->short_count = short_count; 519 memcpy(command->shorts, shorts, short_count * sizeof(short)); 520 if (change_tag != NULL) 521 *change_tag = command->change_tag; 522 523 rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size); 524 free(command); 525 return rv; 526 } 527 528 529 /*! Deprecated function for BeOS R4. 530 */ 531 /*static*/ status_t 532 BBufferConsumer::RequestFormatChange(const media_source& source, 533 const media_destination& destination, media_format* format, 534 int32* _changeTag) 535 { 536 CALLED(); 537 if (IS_INVALID_SOURCE(source)) 538 return B_MEDIA_BAD_SOURCE; 539 if (IS_INVALID_DESTINATION(destination)) 540 return B_MEDIA_BAD_DESTINATION; 541 542 producer_format_change_requested_command command; 543 544 command.source = source; 545 command.destination = destination; 546 command.format = *format; 547 command.user_data = 0; 548 command.change_tag = NewChangeTag(); 549 if (_changeTag != NULL) 550 *_changeTag = command.change_tag; 551 552 return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, 553 sizeof(command)); 554 } 555 556 557 /*! Deprecated function for BeOS R4. 558 */ 559 /*static*/ status_t 560 BBufferConsumer::SetOutputEnabled(const media_source& source, bool enabled, 561 int32* _changeTag) 562 { 563 CALLED(); 564 if (IS_INVALID_SOURCE(source)) 565 return B_MEDIA_BAD_SOURCE; 566 567 producer_enable_output_command command; 568 569 command.source = source; 570 command.destination = media_destination::null; 571 command.enabled = enabled; 572 command.user_data = 0; 573 command.change_tag = NewChangeTag(); 574 if (_changeTag != NULL) 575 *_changeTag = command.change_tag; 576 577 return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, 578 sizeof(command)); 579 } 580 581 582 status_t BBufferConsumer::_Reserved_BufferConsumer_0(void*) { return B_ERROR; } 583 status_t BBufferConsumer::_Reserved_BufferConsumer_1(void*) { return B_ERROR; } 584 status_t BBufferConsumer::_Reserved_BufferConsumer_2(void*) { return B_ERROR; } 585 status_t BBufferConsumer::_Reserved_BufferConsumer_3(void*) { return B_ERROR; } 586 status_t BBufferConsumer::_Reserved_BufferConsumer_4(void*) { return B_ERROR; } 587 status_t BBufferConsumer::_Reserved_BufferConsumer_5(void*) { return B_ERROR; } 588 status_t BBufferConsumer::_Reserved_BufferConsumer_6(void*) { return B_ERROR; } 589 status_t BBufferConsumer::_Reserved_BufferConsumer_7(void*) { return B_ERROR; } 590 status_t BBufferConsumer::_Reserved_BufferConsumer_8(void*) { return B_ERROR; } 591 status_t BBufferConsumer::_Reserved_BufferConsumer_9(void*) { return B_ERROR; } 592 status_t BBufferConsumer::_Reserved_BufferConsumer_10(void*) { return B_ERROR; } 593 status_t BBufferConsumer::_Reserved_BufferConsumer_11(void*) { return B_ERROR; } 594 status_t BBufferConsumer::_Reserved_BufferConsumer_12(void*) { return B_ERROR; } 595 status_t BBufferConsumer::_Reserved_BufferConsumer_13(void*) { return B_ERROR; } 596 status_t BBufferConsumer::_Reserved_BufferConsumer_14(void*) { return B_ERROR; } 597 status_t BBufferConsumer::_Reserved_BufferConsumer_15(void*) { return B_ERROR; } 598 599