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 <BufferConsumer.h> 31 #include <BufferProducer.h> 32 #include <BufferGroup.h> 33 #include <Buffer.h> 34 #include <TimeSource.h> //for debugging 35 #include <malloc.h> 36 #include "debug.h" 37 #include "MediaMisc.h" 38 #include "DataExchange.h" 39 #include "BufferIdCache.h" 40 41 /************************************************************* 42 * protected BBufferConsumer 43 *************************************************************/ 44 45 /* virtual */ 46 BBufferConsumer::~BBufferConsumer() 47 { 48 CALLED(); 49 delete fBufferCache; 50 if (fDeleteBufferGroup) 51 delete fDeleteBufferGroup; 52 } 53 54 55 /************************************************************* 56 * public BBufferConsumer 57 *************************************************************/ 58 59 media_type 60 BBufferConsumer::ConsumerType() 61 { 62 CALLED(); 63 return fConsumerType; 64 } 65 66 67 /* static */ status_t 68 BBufferConsumer::RegionToClipData(const BRegion *region, 69 int32 *format, 70 int32 *ioSize, 71 void *data) 72 { 73 CALLED(); 74 75 status_t rv; 76 int count; 77 78 count = *ioSize / sizeof(int16); 79 rv = BBufferProducer::clip_region_to_shorts(region, static_cast<int16 *>(data), count, &count); 80 *ioSize = count * sizeof(int16); 81 *format = BBufferProducer::B_CLIP_SHORT_RUNS; 82 83 return rv; 84 } 85 86 /************************************************************* 87 * protected BBufferConsumer 88 *************************************************************/ 89 90 /* explicit */ 91 BBufferConsumer::BBufferConsumer(media_type consumer_type) : 92 BMediaNode("called by BBufferConsumer"), 93 fConsumerType(consumer_type), 94 fBufferCache(new _buffer_id_cache), 95 fDeleteBufferGroup(0) 96 { 97 CALLED(); 98 99 AddNodeKind(B_BUFFER_CONSUMER); 100 } 101 102 103 /* static */ void 104 BBufferConsumer::NotifyLateProducer(const media_source &what_source, 105 bigtime_t how_much, 106 bigtime_t performance_time) 107 { 108 CALLED(); 109 if (IS_INVALID_SOURCE(what_source)) 110 return; 111 112 producer_late_notice_received_command command; 113 command.source = what_source; 114 command.how_much = how_much; 115 command.performance_time = performance_time; 116 117 SendToPort(what_source.port, PRODUCER_LATE_NOTICE_RECEIVED, &command, sizeof(command)); 118 } 119 120 121 status_t 122 BBufferConsumer::SetVideoClippingFor(const media_source &output, 123 const media_destination &destination, 124 const int16 *shorts, 125 int32 short_count, 126 const media_video_display_info &display, 127 void *user_data, 128 int32 *change_tag, 129 void *_reserved_) 130 { 131 CALLED(); 132 if (IS_INVALID_SOURCE(output)) 133 return B_MEDIA_BAD_SOURCE; 134 if (IS_INVALID_DESTINATION(destination)) 135 return B_MEDIA_BAD_DESTINATION; 136 if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(producer_video_clipping_changed_command)) / 2) 137 debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n"); 138 139 producer_video_clipping_changed_command *command; 140 size_t size; 141 status_t rv; 142 143 size = sizeof(producer_video_clipping_changed_command) + short_count * sizeof(short); 144 command = static_cast<producer_video_clipping_changed_command *>(malloc(size)); 145 command->source = output; 146 command->destination = destination; 147 command->display = display; 148 command->user_data = user_data; 149 command->change_tag = NewChangeTag(); 150 command->short_count = short_count; 151 memcpy(command->shorts, shorts, short_count * sizeof(short)); 152 if (change_tag != NULL) 153 *change_tag = command->change_tag; 154 155 rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size); 156 free(command); 157 return rv; 158 } 159 160 161 status_t 162 BBufferConsumer::SetOutputEnabled(const media_source &source, 163 const media_destination &destination, 164 bool enabled, 165 void *user_data, 166 int32 *change_tag, 167 void *_reserved_) 168 { 169 CALLED(); 170 if (IS_INVALID_SOURCE(source)) 171 return B_MEDIA_BAD_SOURCE; 172 if (IS_INVALID_DESTINATION(destination)) 173 return B_MEDIA_BAD_DESTINATION; 174 175 producer_enable_output_command command; 176 177 command.source = source; 178 command.destination = destination; 179 command.enabled = enabled; 180 command.user_data = user_data; 181 command.change_tag = NewChangeTag(); 182 if (change_tag != NULL) 183 *change_tag = command.change_tag; 184 185 return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command)); 186 } 187 188 189 status_t 190 BBufferConsumer::RequestFormatChange(const media_source &source, 191 const media_destination &destination, 192 const media_format &to_format, 193 void *user_data, 194 int32 *change_tag, 195 void *_reserved_) 196 { 197 CALLED(); 198 if (IS_INVALID_SOURCE(source)) 199 return B_MEDIA_BAD_SOURCE; 200 if (IS_INVALID_DESTINATION(destination)) 201 return B_MEDIA_BAD_DESTINATION; 202 203 producer_format_change_requested_command command; 204 205 command.source = source; 206 command.destination = destination; 207 command.format = to_format; 208 command.user_data = user_data; 209 command.change_tag = NewChangeTag(); 210 if (change_tag != NULL) 211 *change_tag = command.change_tag; 212 213 return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command)); 214 } 215 216 217 status_t 218 BBufferConsumer::RequestAdditionalBuffer(const media_source &source, 219 BBuffer *prev_buffer, 220 void *_reserved) 221 { 222 CALLED(); 223 if (IS_INVALID_SOURCE(source)) 224 return B_MEDIA_BAD_SOURCE; 225 226 producer_additional_buffer_requested_command command; 227 228 command.source = source; 229 command.prev_buffer = prev_buffer->ID(); 230 command.prev_time = 0; 231 command.has_seek_tag = false; 232 //command.prev_tag = 233 234 return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command)); 235 } 236 237 238 status_t 239 BBufferConsumer::RequestAdditionalBuffer(const media_source &source, 240 bigtime_t start_time, 241 void *_reserved) 242 { 243 CALLED(); 244 if (IS_INVALID_SOURCE(source)) 245 return B_MEDIA_BAD_SOURCE; 246 247 producer_additional_buffer_requested_command command; 248 249 command.source = source; 250 command.prev_buffer = 0; 251 command.prev_time = start_time; 252 command.has_seek_tag = false; 253 //command.prev_tag = 254 255 return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command)); 256 } 257 258 259 status_t 260 BBufferConsumer::SetOutputBuffersFor(const media_source &source, 261 const media_destination &destination, 262 BBufferGroup *group, 263 void *user_data, 264 int32 *change_tag, 265 bool will_reclaim, 266 void *_reserved_) 267 { 268 CALLED(); 269 270 if (IS_INVALID_SOURCE(source)) 271 return B_MEDIA_BAD_SOURCE; 272 if (IS_INVALID_DESTINATION(destination)) 273 return B_MEDIA_BAD_DESTINATION; 274 275 producer_set_buffer_group_command *command; 276 BBuffer **buffers; 277 int32 buffer_count; 278 size_t size; 279 status_t rv; 280 281 if (group == 0) { 282 buffer_count = 0; 283 } else { 284 if (B_OK != group->CountBuffers(&buffer_count)) 285 return B_ERROR; 286 } 287 288 if (buffer_count != 0) { 289 buffers = new BBuffer * [buffer_count]; 290 if (B_OK != group->GetBufferList(buffer_count, buffers)) { 291 delete [] buffers; 292 return B_ERROR; 293 } 294 } else { 295 buffers = NULL; 296 } 297 298 size = sizeof(producer_set_buffer_group_command) + buffer_count * sizeof(media_buffer_id); 299 command = static_cast<producer_set_buffer_group_command *>(malloc(size)); 300 command->source = source; 301 command->destination = destination; 302 command->user_data = user_data; 303 command->change_tag = NewChangeTag(); 304 command->buffer_count = buffer_count; 305 for (int32 i = 0; i < buffer_count; i++) 306 command->buffers[i] = buffers[i]->ID(); 307 308 delete [] buffers; 309 310 if (change_tag != NULL) 311 *change_tag = command->change_tag; 312 313 rv = SendToPort(source.port, PRODUCER_SET_BUFFER_GROUP, command, size); 314 free(command); 315 316 if (rv == B_OK) { 317 if (fDeleteBufferGroup) // XXX will leak memory if port write failed 318 delete fDeleteBufferGroup; 319 fDeleteBufferGroup = will_reclaim ? NULL : group; 320 } 321 return rv; 322 } 323 324 325 status_t 326 BBufferConsumer::SendLatencyChange(const media_source &source, 327 const media_destination &destination, 328 bigtime_t my_new_latency, 329 uint32 flags) 330 { 331 CALLED(); 332 if (IS_INVALID_SOURCE(source)) 333 return B_MEDIA_BAD_SOURCE; 334 if (IS_INVALID_DESTINATION(destination)) 335 return B_MEDIA_BAD_DESTINATION; 336 337 producer_latency_changed_command command; 338 339 command.source = source; 340 command.destination = destination; 341 command.latency = my_new_latency; 342 command.flags = flags; 343 344 TRACE("###### BBufferConsumer::SendLatencyChange: latency from %ld/%ld to %ld/%ld changed to %Ld\n", 345 source.port, source.id, destination.port, destination.id, my_new_latency); 346 347 return SendToPort(source.port, PRODUCER_LATENCY_CHANGED, &command, sizeof(command)); 348 } 349 350 /************************************************************* 351 * protected BBufferConsumer 352 *************************************************************/ 353 354 /* virtual */ status_t 355 BBufferConsumer::HandleMessage(int32 message, 356 const void *data, 357 size_t size) 358 { 359 PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message, ID()); 360 status_t rv; 361 switch (message) { 362 case CONSUMER_ACCEPT_FORMAT: 363 { 364 const consumer_accept_format_request *request = static_cast<const consumer_accept_format_request *>(data); 365 consumer_accept_format_reply reply; 366 reply.format = request->format; 367 rv = AcceptFormat(request->dest, &reply.format); 368 request->SendReply(rv, &reply, sizeof(reply)); 369 return B_OK; 370 } 371 372 case CONSUMER_GET_NEXT_INPUT: 373 { 374 const consumer_get_next_input_request *request = static_cast<const consumer_get_next_input_request *>(data); 375 consumer_get_next_input_reply reply; 376 reply.cookie = request->cookie; 377 rv = GetNextInput(&reply.cookie, &reply.input); 378 request->SendReply(rv, &reply, sizeof(reply)); 379 return B_OK; 380 } 381 382 case CONSUMER_DISPOSE_INPUT_COOKIE: 383 { 384 const consumer_dispose_input_cookie_request *request = static_cast<const consumer_dispose_input_cookie_request *>(data); 385 consumer_dispose_input_cookie_reply reply; 386 DisposeInputCookie(request->cookie); 387 request->SendReply(B_OK, &reply, sizeof(reply)); 388 return B_OK; 389 } 390 391 case CONSUMER_BUFFER_RECEIVED: 392 { 393 const consumer_buffer_received_command *command = static_cast<const consumer_buffer_received_command *>(data); 394 BBuffer *buffer; 395 buffer = fBufferCache->GetBuffer(command->buffer); 396 buffer->SetHeader(&command->header); 397 PRINT(4, "calling BBufferConsumer::BufferReceived buffer %ld at perf %Ld and TimeSource()->Now() is %Ld\n", buffer->Header()->buffer, buffer->Header()->start_time, TimeSource()->Now()); 398 //printf("BBufferConsumer::BufferReceived node %2ld, buffer %2ld, start_time %12Ld with lateness %6Ld\n", ID(), buffer->Header()->buffer, buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time); 399 BufferReceived(buffer); 400 return B_OK; 401 } 402 403 case CONSUMER_PRODUCER_DATA_STATUS: 404 { 405 const consumer_producer_data_status_command *command = static_cast<const consumer_producer_data_status_command *>(data); 406 ProducerDataStatus(command->for_whom, command->status, command->at_performance_time); 407 return B_OK; 408 } 409 410 case CONSUMER_GET_LATENCY_FOR: 411 { 412 const consumer_get_latency_for_request *request = static_cast<const consumer_get_latency_for_request *>(data); 413 consumer_get_latency_for_reply reply; 414 rv = GetLatencyFor(request->for_whom, &reply.latency, &reply.timesource); 415 request->SendReply(rv, &reply, sizeof(reply)); 416 return B_OK; 417 } 418 419 case CONSUMER_CONNECTED: 420 { 421 const consumer_connected_request *request = static_cast<const consumer_connected_request *>(data); 422 consumer_connected_reply reply; 423 reply.input = request->input; 424 rv = Connected(request->input.source, request->input.destination, request->input.format, &reply.input); 425 request->SendReply(rv, &reply, sizeof(reply)); 426 return B_OK; 427 } 428 429 case CONSUMER_DISCONNECTED: 430 { 431 const consumer_disconnected_request *request = static_cast<const consumer_disconnected_request *>(data); 432 consumer_disconnected_reply reply; 433 Disconnected(request->source, request->destination); 434 request->SendReply(B_OK, &reply, sizeof(reply)); 435 return B_OK; 436 } 437 438 case CONSUMER_FORMAT_CHANGED: 439 { 440 const consumer_format_changed_request *request = static_cast<const consumer_format_changed_request *>(data); 441 consumer_format_changed_reply reply; 442 rv = FormatChanged(request->producer, request->consumer, request->change_tag, request->format); 443 request->SendReply(rv, &reply, sizeof(reply)); 444 445 // XXX is this RequestCompleted() correct? 446 node_request_completed_command completedcommand; 447 completedcommand.info.what = media_request_info::B_FORMAT_CHANGED; 448 completedcommand.info.change_tag = request->change_tag; 449 completedcommand.info.status = reply.result; 450 //completedcommand.info.cookie 451 completedcommand.info.user_data = 0; 452 completedcommand.info.source = request->producer; 453 completedcommand.info.destination = request->consumer; 454 completedcommand.info.format = request->format; 455 SendToPort(request->consumer.port, NODE_REQUEST_COMPLETED, &completedcommand, sizeof(completedcommand)); 456 return B_OK; 457 } 458 459 case CONSUMER_SEEK_TAG_REQUESTED: 460 { 461 const consumer_seek_tag_requested_request *request = static_cast<const consumer_seek_tag_requested_request *>(data); 462 consumer_seek_tag_requested_reply reply; 463 rv = SeekTagRequested(request->destination, request->target_time, request->flags, &reply.seek_tag, &reply.tagged_time, &reply.flags); 464 request->SendReply(rv, &reply, sizeof(reply)); 465 return B_OK; 466 } 467 468 }; 469 return B_ERROR; 470 } 471 472 status_t 473 BBufferConsumer::SeekTagRequested(const media_destination &destination, 474 bigtime_t in_target_time, 475 uint32 in_flags, 476 media_seek_tag *out_seek_tag, 477 bigtime_t *out_tagged_time, 478 uint32 *out_flags) 479 { 480 CALLED(); 481 // may be implemented by derived classes 482 return B_ERROR; 483 } 484 485 /************************************************************* 486 * private BBufferConsumer 487 *************************************************************/ 488 489 /* 490 not implemented: 491 BBufferConsumer::BBufferConsumer() 492 BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone) 493 BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone) 494 */ 495 496 /* deprecated function for R4 */ 497 /* static */ status_t 498 BBufferConsumer::SetVideoClippingFor(const media_source &output, 499 const int16 *shorts, 500 int32 short_count, 501 const media_video_display_info &display, 502 int32 *change_tag) 503 { 504 CALLED(); 505 if (IS_INVALID_SOURCE(output)) 506 return B_MEDIA_BAD_SOURCE; 507 if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(producer_video_clipping_changed_command)) / 2) 508 debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n"); 509 510 producer_video_clipping_changed_command *command; 511 size_t size; 512 status_t rv; 513 514 size = sizeof(producer_video_clipping_changed_command) + short_count * sizeof(short); 515 command = static_cast<producer_video_clipping_changed_command *>(malloc(size)); 516 command->source = output; 517 command->destination = media_destination::null; 518 command->display = display; 519 command->user_data = 0; 520 command->change_tag = NewChangeTag(); 521 command->short_count = short_count; 522 memcpy(command->shorts, shorts, short_count * sizeof(short)); 523 if (change_tag != NULL) 524 *change_tag = command->change_tag; 525 526 rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size); 527 free(command); 528 return rv; 529 } 530 531 532 /* deprecated function for R4 */ 533 /* static */ status_t 534 BBufferConsumer::RequestFormatChange(const media_source &source, 535 const media_destination &destination, 536 media_format *in_to_format, 537 int32 *change_tag) 538 { 539 CALLED(); 540 if (IS_INVALID_SOURCE(source)) 541 return B_MEDIA_BAD_SOURCE; 542 if (IS_INVALID_DESTINATION(destination)) 543 return B_MEDIA_BAD_DESTINATION; 544 545 producer_format_change_requested_command command; 546 547 command.source = source; 548 command.destination = destination; 549 command.format = *in_to_format; 550 command.user_data = 0; 551 command.change_tag = NewChangeTag(); 552 if (change_tag != NULL) 553 *change_tag = command.change_tag; 554 555 return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command)); 556 } 557 558 559 /* deprecated function for R4 */ 560 /* static */ status_t 561 BBufferConsumer::SetOutputEnabled(const media_source &source, 562 bool enabled, 563 int32 *change_tag) 564 { 565 CALLED(); 566 if (IS_INVALID_SOURCE(source)) 567 return B_MEDIA_BAD_SOURCE; 568 569 producer_enable_output_command command; 570 571 command.source = source; 572 command.destination = media_destination::null; 573 command.enabled = enabled; 574 command.user_data = 0; 575 command.change_tag = NewChangeTag(); 576 if (change_tag != NULL) 577 *change_tag = command.change_tag; 578 579 return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command)); 580 } 581 582 583 status_t BBufferConsumer::_Reserved_BufferConsumer_0(void *) { return B_ERROR; } 584 status_t BBufferConsumer::_Reserved_BufferConsumer_1(void *) { return B_ERROR; } 585 status_t BBufferConsumer::_Reserved_BufferConsumer_2(void *) { return B_ERROR; } 586 status_t BBufferConsumer::_Reserved_BufferConsumer_3(void *) { return B_ERROR; } 587 status_t BBufferConsumer::_Reserved_BufferConsumer_4(void *) { return B_ERROR; } 588 status_t BBufferConsumer::_Reserved_BufferConsumer_5(void *) { return B_ERROR; } 589 status_t BBufferConsumer::_Reserved_BufferConsumer_6(void *) { return B_ERROR; } 590 status_t BBufferConsumer::_Reserved_BufferConsumer_7(void *) { return B_ERROR; } 591 status_t BBufferConsumer::_Reserved_BufferConsumer_8(void *) { return B_ERROR; } 592 status_t BBufferConsumer::_Reserved_BufferConsumer_9(void *) { return B_ERROR; } 593 status_t BBufferConsumer::_Reserved_BufferConsumer_10(void *) { return B_ERROR; } 594 status_t BBufferConsumer::_Reserved_BufferConsumer_11(void *) { return B_ERROR; } 595 status_t BBufferConsumer::_Reserved_BufferConsumer_12(void *) { return B_ERROR; } 596 status_t BBufferConsumer::_Reserved_BufferConsumer_13(void *) { return B_ERROR; } 597 status_t BBufferConsumer::_Reserved_BufferConsumer_14(void *) { return B_ERROR; } 598 status_t BBufferConsumer::_Reserved_BufferConsumer_15(void *) { return B_ERROR; } 599 600