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 status_t status = SetBufferGroup(command->source, group); 274 if (command->destination == media_destination::null) 275 return B_OK; 276 replycommand.info.what 277 = media_request_info::B_SET_OUTPUT_BUFFERS_FOR; 278 replycommand.info.change_tag = command->change_tag; 279 replycommand.info.status = status; 280 replycommand.info.cookie = group; 281 replycommand.info.user_data = command->user_data; 282 replycommand.info.source = command->source; 283 replycommand.info.destination = command->destination; 284 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 285 &replycommand, sizeof(replycommand)); 286 return B_OK; 287 } 288 289 case PRODUCER_FORMAT_CHANGE_REQUESTED: 290 { 291 const producer_format_change_requested_command* command 292 = static_cast< 293 const producer_format_change_requested_command*>(data); 294 node_request_completed_command replycommand; 295 replycommand.info.format = command->format; 296 status_t status = FormatChangeRequested(command->source, 297 command->destination, &replycommand.info.format, NULL); 298 if (command->destination == media_destination::null) 299 return B_OK; 300 replycommand.info.what 301 = media_request_info::B_REQUEST_FORMAT_CHANGE; 302 replycommand.info.change_tag = command->change_tag; 303 replycommand.info.status = status; 304 //replycommand.info.cookie 305 replycommand.info.user_data = command->user_data; 306 replycommand.info.source = command->source; 307 replycommand.info.destination = command->destination; 308 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 309 &replycommand, sizeof(replycommand)); 310 return B_OK; 311 } 312 313 case PRODUCER_VIDEO_CLIPPING_CHANGED: 314 { 315 const producer_video_clipping_changed_command* command 316 = static_cast< 317 const producer_video_clipping_changed_command*>(data); 318 node_request_completed_command replycommand; 319 status_t status = VideoClippingChanged(command->source, 320 command->short_count, (int16 *)command->shorts, 321 command->display, NULL); 322 if (command->destination == media_destination::null) 323 return B_OK; 324 replycommand.info.what 325 = media_request_info::B_SET_VIDEO_CLIPPING_FOR; 326 replycommand.info.change_tag = command->change_tag; 327 replycommand.info.status = status; 328 //replycommand.info.cookie 329 replycommand.info.user_data = command->user_data; 330 replycommand.info.source = command->source; 331 replycommand.info.destination = command->destination; 332 replycommand.info.format.type = B_MEDIA_RAW_VIDEO; 333 replycommand.info.format.u.raw_video.display = command->display; 334 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 335 &replycommand, sizeof(replycommand)); 336 return B_OK; 337 } 338 339 case PRODUCER_ADDITIONAL_BUFFER_REQUESTED: 340 { 341 const producer_additional_buffer_requested_command* command 342 = static_cast< 343 const producer_additional_buffer_requested_command*>(data); 344 AdditionalBufferRequested(command->source, command->prev_buffer, 345 command->prev_time, command->has_seek_tag 346 ? &command->prev_tag : NULL); 347 return B_OK; 348 } 349 350 case PRODUCER_LATENCY_CHANGED: 351 { 352 const producer_latency_changed_command* command 353 = static_cast<const producer_latency_changed_command*>(data); 354 LatencyChanged(command->source, command->destination, 355 command->latency, command->flags); 356 return B_OK; 357 } 358 359 case PRODUCER_LATE_NOTICE_RECEIVED: 360 { 361 const producer_late_notice_received_command* command 362 = static_cast< 363 const producer_late_notice_received_command*>(data); 364 LateNoticeReceived(command->source, command->how_much, 365 command->performance_time); 366 return B_OK; 367 } 368 369 case PRODUCER_ENABLE_OUTPUT: 370 { 371 const producer_enable_output_command* command 372 = static_cast<const producer_enable_output_command*>(data); 373 node_request_completed_command replycommand; 374 EnableOutput(command->source, command->enabled, NULL); 375 if (command->destination == media_destination::null) 376 return B_OK; 377 378 replycommand.info.what = media_request_info::B_SET_OUTPUT_ENABLED; 379 replycommand.info.change_tag = command->change_tag; 380 replycommand.info.status = B_OK; 381 //replycommand.info.cookie 382 replycommand.info.user_data = command->user_data; 383 replycommand.info.source = command->source; 384 replycommand.info.destination = command->destination; 385 //replycommand.info.format 386 SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, 387 &replycommand, sizeof(replycommand)); 388 return B_OK; 389 } 390 } 391 392 return B_ERROR; 393 } 394 395 396 void 397 BBufferProducer::AdditionalBufferRequested(const media_source& source, 398 media_buffer_id previousBuffer, bigtime_t previousTime, 399 const media_seek_tag* previousTag) 400 { 401 CALLED(); 402 // may be implemented by derived classes 403 } 404 405 406 void 407 BBufferProducer::LatencyChanged(const media_source& source, 408 const media_destination& destination, bigtime_t newLatency, uint32 flags) 409 { 410 CALLED(); 411 // may be implemented by derived classes 412 } 413 414 415 status_t 416 BBufferProducer::SendBuffer(BBuffer* buffer, const media_source& source, 417 const media_destination& destination) 418 { 419 CALLED(); 420 if (destination == media_destination::null) 421 return B_MEDIA_BAD_DESTINATION; 422 if (source == media_source::null) 423 return B_MEDIA_BAD_SOURCE; 424 if (buffer == NULL) 425 return B_BAD_VALUE; 426 427 consumer_buffer_received_command command; 428 command.buffer = buffer->ID(); 429 command.header = *buffer->Header(); 430 command.header.buffer = command.buffer; 431 command.header.source_port = source.port; 432 command.header.source = source.id; 433 command.header.destination = destination.id; 434 command.header.owner = 0; // XXX fill with "buffer owner info area" 435 command.header.start_time += fDelay; 436 // time compensation as set by BMediaRoster::SetProducerRunModeDelay() 437 438 //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); 439 440 return SendToPort(destination.port, CONSUMER_BUFFER_RECEIVED, &command, 441 sizeof(command)); 442 } 443 444 445 status_t 446 BBufferProducer::SendDataStatus(int32 status, 447 const media_destination& destination, bigtime_t atTime) 448 { 449 CALLED(); 450 if (IS_INVALID_DESTINATION(destination)) 451 return B_MEDIA_BAD_DESTINATION; 452 453 consumer_producer_data_status_command command; 454 command.for_whom = destination; 455 command.status = status; 456 command.at_performance_time = atTime; 457 458 return SendToPort(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &command, 459 sizeof(command)); 460 } 461 462 463 status_t 464 BBufferProducer::ProposeFormatChange(media_format* format, 465 const media_destination& destination) 466 { 467 CALLED(); 468 if (IS_INVALID_DESTINATION(destination)) 469 return B_MEDIA_BAD_DESTINATION; 470 471 consumer_accept_format_request request; 472 consumer_accept_format_reply reply; 473 474 request.dest = destination; 475 request.format = *format; 476 status_t status = QueryPort(destination.port, CONSUMER_ACCEPT_FORMAT, 477 &request, sizeof(request), &reply, sizeof(reply)); 478 if (status != B_OK) 479 return status; 480 481 *format = reply.format; 482 return B_OK; 483 } 484 485 486 status_t 487 BBufferProducer::ChangeFormat(const media_source& source, 488 const media_destination& destination, media_format* format) 489 { 490 CALLED(); 491 if (IS_INVALID_SOURCE(source)) 492 return B_MEDIA_BAD_SOURCE; 493 if (IS_INVALID_DESTINATION(destination)) 494 return B_MEDIA_BAD_DESTINATION; 495 496 consumer_format_changed_request request; 497 consumer_format_changed_reply reply; 498 499 request.producer = source; 500 request.consumer = destination; 501 request.format = *format; 502 503 // we use a request/reply to make this synchronous 504 return QueryPort(destination.port, CONSUMER_FORMAT_CHANGED, &request, 505 sizeof(request), &reply, sizeof(reply)); 506 } 507 508 509 status_t 510 BBufferProducer::FindLatencyFor(const media_destination& destination, 511 bigtime_t* _latency, media_node_id* _timesource) 512 { 513 CALLED(); 514 if (IS_INVALID_DESTINATION(destination)) 515 return B_MEDIA_BAD_DESTINATION; 516 517 consumer_get_latency_for_request request; 518 consumer_get_latency_for_reply reply; 519 520 request.for_whom = destination; 521 522 status_t status = QueryPort(destination.port, CONSUMER_GET_LATENCY_FOR, 523 &request, sizeof(request), &reply, sizeof(reply)); 524 if (status != B_OK) 525 return status; 526 527 *_latency = reply.latency; 528 *_timesource = reply.timesource; 529 return B_OK; 530 } 531 532 533 status_t 534 BBufferProducer::FindSeekTag(const media_destination& destination, 535 bigtime_t targetTime, media_seek_tag* _tag, bigtime_t* _tagged_time, 536 uint32* _flags, uint32 flags) 537 { 538 CALLED(); 539 if (IS_INVALID_DESTINATION(destination)) 540 return B_MEDIA_BAD_DESTINATION; 541 542 consumer_seek_tag_requested_request request; 543 consumer_seek_tag_requested_reply reply; 544 545 request.destination = destination; 546 request.target_time = targetTime; 547 request.flags = flags; 548 549 status_t status = QueryPort(destination.port, CONSUMER_SEEK_TAG_REQUESTED, 550 &request, sizeof(request), &reply, sizeof(reply)); 551 if (status != B_OK) 552 return status; 553 554 *_tag = reply.seek_tag; 555 *_tagged_time = reply.tagged_time; 556 *_flags = reply.flags; 557 return B_OK; 558 } 559 560 561 void 562 BBufferProducer::SetInitialLatency(bigtime_t initialLatency, uint32 flags) 563 { 564 fInitialLatency = initialLatency; 565 fInitialFlags = flags; 566 } 567 568 569 // #pragma mark - private BBufferProducer 570 571 572 /* 573 private unimplemented 574 BBufferProducer::BBufferProducer() 575 BBufferProducer::BBufferProducer(const BBufferProducer &clone) 576 BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone) 577 */ 578 579 status_t BBufferProducer::_Reserved_BufferProducer_0(void*) { return B_ERROR; } 580 status_t BBufferProducer::_Reserved_BufferProducer_1(void*) { return B_ERROR; } 581 status_t BBufferProducer::_Reserved_BufferProducer_2(void*) { return B_ERROR; } 582 status_t BBufferProducer::_Reserved_BufferProducer_3(void*) { return B_ERROR; } 583 status_t BBufferProducer::_Reserved_BufferProducer_4(void*) { return B_ERROR; } 584 status_t BBufferProducer::_Reserved_BufferProducer_5(void*) { return B_ERROR; } 585 status_t BBufferProducer::_Reserved_BufferProducer_6(void*) { return B_ERROR; } 586 status_t BBufferProducer::_Reserved_BufferProducer_7(void*) { return B_ERROR; } 587 status_t BBufferProducer::_Reserved_BufferProducer_8(void*) { return B_ERROR; } 588 status_t BBufferProducer::_Reserved_BufferProducer_9(void*) { return B_ERROR; } 589 status_t BBufferProducer::_Reserved_BufferProducer_10(void*) { return B_ERROR; } 590 status_t BBufferProducer::_Reserved_BufferProducer_11(void*) { return B_ERROR; } 591 status_t BBufferProducer::_Reserved_BufferProducer_12(void*) { return B_ERROR; } 592 status_t BBufferProducer::_Reserved_BufferProducer_13(void*) { return B_ERROR; } 593 status_t BBufferProducer::_Reserved_BufferProducer_14(void*) { return B_ERROR; } 594 status_t BBufferProducer::_Reserved_BufferProducer_15(void*) { return B_ERROR; } 595 596 597 //! Deprecated. 598 status_t 599 BBufferProducer::SendBuffer(BBuffer* buffer, 600 const media_destination& destination) 601 { 602 CALLED(); 603 604 // Try to find the source - this is the best we can do 605 media_output output; 606 int32 cookie = 0; 607 status_t status = GetNextOutput(&cookie, &output); 608 if (status != B_OK) 609 return status; 610 611 return SendBuffer(buffer, output.source, destination); 612 } 613 614 615 status_t 616 BBufferProducer::clip_shorts_to_region(const int16* data, int count, 617 BRegion* output) 618 { 619 UNIMPLEMENTED(); 620 return B_ERROR; 621 } 622 623 624 status_t 625 BBufferProducer::clip_region_to_shorts(const BRegion* input, int16* data, 626 int maxCount, int* _count) 627 { 628 UNIMPLEMENTED(); 629 return B_ERROR; 630 } 631