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