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