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 "debug.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 TRACE("PRODUCER_SET_RUN_MODE_DELAY: fDelay now %Ld\n", fDelay); 146 SetRunMode(fRunMode); 147 return B_OK; 148 } 149 150 case PRODUCER_FORMAT_SUGGESTION_REQUESTED: 151 { 152 const producer_format_suggestion_requested_request* request 153 = static_cast< 154 const producer_format_suggestion_requested_request*>(data); 155 producer_format_suggestion_requested_reply reply; 156 status_t status = FormatSuggestionRequested(request->type, 157 request->quality, &reply.format); 158 request->SendReply(status, &reply, sizeof(reply)); 159 return B_OK; 160 } 161 162 case PRODUCER_FORMAT_PROPOSAL: 163 { 164 const producer_format_proposal_request* request 165 = static_cast<const producer_format_proposal_request*>(data); 166 producer_format_proposal_reply reply; 167 reply.format = request->format; 168 status_t status = FormatProposal(request->output, &reply.format); 169 request->SendReply(status, &reply, sizeof(reply)); 170 return B_OK; 171 } 172 173 case PRODUCER_PREPARE_TO_CONNECT: 174 { 175 const producer_prepare_to_connect_request* request 176 = static_cast<const producer_prepare_to_connect_request*>(data); 177 producer_prepare_to_connect_reply reply; 178 reply.format = request->format; 179 reply.out_source = request->source; 180 memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH); 181 status_t status = PrepareToConnect(request->source, 182 request->destination, &reply.format, &reply.out_source, 183 reply.name); 184 request->SendReply(status, &reply, sizeof(reply)); 185 return B_OK; 186 } 187 188 case PRODUCER_CONNECT: 189 { 190 const producer_connect_request* request 191 = static_cast<const producer_connect_request*>(data); 192 producer_connect_reply reply; 193 memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH); 194 Connect(request->error, request->source, request->destination, 195 request->format, reply.name); 196 request->SendReply(B_OK, &reply, sizeof(reply)); 197 return B_OK; 198 } 199 200 case PRODUCER_DISCONNECT: 201 { 202 const producer_disconnect_request* request 203 = static_cast<const producer_disconnect_request*>(data); 204 producer_disconnect_reply reply; 205 Disconnect(request->source, request->destination); 206 request->SendReply(B_OK, &reply, sizeof(reply)); 207 return B_OK; 208 } 209 210 case PRODUCER_GET_INITIAL_LATENCY: 211 { 212 const producer_get_initial_latency_request* request 213 = static_cast< 214 const producer_get_initial_latency_request*>(data); 215 producer_get_initial_latency_reply reply; 216 reply.initial_latency = fInitialLatency; 217 reply.flags = fInitialFlags; 218 request->SendReply(B_OK, &reply, sizeof(reply)); 219 return B_OK; 220 } 221 222 case PRODUCER_SET_PLAY_RATE: 223 { 224 const producer_set_play_rate_request* request 225 = static_cast<const producer_set_play_rate_request*>(data); 226 producer_set_play_rate_reply reply; 227 status_t status = SetPlayRate(request->numer, request->denom); 228 request->SendReply(status, &reply, sizeof(reply)); 229 return B_OK; 230 } 231 232 case PRODUCER_GET_LATENCY: 233 { 234 const producer_get_latency_request* request 235 = static_cast<const producer_get_latency_request*>(data); 236 producer_get_latency_reply reply; 237 status_t status = GetLatency(&reply.latency); 238 request->SendReply(status, &reply, sizeof(reply)); 239 return B_OK; 240 } 241 242 case PRODUCER_GET_NEXT_OUTPUT: 243 { 244 const producer_get_next_output_request* request 245 = static_cast<const producer_get_next_output_request*>(data); 246 producer_get_next_output_reply reply; 247 reply.cookie = request->cookie; 248 status_t status = GetNextOutput(&reply.cookie, &reply.output); 249 request->SendReply(status, &reply, sizeof(reply)); 250 return B_OK; 251 } 252 253 case PRODUCER_DISPOSE_OUTPUT_COOKIE: 254 { 255 const producer_dispose_output_cookie_request*request 256 = static_cast< 257 const producer_dispose_output_cookie_request*>(data); 258 producer_dispose_output_cookie_reply reply; 259 DisposeOutputCookie(request->cookie); 260 request->SendReply(B_OK, &reply, sizeof(reply)); 261 return B_OK; 262 } 263 264 case PRODUCER_SET_BUFFER_GROUP: 265 { 266 const producer_set_buffer_group_command* command 267 = static_cast<const producer_set_buffer_group_command*>(data); 268 node_request_completed_command replycommand; 269 BBufferGroup *group; 270 group = command->buffer_count != 0 271 ? new BBufferGroup(command->buffer_count, command->buffers) 272 : NULL; 273 274 if (group != NULL && group->InitCheck() != B_OK) { 275 ERROR("BBufferProducer::HandleMessage PRODUCER_SET_BUFFER_GROUP" 276 " group InitCheck() failed.\n"); 277 delete group; 278 group = NULL; 279 } 280 status_t status = SetBufferGroup(command->source, group); 281 if (command->destination == media_destination::null) 282 return B_OK; 283 replycommand.info.what 284 = media_request_info::B_SET_OUTPUT_BUFFERS_FOR; 285 replycommand.info.change_tag = command->change_tag; 286 replycommand.info.status = status; 287 replycommand.info.cookie = group; 288 replycommand.info.user_data = command->user_data; 289 replycommand.info.source = command->source; 290 replycommand.info.destination = command->destination; 291 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 292 &replycommand, sizeof(replycommand)); 293 return B_OK; 294 } 295 296 case PRODUCER_FORMAT_CHANGE_REQUESTED: 297 { 298 const producer_format_change_requested_command* command 299 = static_cast< 300 const producer_format_change_requested_command*>(data); 301 node_request_completed_command replycommand; 302 replycommand.info.format = command->format; 303 status_t status = FormatChangeRequested(command->source, 304 command->destination, &replycommand.info.format, NULL); 305 if (command->destination == media_destination::null) 306 return B_OK; 307 replycommand.info.what 308 = media_request_info::B_REQUEST_FORMAT_CHANGE; 309 replycommand.info.change_tag = command->change_tag; 310 replycommand.info.status = status; 311 //replycommand.info.cookie 312 replycommand.info.user_data = command->user_data; 313 replycommand.info.source = command->source; 314 replycommand.info.destination = command->destination; 315 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 316 &replycommand, sizeof(replycommand)); 317 return B_OK; 318 } 319 320 case PRODUCER_VIDEO_CLIPPING_CHANGED: 321 { 322 const producer_video_clipping_changed_command* command 323 = static_cast< 324 const producer_video_clipping_changed_command*>(data); 325 node_request_completed_command replycommand; 326 status_t status = VideoClippingChanged(command->source, 327 command->short_count, (int16 *)command->shorts, 328 command->display, NULL); 329 if (command->destination == media_destination::null) 330 return B_OK; 331 replycommand.info.what 332 = media_request_info::B_SET_VIDEO_CLIPPING_FOR; 333 replycommand.info.change_tag = command->change_tag; 334 replycommand.info.status = status; 335 //replycommand.info.cookie 336 replycommand.info.user_data = command->user_data; 337 replycommand.info.source = command->source; 338 replycommand.info.destination = command->destination; 339 replycommand.info.format.type = B_MEDIA_RAW_VIDEO; 340 replycommand.info.format.u.raw_video.display = command->display; 341 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 342 &replycommand, sizeof(replycommand)); 343 return B_OK; 344 } 345 346 case PRODUCER_ADDITIONAL_BUFFER_REQUESTED: 347 { 348 const producer_additional_buffer_requested_command* command 349 = static_cast< 350 const producer_additional_buffer_requested_command*>(data); 351 AdditionalBufferRequested(command->source, command->prev_buffer, 352 command->prev_time, command->has_seek_tag 353 ? &command->prev_tag : NULL); 354 return B_OK; 355 } 356 357 case PRODUCER_LATENCY_CHANGED: 358 { 359 const producer_latency_changed_command* command 360 = static_cast<const producer_latency_changed_command*>(data); 361 LatencyChanged(command->source, command->destination, 362 command->latency, command->flags); 363 return B_OK; 364 } 365 366 case PRODUCER_LATE_NOTICE_RECEIVED: 367 { 368 const producer_late_notice_received_command* command 369 = static_cast< 370 const producer_late_notice_received_command*>(data); 371 LateNoticeReceived(command->source, command->how_much, 372 command->performance_time); 373 return B_OK; 374 } 375 376 case PRODUCER_ENABLE_OUTPUT: 377 { 378 const producer_enable_output_command* command 379 = static_cast<const producer_enable_output_command*>(data); 380 node_request_completed_command replycommand; 381 EnableOutput(command->source, command->enabled, NULL); 382 if (command->destination == media_destination::null) 383 return B_OK; 384 385 replycommand.info.what = media_request_info::B_SET_OUTPUT_ENABLED; 386 replycommand.info.change_tag = command->change_tag; 387 replycommand.info.status = B_OK; 388 //replycommand.info.cookie 389 replycommand.info.user_data = command->user_data; 390 replycommand.info.source = command->source; 391 replycommand.info.destination = command->destination; 392 //replycommand.info.format 393 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 394 &replycommand, sizeof(replycommand)); 395 return B_OK; 396 } 397 } 398 399 return B_ERROR; 400 } 401 402 403 void 404 BBufferProducer::AdditionalBufferRequested(const media_source& source, 405 media_buffer_id previousBuffer, bigtime_t previousTime, 406 const media_seek_tag* previousTag) 407 { 408 CALLED(); 409 // may be implemented by derived classes 410 } 411 412 413 void 414 BBufferProducer::LatencyChanged(const media_source& source, 415 const media_destination& destination, bigtime_t newLatency, uint32 flags) 416 { 417 CALLED(); 418 // may be implemented by derived classes 419 } 420 421 422 status_t 423 BBufferProducer::SendBuffer(BBuffer* buffer, const media_source& source, 424 const media_destination& destination) 425 { 426 CALLED(); 427 if (destination == media_destination::null) 428 return B_MEDIA_BAD_DESTINATION; 429 if (source == media_source::null) 430 return B_MEDIA_BAD_SOURCE; 431 if (buffer == NULL) 432 return B_BAD_VALUE; 433 434 consumer_buffer_received_command command; 435 command.buffer = buffer->ID(); 436 command.header = *buffer->Header(); 437 command.header.buffer = command.buffer; 438 command.header.source_port = source.port; 439 command.header.source = source.id; 440 command.header.destination = destination.id; 441 command.header.owner = 0; // XXX fill with "buffer owner info area" 442 command.header.start_time += fDelay; 443 // time compensation as set by BMediaRoster::SetProducerRunModeDelay() 444 445 //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); 446 447 return SendToPort(destination.port, CONSUMER_BUFFER_RECEIVED, &command, 448 sizeof(command)); 449 } 450 451 452 status_t 453 BBufferProducer::SendDataStatus(int32 status, 454 const media_destination& destination, bigtime_t atTime) 455 { 456 CALLED(); 457 if (IS_INVALID_DESTINATION(destination)) 458 return B_MEDIA_BAD_DESTINATION; 459 460 consumer_producer_data_status_command command; 461 command.for_whom = destination; 462 command.status = status; 463 command.at_performance_time = atTime; 464 465 return SendToPort(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &command, 466 sizeof(command)); 467 } 468 469 470 status_t 471 BBufferProducer::ProposeFormatChange(media_format* format, 472 const media_destination& destination) 473 { 474 CALLED(); 475 if (IS_INVALID_DESTINATION(destination)) 476 return B_MEDIA_BAD_DESTINATION; 477 478 consumer_accept_format_request request; 479 consumer_accept_format_reply reply; 480 481 request.dest = destination; 482 request.format = *format; 483 status_t status = QueryPort(destination.port, CONSUMER_ACCEPT_FORMAT, 484 &request, sizeof(request), &reply, sizeof(reply)); 485 if (status != B_OK) 486 return status; 487 488 *format = reply.format; 489 return B_OK; 490 } 491 492 493 status_t 494 BBufferProducer::ChangeFormat(const media_source& source, 495 const media_destination& destination, media_format* format) 496 { 497 CALLED(); 498 if (IS_INVALID_SOURCE(source)) 499 return B_MEDIA_BAD_SOURCE; 500 if (IS_INVALID_DESTINATION(destination)) 501 return B_MEDIA_BAD_DESTINATION; 502 503 consumer_format_changed_request request; 504 consumer_format_changed_reply reply; 505 506 request.producer = source; 507 request.consumer = destination; 508 request.format = *format; 509 510 // we use a request/reply to make this synchronous 511 return QueryPort(destination.port, CONSUMER_FORMAT_CHANGED, &request, 512 sizeof(request), &reply, sizeof(reply)); 513 } 514 515 516 status_t 517 BBufferProducer::FindLatencyFor(const media_destination& destination, 518 bigtime_t* _latency, media_node_id* _timesource) 519 { 520 CALLED(); 521 if (IS_INVALID_DESTINATION(destination)) 522 return B_MEDIA_BAD_DESTINATION; 523 524 consumer_get_latency_for_request request; 525 consumer_get_latency_for_reply reply; 526 527 request.for_whom = destination; 528 529 status_t status = QueryPort(destination.port, CONSUMER_GET_LATENCY_FOR, 530 &request, sizeof(request), &reply, sizeof(reply)); 531 if (status != B_OK) 532 return status; 533 534 *_latency = reply.latency; 535 *_timesource = reply.timesource; 536 return B_OK; 537 } 538 539 540 status_t 541 BBufferProducer::FindSeekTag(const media_destination& destination, 542 bigtime_t targetTime, media_seek_tag* _tag, bigtime_t* _tagged_time, 543 uint32* _flags, uint32 flags) 544 { 545 CALLED(); 546 if (IS_INVALID_DESTINATION(destination)) 547 return B_MEDIA_BAD_DESTINATION; 548 549 consumer_seek_tag_requested_request request; 550 consumer_seek_tag_requested_reply reply; 551 552 request.destination = destination; 553 request.target_time = targetTime; 554 request.flags = flags; 555 556 status_t status = QueryPort(destination.port, CONSUMER_SEEK_TAG_REQUESTED, 557 &request, sizeof(request), &reply, sizeof(reply)); 558 if (status != B_OK) 559 return status; 560 561 *_tag = reply.seek_tag; 562 *_tagged_time = reply.tagged_time; 563 *_flags = reply.flags; 564 return B_OK; 565 } 566 567 568 void 569 BBufferProducer::SetInitialLatency(bigtime_t initialLatency, uint32 flags) 570 { 571 fInitialLatency = initialLatency; 572 fInitialFlags = flags; 573 } 574 575 576 // #pragma mark - private BBufferProducer 577 578 579 /* 580 private unimplemented 581 BBufferProducer::BBufferProducer() 582 BBufferProducer::BBufferProducer(const BBufferProducer &clone) 583 BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone) 584 */ 585 586 status_t BBufferProducer::_Reserved_BufferProducer_0(void*) { return B_ERROR; } 587 status_t BBufferProducer::_Reserved_BufferProducer_1(void*) { return B_ERROR; } 588 status_t BBufferProducer::_Reserved_BufferProducer_2(void*) { return B_ERROR; } 589 status_t BBufferProducer::_Reserved_BufferProducer_3(void*) { return B_ERROR; } 590 status_t BBufferProducer::_Reserved_BufferProducer_4(void*) { return B_ERROR; } 591 status_t BBufferProducer::_Reserved_BufferProducer_5(void*) { return B_ERROR; } 592 status_t BBufferProducer::_Reserved_BufferProducer_6(void*) { return B_ERROR; } 593 status_t BBufferProducer::_Reserved_BufferProducer_7(void*) { return B_ERROR; } 594 status_t BBufferProducer::_Reserved_BufferProducer_8(void*) { return B_ERROR; } 595 status_t BBufferProducer::_Reserved_BufferProducer_9(void*) { return B_ERROR; } 596 status_t BBufferProducer::_Reserved_BufferProducer_10(void*) { return B_ERROR; } 597 status_t BBufferProducer::_Reserved_BufferProducer_11(void*) { return B_ERROR; } 598 status_t BBufferProducer::_Reserved_BufferProducer_12(void*) { return B_ERROR; } 599 status_t BBufferProducer::_Reserved_BufferProducer_13(void*) { return B_ERROR; } 600 status_t BBufferProducer::_Reserved_BufferProducer_14(void*) { return B_ERROR; } 601 status_t BBufferProducer::_Reserved_BufferProducer_15(void*) { return B_ERROR; } 602 603 604 //! Deprecated. 605 status_t 606 BBufferProducer::SendBuffer(BBuffer* buffer, 607 const media_destination& destination) 608 { 609 CALLED(); 610 611 // Try to find the source - this is the best we can do 612 media_output output; 613 int32 cookie = 0; 614 status_t status = GetNextOutput(&cookie, &output); 615 if (status != B_OK) 616 return status; 617 618 return SendBuffer(buffer, output.source, destination); 619 } 620 621 622 status_t 623 BBufferProducer::clip_shorts_to_region(const int16* data, int count, 624 BRegion* output) 625 { 626 UNIMPLEMENTED(); 627 return B_ERROR; 628 } 629 630 631 status_t 632 BBufferProducer::clip_region_to_shorts(const BRegion* input, int16* data, 633 int maxCount, int* _count) 634 { 635 UNIMPLEMENTED(); 636 return B_ERROR; 637 } 638