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