1 /* 2 * Copyright 2010-2012, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2002-2003, Marcus Overhagen, <Marcus@Overhagen.de>. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <Buffer.h> 9 #include <BufferConsumer.h> 10 #include <BufferGroup.h> 11 #include <BufferProducer.h> 12 13 #include "MediaDebug.h" 14 #include "DataExchange.h" 15 #include "MediaMisc.h" 16 17 18 // #pragma mark - protected BBufferProducer 19 20 21 BBufferProducer::~BBufferProducer() 22 { 23 CALLED(); 24 } 25 26 27 // #pragma mark - public BBufferProducer 28 29 30 /*static*/ status_t 31 BBufferProducer::ClipDataToRegion(int32 format, int32 size, const void* data, 32 BRegion* region) 33 { 34 CALLED(); 35 36 if (format != B_CLIP_SHORT_RUNS) 37 return B_MEDIA_BAD_CLIP_FORMAT; 38 39 return clip_shorts_to_region((const int16*)data, size / sizeof(int16), 40 region); 41 } 42 43 44 media_type 45 BBufferProducer::ProducerType() 46 { 47 CALLED(); 48 return fProducerType; 49 } 50 51 52 // #pragma mark - protected BBufferProducer 53 54 55 BBufferProducer::BBufferProducer(media_type producer_type) 56 : 57 BMediaNode("called by BBufferProducer"), 58 fProducerType(producer_type), 59 fInitialLatency(0), 60 fInitialFlags(0), 61 fDelay(0) 62 { 63 CALLED(); 64 65 AddNodeKind(B_BUFFER_PRODUCER); 66 } 67 68 69 status_t 70 BBufferProducer::VideoClippingChanged(const media_source& source, 71 int16 numShorts, int16* clipData, const media_video_display_info& display, 72 int32* /*_deprecated_*/) 73 { 74 CALLED(); 75 // may be implemented by derived classes 76 return B_ERROR; 77 } 78 79 80 status_t 81 BBufferProducer::GetLatency(bigtime_t* _latency) 82 { 83 CALLED(); 84 // The default implementation of GetLatency() finds the maximum 85 // latency of your currently-available outputs by iterating over 86 // them, and returns that value in outLatency 87 88 int32 cookie; 89 bigtime_t latency; 90 media_output output; 91 media_node_id unused; 92 93 *_latency = 0; 94 cookie = 0; 95 while (GetNextOutput(&cookie, &output) == B_OK) { 96 if (output.destination == media_destination::null) 97 continue; 98 99 if (output.node.node == fNodeID) { 100 // avoid port writes (deadlock) if loopback connection 101 if (fConsumerThis == NULL) 102 fConsumerThis = dynamic_cast<BBufferConsumer*>(this); 103 if (fConsumerThis == NULL) 104 continue; 105 106 latency = 0; 107 if (fConsumerThis->GetLatencyFor(output.destination, &latency, 108 &unused) == B_OK && latency > *_latency) { 109 *_latency = latency; 110 } 111 } else if (FindLatencyFor(output.destination, &latency, &unused) 112 == B_OK && latency > *_latency) { 113 *_latency = latency; 114 } 115 } 116 printf("BBufferProducer::GetLatency: node %" B_PRId32 ", name \"%s\" has " 117 "max latency %" B_PRId64 "\n", fNodeID, fName, *_latency); 118 return B_OK; 119 } 120 121 122 status_t 123 BBufferProducer::SetPlayRate(int32 numer, int32 denom) 124 { 125 CALLED(); 126 // may be implemented by derived classes 127 return B_ERROR; 128 } 129 130 131 status_t 132 BBufferProducer::HandleMessage(int32 message, const void* data, size_t size) 133 { 134 PRINT(4, "BBufferProducer::HandleMessage %#lx, node %ld\n", message, 135 fNodeID); 136 137 switch (message) { 138 case PRODUCER_SET_RUN_MODE_DELAY: 139 { 140 const producer_set_run_mode_delay_command* command 141 = static_cast<const producer_set_run_mode_delay_command*>(data); 142 // when changing this, also change NODE_SET_RUN_MODE 143 fDelay = command->delay; 144 fRunMode = command->mode; 145 146 TRACE("PRODUCER_SET_RUN_MODE_DELAY: fDelay now %" B_PRId64 "\n", 147 fDelay); 148 149 SetRunMode(fRunMode); 150 return B_OK; 151 } 152 153 case PRODUCER_FORMAT_SUGGESTION_REQUESTED: 154 { 155 const producer_format_suggestion_requested_request* request 156 = static_cast< 157 const producer_format_suggestion_requested_request*>(data); 158 producer_format_suggestion_requested_reply reply; 159 status_t status = FormatSuggestionRequested(request->type, 160 request->quality, &reply.format); 161 request->SendReply(status, &reply, sizeof(reply)); 162 return B_OK; 163 } 164 165 case PRODUCER_FORMAT_PROPOSAL: 166 { 167 const producer_format_proposal_request* request 168 = static_cast<const producer_format_proposal_request*>(data); 169 producer_format_proposal_reply reply; 170 reply.format = request->format; 171 status_t status = FormatProposal(request->output, &reply.format); 172 request->SendReply(status, &reply, sizeof(reply)); 173 return B_OK; 174 } 175 176 case PRODUCER_PREPARE_TO_CONNECT: 177 { 178 const producer_prepare_to_connect_request* request 179 = static_cast<const producer_prepare_to_connect_request*>(data); 180 producer_prepare_to_connect_reply reply; 181 reply.format = request->format; 182 reply.out_source = request->source; 183 memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH); 184 status_t status = PrepareToConnect(request->source, 185 request->destination, &reply.format, &reply.out_source, 186 reply.name); 187 request->SendReply(status, &reply, sizeof(reply)); 188 return B_OK; 189 } 190 191 case PRODUCER_CONNECT: 192 { 193 const producer_connect_request* request 194 = static_cast<const producer_connect_request*>(data); 195 producer_connect_reply reply; 196 memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH); 197 Connect(request->error, request->source, request->destination, 198 request->format, reply.name); 199 request->SendReply(B_OK, &reply, sizeof(reply)); 200 return B_OK; 201 } 202 203 case PRODUCER_DISCONNECT: 204 { 205 const producer_disconnect_request* request 206 = static_cast<const producer_disconnect_request*>(data); 207 producer_disconnect_reply reply; 208 Disconnect(request->source, request->destination); 209 request->SendReply(B_OK, &reply, sizeof(reply)); 210 return B_OK; 211 } 212 213 case PRODUCER_GET_INITIAL_LATENCY: 214 { 215 const producer_get_initial_latency_request* request 216 = static_cast< 217 const producer_get_initial_latency_request*>(data); 218 producer_get_initial_latency_reply reply; 219 reply.initial_latency = fInitialLatency; 220 reply.flags = fInitialFlags; 221 request->SendReply(B_OK, &reply, sizeof(reply)); 222 return B_OK; 223 } 224 225 case PRODUCER_SET_PLAY_RATE: 226 { 227 const producer_set_play_rate_request* request 228 = static_cast<const producer_set_play_rate_request*>(data); 229 producer_set_play_rate_reply reply; 230 status_t status = SetPlayRate(request->numer, request->denom); 231 request->SendReply(status, &reply, sizeof(reply)); 232 return B_OK; 233 } 234 235 case PRODUCER_GET_LATENCY: 236 { 237 const producer_get_latency_request* request 238 = static_cast<const producer_get_latency_request*>(data); 239 producer_get_latency_reply reply; 240 status_t status = GetLatency(&reply.latency); 241 request->SendReply(status, &reply, sizeof(reply)); 242 return B_OK; 243 } 244 245 case PRODUCER_GET_NEXT_OUTPUT: 246 { 247 const producer_get_next_output_request* request 248 = static_cast<const producer_get_next_output_request*>(data); 249 producer_get_next_output_reply reply; 250 reply.cookie = request->cookie; 251 status_t status = GetNextOutput(&reply.cookie, &reply.output); 252 request->SendReply(status, &reply, sizeof(reply)); 253 return B_OK; 254 } 255 256 case PRODUCER_DISPOSE_OUTPUT_COOKIE: 257 { 258 const producer_dispose_output_cookie_request*request 259 = static_cast< 260 const producer_dispose_output_cookie_request*>(data); 261 producer_dispose_output_cookie_reply reply; 262 DisposeOutputCookie(request->cookie); 263 request->SendReply(B_OK, &reply, sizeof(reply)); 264 return B_OK; 265 } 266 267 case PRODUCER_SET_BUFFER_GROUP: 268 { 269 const producer_set_buffer_group_command* command 270 = static_cast<const producer_set_buffer_group_command*>(data); 271 node_request_completed_command replycommand; 272 BBufferGroup *group; 273 group = command->buffer_count != 0 274 ? new BBufferGroup(command->buffer_count, command->buffers) 275 : NULL; 276 277 if (group != NULL && group->InitCheck() != B_OK) { 278 ERROR("BBufferProducer::HandleMessage PRODUCER_SET_BUFFER_GROUP" 279 " group InitCheck() failed.\n"); 280 delete group; 281 group = NULL; 282 } 283 status_t status = SetBufferGroup(command->source, group); 284 if (command->destination == media_destination::null) 285 return B_OK; 286 replycommand.info.what 287 = media_request_info::B_SET_OUTPUT_BUFFERS_FOR; 288 replycommand.info.change_tag = command->change_tag; 289 replycommand.info.status = status; 290 replycommand.info.cookie = group; 291 replycommand.info.user_data = command->user_data; 292 replycommand.info.source = command->source; 293 replycommand.info.destination = command->destination; 294 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 295 &replycommand, sizeof(replycommand)); 296 return B_OK; 297 } 298 299 case PRODUCER_FORMAT_CHANGE_REQUESTED: 300 { 301 const producer_format_change_requested_command* command 302 = static_cast< 303 const producer_format_change_requested_command*>(data); 304 node_request_completed_command replycommand; 305 replycommand.info.format = command->format; 306 status_t status = FormatChangeRequested(command->source, 307 command->destination, &replycommand.info.format, NULL); 308 if (command->destination == media_destination::null) 309 return B_OK; 310 replycommand.info.what 311 = media_request_info::B_REQUEST_FORMAT_CHANGE; 312 replycommand.info.change_tag = command->change_tag; 313 replycommand.info.status = status; 314 //replycommand.info.cookie 315 replycommand.info.user_data = command->user_data; 316 replycommand.info.source = command->source; 317 replycommand.info.destination = command->destination; 318 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 319 &replycommand, sizeof(replycommand)); 320 return B_OK; 321 } 322 323 case PRODUCER_VIDEO_CLIPPING_CHANGED: 324 { 325 const producer_video_clipping_changed_command* command 326 = static_cast< 327 const producer_video_clipping_changed_command*>(data); 328 node_request_completed_command replycommand; 329 status_t status = VideoClippingChanged(command->source, 330 command->short_count, (int16 *)command->shorts, 331 command->display, NULL); 332 if (command->destination == media_destination::null) 333 return B_OK; 334 replycommand.info.what 335 = media_request_info::B_SET_VIDEO_CLIPPING_FOR; 336 replycommand.info.change_tag = command->change_tag; 337 replycommand.info.status = status; 338 //replycommand.info.cookie 339 replycommand.info.user_data = command->user_data; 340 replycommand.info.source = command->source; 341 replycommand.info.destination = command->destination; 342 replycommand.info.format.type = B_MEDIA_RAW_VIDEO; 343 replycommand.info.format.u.raw_video.display = command->display; 344 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 345 &replycommand, sizeof(replycommand)); 346 return B_OK; 347 } 348 349 case PRODUCER_ADDITIONAL_BUFFER_REQUESTED: 350 { 351 const producer_additional_buffer_requested_command* command 352 = static_cast< 353 const producer_additional_buffer_requested_command*>(data); 354 AdditionalBufferRequested(command->source, command->prev_buffer, 355 command->prev_time, command->has_seek_tag 356 ? &command->prev_tag : NULL); 357 return B_OK; 358 } 359 360 case PRODUCER_LATENCY_CHANGED: 361 { 362 const producer_latency_changed_command* command 363 = static_cast<const producer_latency_changed_command*>(data); 364 LatencyChanged(command->source, command->destination, 365 command->latency, command->flags); 366 return B_OK; 367 } 368 369 case PRODUCER_LATE_NOTICE_RECEIVED: 370 { 371 const producer_late_notice_received_command* command 372 = static_cast< 373 const producer_late_notice_received_command*>(data); 374 LateNoticeReceived(command->source, command->how_much, 375 command->performance_time); 376 return B_OK; 377 } 378 379 case PRODUCER_ENABLE_OUTPUT: 380 { 381 const producer_enable_output_command* command 382 = static_cast<const producer_enable_output_command*>(data); 383 node_request_completed_command replycommand; 384 EnableOutput(command->source, command->enabled, NULL); 385 if (command->destination == media_destination::null) 386 return B_OK; 387 388 replycommand.info.what = media_request_info::B_SET_OUTPUT_ENABLED; 389 replycommand.info.change_tag = command->change_tag; 390 replycommand.info.status = B_OK; 391 //replycommand.info.cookie 392 replycommand.info.user_data = command->user_data; 393 replycommand.info.source = command->source; 394 replycommand.info.destination = command->destination; 395 //replycommand.info.format 396 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 397 &replycommand, sizeof(replycommand)); 398 return B_OK; 399 } 400 } 401 402 return B_ERROR; 403 } 404 405 406 void 407 BBufferProducer::AdditionalBufferRequested(const media_source& source, 408 media_buffer_id previousBuffer, bigtime_t previousTime, 409 const media_seek_tag* previousTag) 410 { 411 CALLED(); 412 // may be implemented by derived classes 413 } 414 415 416 void 417 BBufferProducer::LatencyChanged(const media_source& source, 418 const media_destination& destination, bigtime_t newLatency, uint32 flags) 419 { 420 CALLED(); 421 // may be implemented by derived classes 422 } 423 424 425 status_t 426 BBufferProducer::SendBuffer(BBuffer* buffer, const media_source& source, 427 const media_destination& destination) 428 { 429 CALLED(); 430 if (destination == media_destination::null) 431 return B_MEDIA_BAD_DESTINATION; 432 if (source == media_source::null) 433 return B_MEDIA_BAD_SOURCE; 434 if (buffer == NULL) 435 return B_BAD_VALUE; 436 437 consumer_buffer_received_command command; 438 command.buffer = buffer->ID(); 439 command.header = *buffer->Header(); 440 command.header.buffer = command.buffer; 441 command.header.source_port = source.port; 442 command.header.source = source.id; 443 command.header.destination = destination.id; 444 command.header.owner = 0; // XXX fill with "buffer owner info area" 445 command.header.start_time += fDelay; 446 // time compensation as set by BMediaRoster::SetProducerRunModeDelay() 447 448 //printf("BBufferProducer::SendBuffer node %2ld, buffer %2ld, start_time %12Ld with lateness %6Ld\n", ID(), buffer->Header()->buffer, command.header.start_time, TimeSource()->Now() - command.header.start_time); 449 450 return SendToPort(destination.port, CONSUMER_BUFFER_RECEIVED, &command, 451 sizeof(command)); 452 } 453 454 455 status_t 456 BBufferProducer::SendDataStatus(int32 status, 457 const media_destination& destination, bigtime_t atTime) 458 { 459 CALLED(); 460 if (IS_INVALID_DESTINATION(destination)) 461 return B_MEDIA_BAD_DESTINATION; 462 463 consumer_producer_data_status_command command; 464 command.for_whom = destination; 465 command.status = status; 466 command.at_performance_time = atTime; 467 468 return SendToPort(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &command, 469 sizeof(command)); 470 } 471 472 473 status_t 474 BBufferProducer::ProposeFormatChange(media_format* format, 475 const media_destination& destination) 476 { 477 CALLED(); 478 if (IS_INVALID_DESTINATION(destination)) 479 return B_MEDIA_BAD_DESTINATION; 480 481 consumer_accept_format_request request; 482 consumer_accept_format_reply reply; 483 484 request.dest = destination; 485 request.format = *format; 486 status_t status = QueryPort(destination.port, CONSUMER_ACCEPT_FORMAT, 487 &request, sizeof(request), &reply, sizeof(reply)); 488 if (status != B_OK) 489 return status; 490 491 *format = reply.format; 492 return B_OK; 493 } 494 495 496 status_t 497 BBufferProducer::ChangeFormat(const media_source& source, 498 const media_destination& destination, media_format* format) 499 { 500 CALLED(); 501 if (IS_INVALID_SOURCE(source)) 502 return B_MEDIA_BAD_SOURCE; 503 if (IS_INVALID_DESTINATION(destination)) 504 return B_MEDIA_BAD_DESTINATION; 505 506 consumer_format_changed_request request; 507 consumer_format_changed_reply reply; 508 509 request.producer = source; 510 request.consumer = destination; 511 request.format = *format; 512 513 // we use a request/reply to make this synchronous 514 return QueryPort(destination.port, CONSUMER_FORMAT_CHANGED, &request, 515 sizeof(request), &reply, sizeof(reply)); 516 } 517 518 519 status_t 520 BBufferProducer::FindLatencyFor(const media_destination& destination, 521 bigtime_t* _latency, media_node_id* _timesource) 522 { 523 CALLED(); 524 if (IS_INVALID_DESTINATION(destination)) 525 return B_MEDIA_BAD_DESTINATION; 526 527 consumer_get_latency_for_request request; 528 consumer_get_latency_for_reply reply; 529 530 request.for_whom = destination; 531 532 status_t status = QueryPort(destination.port, CONSUMER_GET_LATENCY_FOR, 533 &request, sizeof(request), &reply, sizeof(reply)); 534 if (status != B_OK) 535 return status; 536 537 *_latency = reply.latency; 538 *_timesource = reply.timesource; 539 return B_OK; 540 } 541 542 543 status_t 544 BBufferProducer::FindSeekTag(const media_destination& destination, 545 bigtime_t targetTime, media_seek_tag* _tag, bigtime_t* _tagged_time, 546 uint32* _flags, uint32 flags) 547 { 548 CALLED(); 549 if (IS_INVALID_DESTINATION(destination)) 550 return B_MEDIA_BAD_DESTINATION; 551 552 consumer_seek_tag_requested_request request; 553 consumer_seek_tag_requested_reply reply; 554 555 request.destination = destination; 556 request.target_time = targetTime; 557 request.flags = flags; 558 559 status_t status = QueryPort(destination.port, CONSUMER_SEEK_TAG_REQUESTED, 560 &request, sizeof(request), &reply, sizeof(reply)); 561 if (status != B_OK) 562 return status; 563 564 *_tag = reply.seek_tag; 565 *_tagged_time = reply.tagged_time; 566 *_flags = reply.flags; 567 return B_OK; 568 } 569 570 571 void 572 BBufferProducer::SetInitialLatency(bigtime_t initialLatency, uint32 flags) 573 { 574 fInitialLatency = initialLatency; 575 fInitialFlags = flags; 576 } 577 578 579 // #pragma mark - private BBufferProducer 580 581 582 /* 583 private unimplemented 584 BBufferProducer::BBufferProducer() 585 BBufferProducer::BBufferProducer(const BBufferProducer &clone) 586 BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone) 587 */ 588 589 status_t BBufferProducer::_Reserved_BufferProducer_0(void*) { return B_ERROR; } 590 status_t BBufferProducer::_Reserved_BufferProducer_1(void*) { return B_ERROR; } 591 status_t BBufferProducer::_Reserved_BufferProducer_2(void*) { return B_ERROR; } 592 status_t BBufferProducer::_Reserved_BufferProducer_3(void*) { return B_ERROR; } 593 status_t BBufferProducer::_Reserved_BufferProducer_4(void*) { return B_ERROR; } 594 status_t BBufferProducer::_Reserved_BufferProducer_5(void*) { return B_ERROR; } 595 status_t BBufferProducer::_Reserved_BufferProducer_6(void*) { return B_ERROR; } 596 status_t BBufferProducer::_Reserved_BufferProducer_7(void*) { return B_ERROR; } 597 status_t BBufferProducer::_Reserved_BufferProducer_8(void*) { return B_ERROR; } 598 status_t BBufferProducer::_Reserved_BufferProducer_9(void*) { return B_ERROR; } 599 status_t BBufferProducer::_Reserved_BufferProducer_10(void*) { return B_ERROR; } 600 status_t BBufferProducer::_Reserved_BufferProducer_11(void*) { return B_ERROR; } 601 status_t BBufferProducer::_Reserved_BufferProducer_12(void*) { return B_ERROR; } 602 status_t BBufferProducer::_Reserved_BufferProducer_13(void*) { return B_ERROR; } 603 status_t BBufferProducer::_Reserved_BufferProducer_14(void*) { return B_ERROR; } 604 status_t BBufferProducer::_Reserved_BufferProducer_15(void*) { return B_ERROR; } 605 606 607 //! Deprecated. 608 status_t 609 BBufferProducer::SendBuffer(BBuffer* buffer, 610 const media_destination& destination) 611 { 612 CALLED(); 613 614 // Try to find the source - this is the best we can do 615 media_output output; 616 int32 cookie = 0; 617 status_t status = GetNextOutput(&cookie, &output); 618 if (status != B_OK) 619 return status; 620 621 return SendBuffer(buffer, output.source, destination); 622 } 623 624 625 status_t 626 BBufferProducer::clip_shorts_to_region(const int16* data, int count, 627 BRegion* output) 628 { 629 UNIMPLEMENTED(); 630 return B_ERROR; 631 } 632 633 634 status_t 635 BBufferProducer::clip_region_to_shorts(const BRegion* input, int16* data, 636 int maxCount, int* _count) 637 { 638 UNIMPLEMENTED(); 639 return B_ERROR; 640 } 641