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