2 * Copyright 2010-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2002-2003, Marcus Overhagen, <Marcus@Overhagen.de>.
4 * Distributed under the terms of the MIT License.
9 #include <BufferConsumer.h>
10 #include <BufferGroup.h>
11 #include <BufferProducer.h>
14 #include "DataExchange.h"
15 #include "MediaMisc.h"
18 // #pragma mark - protected BBufferProducer
21 BBufferProducer::~BBufferProducer()
27 // #pragma mark - public BBufferProducer
31 BBufferProducer::ClipDataToRegion(int32 format
, int32 size
, const void* data
,
36 if (format
!= B_CLIP_SHORT_RUNS
)
37 return B_MEDIA_BAD_CLIP_FORMAT
;
39 return clip_shorts_to_region((const int16
*)data
, size
/ sizeof(int16
),
45 BBufferProducer::ProducerType()
52 // #pragma mark - protected BBufferProducer
55 BBufferProducer::BBufferProducer(media_type producer_type
)
57 BMediaNode("called by BBufferProducer"),
58 fProducerType(producer_type
),
65 AddNodeKind(B_BUFFER_PRODUCER
);
70 BBufferProducer::VideoClippingChanged(const media_source
& source
,
71 int16 numShorts
, int16
* clipData
, const media_video_display_info
& display
,
72 int32
* /*_deprecated_*/)
75 // may be implemented by derived classes
81 BBufferProducer::GetLatency(bigtime_t
* _latency
)
84 // The default implementation of GetLatency() finds the maximum
85 // latency of your currently-available outputs by iterating over
86 // them, and returns that value in outLatency
95 while (GetNextOutput(&cookie
, &output
) == B_OK
) {
96 if (output
.destination
== media_destination::null
)
99 if (output
.node
.node
== fNodeID
) {
100 // avoid port writes (deadlock) if loopback connection
101 if (fConsumerThis
== NULL
)
102 fConsumerThis
= dynamic_cast<BBufferConsumer
*>(this);
103 if (fConsumerThis
== NULL
)
107 if (fConsumerThis
->GetLatencyFor(output
.destination
, &latency
,
108 &unused
) == B_OK
&& latency
> *_latency
) {
111 } else if (FindLatencyFor(output
.destination
, &latency
, &unused
)
112 == B_OK
&& latency
> *_latency
) {
116 printf("BBufferProducer::GetLatency: node %" B_PRId32
", name \"%s\" has "
117 "max latency %" B_PRId64
"\n", fNodeID
, fName
, *_latency
);
123 BBufferProducer::SetPlayRate(int32 numer
, int32 denom
)
126 // may be implemented by derived classes
132 BBufferProducer::HandleMessage(int32 message
, const void* data
, size_t size
)
134 PRINT(4, "BBufferProducer::HandleMessage %#lx, node %ld\n", message
,
138 case PRODUCER_SET_RUN_MODE_DELAY
:
140 const producer_set_run_mode_delay_command
* command
141 = static_cast<const producer_set_run_mode_delay_command
*>(data
);
142 // when changing this, also change NODE_SET_RUN_MODE
143 fDelay
= command
->delay
;
144 fRunMode
= command
->mode
;
146 TRACE("PRODUCER_SET_RUN_MODE_DELAY: fDelay now %" B_PRId64
"\n",
149 SetRunMode(fRunMode
);
153 case PRODUCER_FORMAT_SUGGESTION_REQUESTED
:
155 const producer_format_suggestion_requested_request
* request
157 const producer_format_suggestion_requested_request
*>(data
);
158 producer_format_suggestion_requested_reply reply
;
159 status_t status
= FormatSuggestionRequested(request
->type
,
160 request
->quality
, &reply
.format
);
161 request
->SendReply(status
, &reply
, sizeof(reply
));
165 case PRODUCER_FORMAT_PROPOSAL
:
167 const producer_format_proposal_request
* request
168 = static_cast<const producer_format_proposal_request
*>(data
);
169 producer_format_proposal_reply reply
;
170 reply
.format
= request
->format
;
171 status_t status
= FormatProposal(request
->output
, &reply
.format
);
172 request
->SendReply(status
, &reply
, sizeof(reply
));
176 case PRODUCER_PREPARE_TO_CONNECT
:
178 const producer_prepare_to_connect_request
* request
179 = static_cast<const producer_prepare_to_connect_request
*>(data
);
180 producer_prepare_to_connect_reply reply
;
181 reply
.format
= request
->format
;
182 reply
.out_source
= request
->source
;
183 memcpy(reply
.name
, request
->name
, B_MEDIA_NAME_LENGTH
);
184 status_t status
= PrepareToConnect(request
->source
,
185 request
->destination
, &reply
.format
, &reply
.out_source
,
187 request
->SendReply(status
, &reply
, sizeof(reply
));
191 case PRODUCER_CONNECT
:
193 const producer_connect_request
* request
194 = static_cast<const producer_connect_request
*>(data
);
195 producer_connect_reply reply
;
196 memcpy(reply
.name
, request
->name
, B_MEDIA_NAME_LENGTH
);
197 Connect(request
->error
, request
->source
, request
->destination
,
198 request
->format
, reply
.name
);
199 request
->SendReply(B_OK
, &reply
, sizeof(reply
));
203 case PRODUCER_DISCONNECT
:
205 const producer_disconnect_request
* request
206 = static_cast<const producer_disconnect_request
*>(data
);
207 producer_disconnect_reply reply
;
208 Disconnect(request
->source
, request
->destination
);
209 request
->SendReply(B_OK
, &reply
, sizeof(reply
));
213 case PRODUCER_GET_INITIAL_LATENCY
:
215 const producer_get_initial_latency_request
* request
217 const producer_get_initial_latency_request
*>(data
);
218 producer_get_initial_latency_reply reply
;
219 reply
.initial_latency
= fInitialLatency
;
220 reply
.flags
= fInitialFlags
;
221 request
->SendReply(B_OK
, &reply
, sizeof(reply
));
225 case PRODUCER_SET_PLAY_RATE
:
227 const producer_set_play_rate_request
* request
228 = static_cast<const producer_set_play_rate_request
*>(data
);
229 producer_set_play_rate_reply reply
;
230 status_t status
= SetPlayRate(request
->numer
, request
->denom
);
231 request
->SendReply(status
, &reply
, sizeof(reply
));
235 case PRODUCER_GET_LATENCY
:
237 const producer_get_latency_request
* request
238 = static_cast<const producer_get_latency_request
*>(data
);
239 producer_get_latency_reply reply
;
240 status_t status
= GetLatency(&reply
.latency
);
241 request
->SendReply(status
, &reply
, sizeof(reply
));
245 case PRODUCER_GET_NEXT_OUTPUT
:
247 const producer_get_next_output_request
* request
248 = static_cast<const producer_get_next_output_request
*>(data
);
249 producer_get_next_output_reply reply
;
250 reply
.cookie
= request
->cookie
;
251 status_t status
= GetNextOutput(&reply
.cookie
, &reply
.output
);
252 request
->SendReply(status
, &reply
, sizeof(reply
));
256 case PRODUCER_DISPOSE_OUTPUT_COOKIE
:
258 const producer_dispose_output_cookie_request
*request
260 const producer_dispose_output_cookie_request
*>(data
);
261 producer_dispose_output_cookie_reply reply
;
262 DisposeOutputCookie(request
->cookie
);
263 request
->SendReply(B_OK
, &reply
, sizeof(reply
));
267 case PRODUCER_SET_BUFFER_GROUP
:
269 const producer_set_buffer_group_command
* command
270 = static_cast<const producer_set_buffer_group_command
*>(data
);
271 node_request_completed_command replycommand
;
273 group
= command
->buffer_count
!= 0
274 ? new BBufferGroup(command
->buffer_count
, command
->buffers
)
277 if (group
!= NULL
&& group
->InitCheck() != B_OK
) {
278 ERROR("BBufferProducer::HandleMessage PRODUCER_SET_BUFFER_GROUP"
279 " group InitCheck() failed.\n");
283 status_t status
= SetBufferGroup(command
->source
, group
);
284 if (command
->destination
== media_destination::null
)
286 replycommand
.info
.what
287 = media_request_info::B_SET_OUTPUT_BUFFERS_FOR
;
288 replycommand
.info
.change_tag
= command
->change_tag
;
289 replycommand
.info
.status
= status
;
290 replycommand
.info
.cookie
= group
;
291 replycommand
.info
.user_data
= command
->user_data
;
292 replycommand
.info
.source
= command
->source
;
293 replycommand
.info
.destination
= command
->destination
;
294 SendToPort(command
->destination
.port
, NODE_REQUEST_COMPLETED
,
295 &replycommand
, sizeof(replycommand
));
299 case PRODUCER_FORMAT_CHANGE_REQUESTED
:
301 const producer_format_change_requested_command
* command
303 const producer_format_change_requested_command
*>(data
);
304 node_request_completed_command replycommand
;
305 replycommand
.info
.format
= command
->format
;
306 status_t status
= FormatChangeRequested(command
->source
,
307 command
->destination
, &replycommand
.info
.format
, NULL
);
308 if (command
->destination
== media_destination::null
)
310 replycommand
.info
.what
311 = media_request_info::B_REQUEST_FORMAT_CHANGE
;
312 replycommand
.info
.change_tag
= command
->change_tag
;
313 replycommand
.info
.status
= status
;
314 //replycommand.info.cookie
315 replycommand
.info
.user_data
= command
->user_data
;
316 replycommand
.info
.source
= command
->source
;
317 replycommand
.info
.destination
= command
->destination
;
318 SendToPort(command
->destination
.port
, NODE_REQUEST_COMPLETED
,
319 &replycommand
, sizeof(replycommand
));
323 case PRODUCER_VIDEO_CLIPPING_CHANGED
:
325 const producer_video_clipping_changed_command
* command
327 const producer_video_clipping_changed_command
*>(data
);
328 node_request_completed_command replycommand
;
329 status_t status
= VideoClippingChanged(command
->source
,
330 command
->short_count
, (int16
*)command
->shorts
,
331 command
->display
, NULL
);
332 if (command
->destination
== media_destination::null
)
334 replycommand
.info
.what
335 = media_request_info::B_SET_VIDEO_CLIPPING_FOR
;
336 replycommand
.info
.change_tag
= command
->change_tag
;
337 replycommand
.info
.status
= status
;
338 //replycommand.info.cookie
339 replycommand
.info
.user_data
= command
->user_data
;
340 replycommand
.info
.source
= command
->source
;
341 replycommand
.info
.destination
= command
->destination
;
342 replycommand
.info
.format
.type
= B_MEDIA_RAW_VIDEO
;
343 replycommand
.info
.format
.u
.raw_video
.display
= command
->display
;
344 SendToPort(command
->destination
.port
, NODE_REQUEST_COMPLETED
,
345 &replycommand
, sizeof(replycommand
));
349 case PRODUCER_ADDITIONAL_BUFFER_REQUESTED
:
351 const producer_additional_buffer_requested_command
* command
353 const producer_additional_buffer_requested_command
*>(data
);
354 AdditionalBufferRequested(command
->source
, command
->prev_buffer
,
355 command
->prev_time
, command
->has_seek_tag
356 ? &command
->prev_tag
: NULL
);
360 case PRODUCER_LATENCY_CHANGED
:
362 const producer_latency_changed_command
* command
363 = static_cast<const producer_latency_changed_command
*>(data
);
364 LatencyChanged(command
->source
, command
->destination
,
365 command
->latency
, command
->flags
);
369 case PRODUCER_LATE_NOTICE_RECEIVED
:
371 const producer_late_notice_received_command
* command
373 const producer_late_notice_received_command
*>(data
);
374 LateNoticeReceived(command
->source
, command
->how_much
,
375 command
->performance_time
);
379 case PRODUCER_ENABLE_OUTPUT
:
381 const producer_enable_output_command
* command
382 = static_cast<const producer_enable_output_command
*>(data
);
383 node_request_completed_command replycommand
;
384 EnableOutput(command
->source
, command
->enabled
, NULL
);
385 if (command
->destination
== media_destination::null
)
388 replycommand
.info
.what
= media_request_info::B_SET_OUTPUT_ENABLED
;
389 replycommand
.info
.change_tag
= command
->change_tag
;
390 replycommand
.info
.status
= B_OK
;
391 //replycommand.info.cookie
392 replycommand
.info
.user_data
= command
->user_data
;
393 replycommand
.info
.source
= command
->source
;
394 replycommand
.info
.destination
= command
->destination
;
395 //replycommand.info.format
396 SendToPort(command
->destination
.port
, NODE_REQUEST_COMPLETED
,
397 &replycommand
, sizeof(replycommand
));
407 BBufferProducer::AdditionalBufferRequested(const media_source
& source
,
408 media_buffer_id previousBuffer
, bigtime_t previousTime
,
409 const media_seek_tag
* previousTag
)
412 // may be implemented by derived classes
417 BBufferProducer::LatencyChanged(const media_source
& source
,
418 const media_destination
& destination
, bigtime_t newLatency
, uint32 flags
)
421 // may be implemented by derived classes
426 BBufferProducer::SendBuffer(BBuffer
* buffer
, const media_source
& source
,
427 const media_destination
& destination
)
430 if (destination
== media_destination::null
)
431 return B_MEDIA_BAD_DESTINATION
;
432 if (source
== media_source::null
)
433 return B_MEDIA_BAD_SOURCE
;
437 consumer_buffer_received_command command
;
438 command
.buffer
= buffer
->ID();
439 command
.header
= *buffer
->Header();
440 command
.header
.buffer
= command
.buffer
;
441 command
.header
.source_port
= source
.port
;
442 command
.header
.source
= source
.id
;
443 command
.header
.destination
= destination
.id
;
444 command
.header
.owner
= 0; // XXX fill with "buffer owner info area"
445 command
.header
.start_time
+= fDelay
;
446 // time compensation as set by BMediaRoster::SetProducerRunModeDelay()
448 //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);
450 return SendToPort(destination
.port
, CONSUMER_BUFFER_RECEIVED
, &command
,
456 BBufferProducer::SendDataStatus(int32 status
,
457 const media_destination
& destination
, bigtime_t atTime
)
460 if (IS_INVALID_DESTINATION(destination
))
461 return B_MEDIA_BAD_DESTINATION
;
463 consumer_producer_data_status_command command
;
464 command
.for_whom
= destination
;
465 command
.status
= status
;
466 command
.at_performance_time
= atTime
;
468 return SendToPort(destination
.port
, CONSUMER_PRODUCER_DATA_STATUS
, &command
,
474 BBufferProducer::ProposeFormatChange(media_format
* format
,
475 const media_destination
& destination
)
478 if (IS_INVALID_DESTINATION(destination
))
479 return B_MEDIA_BAD_DESTINATION
;
481 consumer_accept_format_request request
;
482 consumer_accept_format_reply reply
;
484 request
.dest
= destination
;
485 request
.format
= *format
;
486 status_t status
= QueryPort(destination
.port
, CONSUMER_ACCEPT_FORMAT
,
487 &request
, sizeof(request
), &reply
, sizeof(reply
));
491 *format
= reply
.format
;
497 BBufferProducer::ChangeFormat(const media_source
& source
,
498 const media_destination
& destination
, media_format
* format
)
501 if (IS_INVALID_SOURCE(source
))
502 return B_MEDIA_BAD_SOURCE
;
503 if (IS_INVALID_DESTINATION(destination
))
504 return B_MEDIA_BAD_DESTINATION
;
506 consumer_format_changed_request request
;
507 consumer_format_changed_reply reply
;
509 request
.producer
= source
;
510 request
.consumer
= destination
;
511 request
.format
= *format
;
513 // we use a request/reply to make this synchronous
514 return QueryPort(destination
.port
, CONSUMER_FORMAT_CHANGED
, &request
,
515 sizeof(request
), &reply
, sizeof(reply
));
520 BBufferProducer::FindLatencyFor(const media_destination
& destination
,
521 bigtime_t
* _latency
, media_node_id
* _timesource
)
524 if (IS_INVALID_DESTINATION(destination
))
525 return B_MEDIA_BAD_DESTINATION
;
527 consumer_get_latency_for_request request
;
528 consumer_get_latency_for_reply reply
;
530 request
.for_whom
= destination
;
532 status_t status
= QueryPort(destination
.port
, CONSUMER_GET_LATENCY_FOR
,
533 &request
, sizeof(request
), &reply
, sizeof(reply
));
537 *_latency
= reply
.latency
;
538 *_timesource
= reply
.timesource
;
544 BBufferProducer::FindSeekTag(const media_destination
& destination
,
545 bigtime_t targetTime
, media_seek_tag
* _tag
, bigtime_t
* _tagged_time
,
546 uint32
* _flags
, uint32 flags
)
549 if (IS_INVALID_DESTINATION(destination
))
550 return B_MEDIA_BAD_DESTINATION
;
552 consumer_seek_tag_requested_request request
;
553 consumer_seek_tag_requested_reply reply
;
555 request
.destination
= destination
;
556 request
.target_time
= targetTime
;
557 request
.flags
= flags
;
559 status_t status
= QueryPort(destination
.port
, CONSUMER_SEEK_TAG_REQUESTED
,
560 &request
, sizeof(request
), &reply
, sizeof(reply
));
564 *_tag
= reply
.seek_tag
;
565 *_tagged_time
= reply
.tagged_time
;
566 *_flags
= reply
.flags
;
572 BBufferProducer::SetInitialLatency(bigtime_t initialLatency
, uint32 flags
)
574 fInitialLatency
= initialLatency
;
575 fInitialFlags
= flags
;
579 // #pragma mark - private BBufferProducer
583 private unimplemented
584 BBufferProducer::BBufferProducer()
585 BBufferProducer::BBufferProducer(const BBufferProducer &clone)
586 BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone)
589 status_t
BBufferProducer::_Reserved_BufferProducer_0(void*) { return B_ERROR
; }
590 status_t
BBufferProducer::_Reserved_BufferProducer_1(void*) { return B_ERROR
; }
591 status_t
BBufferProducer::_Reserved_BufferProducer_2(void*) { return B_ERROR
; }
592 status_t
BBufferProducer::_Reserved_BufferProducer_3(void*) { return B_ERROR
; }
593 status_t
BBufferProducer::_Reserved_BufferProducer_4(void*) { return B_ERROR
; }
594 status_t
BBufferProducer::_Reserved_BufferProducer_5(void*) { return B_ERROR
; }
595 status_t
BBufferProducer::_Reserved_BufferProducer_6(void*) { return B_ERROR
; }
596 status_t
BBufferProducer::_Reserved_BufferProducer_7(void*) { return B_ERROR
; }
597 status_t
BBufferProducer::_Reserved_BufferProducer_8(void*) { return B_ERROR
; }
598 status_t
BBufferProducer::_Reserved_BufferProducer_9(void*) { return B_ERROR
; }
599 status_t
BBufferProducer::_Reserved_BufferProducer_10(void*) { return B_ERROR
; }
600 status_t
BBufferProducer::_Reserved_BufferProducer_11(void*) { return B_ERROR
; }
601 status_t
BBufferProducer::_Reserved_BufferProducer_12(void*) { return B_ERROR
; }
602 status_t
BBufferProducer::_Reserved_BufferProducer_13(void*) { return B_ERROR
; }
603 status_t
BBufferProducer::_Reserved_BufferProducer_14(void*) { return B_ERROR
; }
604 status_t
BBufferProducer::_Reserved_BufferProducer_15(void*) { return B_ERROR
; }
609 BBufferProducer::SendBuffer(BBuffer
* buffer
,
610 const media_destination
& destination
)
614 // Try to find the source - this is the best we can do
617 status_t status
= GetNextOutput(&cookie
, &output
);
621 return SendBuffer(buffer
, output
.source
, destination
);
626 BBufferProducer::clip_shorts_to_region(const int16
* data
, int count
,
635 BBufferProducer::clip_region_to_shorts(const BRegion
* input
, int16
* data
,
636 int maxCount
, int* _count
)