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