2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
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:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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
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
30 #include "BufferCache.h"
31 #include <BufferConsumer.h>
36 #include <AutoDeleter.h>
37 #include <BufferProducer.h>
38 #include <BufferGroup.h>
40 #include <TimeSource.h>
43 #include <MediaMisc.h>
44 #include <DataExchange.h>
48 BBufferConsumer::~BBufferConsumer()
52 delete fDeleteBufferGroup
;
56 // #pragma mark - public BBufferConsumer
60 BBufferConsumer::ConsumerType()
68 BBufferConsumer::RegionToClipData(const BRegion
* region
, int32
* _format
,
69 int32
*_size
, void* data
)
73 int count
= *_size
/ sizeof(int16
);
74 status_t status
= BBufferProducer::clip_region_to_shorts(region
,
75 static_cast<int16
*>(data
), count
, &count
);
77 *_size
= count
* sizeof(int16
);
78 *_format
= BBufferProducer::B_CLIP_SHORT_RUNS
;
84 // #pragma mark - protected BBufferConsumer
87 BBufferConsumer::BBufferConsumer(media_type consumerType
)
89 BMediaNode("called by BBufferConsumer"),
90 fConsumerType(consumerType
),
91 fBufferCache(new BPrivate::BufferCache
),
96 AddNodeKind(B_BUFFER_CONSUMER
);
101 BBufferConsumer::NotifyLateProducer(const media_source
& whatSource
,
102 bigtime_t howMuch
, bigtime_t performanceTime
)
105 if (IS_INVALID_SOURCE(whatSource
))
108 producer_late_notice_received_command command
;
109 command
.source
= whatSource
;
110 command
.how_much
= howMuch
;
111 command
.performance_time
= performanceTime
;
113 SendToPort(whatSource
.port
, PRODUCER_LATE_NOTICE_RECEIVED
, &command
,
119 BBufferConsumer::SetVideoClippingFor(const media_source
& output
,
120 const media_destination
& destination
, const int16
* shorts
, int32 shortCount
,
121 const media_video_display_info
& display
, void* userData
, int32
* _changeTag
,
125 if (IS_INVALID_SOURCE(output
))
126 return B_MEDIA_BAD_SOURCE
;
127 if (IS_INVALID_DESTINATION(destination
))
128 return B_MEDIA_BAD_DESTINATION
;
129 if (shortCount
> int(B_MEDIA_MESSAGE_SIZE
130 - sizeof(producer_video_clipping_changed_command
)) / 2) {
131 debugger("BBufferConsumer::SetVideoClippingFor short_count too large "
135 producer_video_clipping_changed_command
* command
;
136 size_t size
= sizeof(producer_video_clipping_changed_command
)
137 + shortCount
* sizeof(short);
139 = static_cast<producer_video_clipping_changed_command
*>(malloc(size
));
143 command
->source
= output
;
144 command
->destination
= destination
;
145 command
->display
= display
;
146 command
->user_data
= userData
;
147 command
->change_tag
= NewChangeTag();
148 command
->short_count
= shortCount
;
149 memcpy(command
->shorts
, shorts
, shortCount
* sizeof(short));
150 if (_changeTag
!= NULL
)
151 *_changeTag
= command
->change_tag
;
153 status_t status
= SendToPort(output
.port
, PRODUCER_VIDEO_CLIPPING_CHANGED
,
162 BBufferConsumer::SetOutputEnabled(const media_source
&source
,
163 const media_destination
&destination
,
170 if (IS_INVALID_SOURCE(source
))
171 return B_MEDIA_BAD_SOURCE
;
172 if (IS_INVALID_DESTINATION(destination
))
173 return B_MEDIA_BAD_DESTINATION
;
175 producer_enable_output_command command
;
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
;
185 return SendToPort(source
.port
, PRODUCER_ENABLE_OUTPUT
, &command
, sizeof(command
));
190 BBufferConsumer::RequestFormatChange(const media_source
&source
,
191 const media_destination
&destination
,
192 const media_format
&to_format
,
198 if (IS_INVALID_SOURCE(source
))
199 return B_MEDIA_BAD_SOURCE
;
200 if (IS_INVALID_DESTINATION(destination
))
201 return B_MEDIA_BAD_DESTINATION
;
203 producer_format_change_requested_command command
;
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
;
213 return SendToPort(source
.port
, PRODUCER_FORMAT_CHANGE_REQUESTED
, &command
, sizeof(command
));
218 BBufferConsumer::RequestAdditionalBuffer(const media_source
&source
,
219 BBuffer
*prev_buffer
,
223 if (IS_INVALID_SOURCE(source
))
224 return B_MEDIA_BAD_SOURCE
;
226 producer_additional_buffer_requested_command command
;
228 command
.source
= source
;
229 command
.prev_buffer
= prev_buffer
->ID();
230 command
.prev_time
= 0;
231 command
.has_seek_tag
= false;
234 return SendToPort(source
.port
, PRODUCER_ADDITIONAL_BUFFER_REQUESTED
, &command
, sizeof(command
));
239 BBufferConsumer::RequestAdditionalBuffer(const media_source
& source
,
240 bigtime_t startTime
, void *_reserved
)
243 if (IS_INVALID_SOURCE(source
))
244 return B_MEDIA_BAD_SOURCE
;
246 producer_additional_buffer_requested_command command
;
248 command
.source
= source
;
249 command
.prev_buffer
= 0;
250 command
.prev_time
= startTime
;
251 command
.has_seek_tag
= false;
253 return SendToPort(source
.port
, PRODUCER_ADDITIONAL_BUFFER_REQUESTED
,
254 &command
, sizeof(command
));
259 BBufferConsumer::SetOutputBuffersFor(const media_source
&source
,
260 const media_destination
&destination
, BBufferGroup
*group
, void *user_data
,
261 int32
*change_tag
, bool will_reclaim
, void *_reserved_
)
265 if (IS_INVALID_SOURCE(source
))
266 return B_MEDIA_BAD_SOURCE
;
267 if (IS_INVALID_DESTINATION(destination
))
268 return B_MEDIA_BAD_DESTINATION
;
270 int32 buffer_count
= 0;
273 if (group
->CountBuffers(&buffer_count
) != B_OK
)
277 size_t size
= sizeof(producer_set_buffer_group_command
)
278 + buffer_count
* sizeof(media_buffer_id
);
280 producer_set_buffer_group_command
*command
281 = static_cast<producer_set_buffer_group_command
*>(malloc(size
));
282 MemoryDeleter
deleter(command
);
284 command
->source
= source
;
285 command
->destination
= destination
;
286 command
->user_data
= user_data
;
287 command
->change_tag
= NewChangeTag();
289 BBuffer
*buffers
[buffer_count
];
290 if (buffer_count
!= 0) {
291 if (group
->GetBufferList(buffer_count
, buffers
) != B_OK
)
293 for (int32 i
= 0; i
< buffer_count
; i
++)
294 command
->buffers
[i
] = buffers
[i
]->ID();
297 command
->buffer_count
= buffer_count
;
299 if (change_tag
!= NULL
)
300 *change_tag
= command
->change_tag
;
302 status_t status
= SendToPort(source
.port
, PRODUCER_SET_BUFFER_GROUP
,
305 if (status
== B_OK
) {
306 // XXX will leak memory if port write failed
307 delete fDeleteBufferGroup
;
308 fDeleteBufferGroup
= will_reclaim
? NULL
: group
;
315 BBufferConsumer::SendLatencyChange(const media_source
& source
,
316 const media_destination
& destination
, bigtime_t newLatency
, uint32 flags
)
319 if (IS_INVALID_SOURCE(source
))
320 return B_MEDIA_BAD_SOURCE
;
321 if (IS_INVALID_DESTINATION(destination
))
322 return B_MEDIA_BAD_DESTINATION
;
324 producer_latency_changed_command command
;
326 command
.source
= source
;
327 command
.destination
= destination
;
328 command
.latency
= newLatency
;
329 command
.flags
= flags
;
331 TRACE("###### BBufferConsumer::SendLatencyChange: latency from %ld/%ld to "
332 "%ld/%ld changed to %Ld\n", source
.port
, source
.id
, destination
.port
,
333 destination
.id
, newLatency
);
335 return SendToPort(source
.port
, PRODUCER_LATENCY_CHANGED
, &command
,
341 BBufferConsumer::HandleMessage(int32 message
, const void* data
, size_t size
)
343 PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message
, ID());
346 case CONSUMER_ACCEPT_FORMAT
:
348 const consumer_accept_format_request
* request
349 = static_cast<const consumer_accept_format_request
*>(data
);
351 consumer_accept_format_reply reply
;
352 reply
.format
= request
->format
;
353 status_t status
= AcceptFormat(request
->dest
, &reply
.format
);
354 request
->SendReply(status
, &reply
, sizeof(reply
));
358 case CONSUMER_GET_NEXT_INPUT
:
360 const consumer_get_next_input_request
*request
= static_cast<const consumer_get_next_input_request
*>(data
);
361 consumer_get_next_input_reply reply
;
362 reply
.cookie
= request
->cookie
;
363 rv
= GetNextInput(&reply
.cookie
, &reply
.input
);
364 request
->SendReply(rv
, &reply
, sizeof(reply
));
368 case CONSUMER_DISPOSE_INPUT_COOKIE
:
370 const consumer_dispose_input_cookie_request
*request
= static_cast<const consumer_dispose_input_cookie_request
*>(data
);
371 consumer_dispose_input_cookie_reply reply
;
372 DisposeInputCookie(request
->cookie
);
373 request
->SendReply(B_OK
, &reply
, sizeof(reply
));
377 case CONSUMER_BUFFER_RECEIVED
:
379 const consumer_buffer_received_command
* command
380 = static_cast<const consumer_buffer_received_command
*>(data
);
382 BBuffer
* buffer
= fBufferCache
->GetBuffer(command
->buffer
);
383 if (buffer
== NULL
) {
384 ERROR("BBufferConsumer::CONSUMER_BUFFER_RECEIVED can't"
385 "find the buffer\n");
387 buffer
->SetHeader(&command
->header
);
389 PRINT(4, "calling BBufferConsumer::BufferReceived buffer %ld "
390 "at perf %Ld and TimeSource()->Now() is %Ld\n",
391 buffer
->Header()->buffer
, buffer
->Header()->start_time
,
392 TimeSource()->Now());
394 BufferReceived(buffer
);
399 case CONSUMER_PRODUCER_DATA_STATUS
:
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
);
406 case CONSUMER_GET_LATENCY_FOR
:
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
));
415 case CONSUMER_CONNECTED
:
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
));
425 case CONSUMER_DISCONNECTED
:
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
));
434 case CONSUMER_FORMAT_CHANGED
:
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
));
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
));
455 case CONSUMER_SEEK_TAG_REQUESTED
:
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
));
468 BBufferConsumer::SeekTagRequested(const media_destination
&destination
,
469 bigtime_t in_target_time
,
471 media_seek_tag
*out_seek_tag
,
472 bigtime_t
*out_tagged_time
,
476 // may be implemented by derived classes
481 // #pragma mark - private BBufferConsumer
486 BBufferConsumer::BBufferConsumer()
487 BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone)
488 BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone)
492 /*! Deprecated function for BeOS R4.
494 /* static */ status_t
495 BBufferConsumer::SetVideoClippingFor(const media_source
&output
,
498 const media_video_display_info
&display
,
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");
507 producer_video_clipping_changed_command
*command
;
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
;
523 rv
= SendToPort(output
.port
, PRODUCER_VIDEO_CLIPPING_CHANGED
, command
, size
);
529 /*! Deprecated function for BeOS R4.
532 BBufferConsumer::RequestFormatChange(const media_source
& source
,
533 const media_destination
& destination
, media_format
* format
,
537 if (IS_INVALID_SOURCE(source
))
538 return B_MEDIA_BAD_SOURCE
;
539 if (IS_INVALID_DESTINATION(destination
))
540 return B_MEDIA_BAD_DESTINATION
;
542 producer_format_change_requested_command command
;
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
;
552 return SendToPort(source
.port
, PRODUCER_FORMAT_CHANGE_REQUESTED
, &command
,
557 /*! Deprecated function for BeOS R4.
560 BBufferConsumer::SetOutputEnabled(const media_source
& source
, bool enabled
,
564 if (IS_INVALID_SOURCE(source
))
565 return B_MEDIA_BAD_SOURCE
;
567 producer_enable_output_command command
;
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
;
577 return SendToPort(source
.port
, PRODUCER_ENABLE_OUTPUT
, &command
,
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
; }