headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / media / BufferConsumer.cpp
blob7171140f27dceb47d44b3623d3537a22b1172dbc
1 /*
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
18 * the distribution.
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.
30 #include "BufferCache.h"
31 #include <BufferConsumer.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #include <AutoDeleter.h>
37 #include <BufferProducer.h>
38 #include <BufferGroup.h>
39 #include <Buffer.h>
40 #include <TimeSource.h>
42 #include <debug.h>
43 #include <MediaMisc.h>
44 #include <DataExchange.h>
48 BBufferConsumer::~BBufferConsumer()
50 CALLED();
51 delete fBufferCache;
52 delete fDeleteBufferGroup;
56 // #pragma mark - public BBufferConsumer
59 media_type
60 BBufferConsumer::ConsumerType()
62 CALLED();
63 return fConsumerType;
67 /*static*/ status_t
68 BBufferConsumer::RegionToClipData(const BRegion* region, int32* _format,
69 int32 *_size, void* data)
71 CALLED();
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;
80 return status;
84 // #pragma mark - protected BBufferConsumer
87 BBufferConsumer::BBufferConsumer(media_type consumerType)
89 BMediaNode("called by BBufferConsumer"),
90 fConsumerType(consumerType),
91 fBufferCache(new BPrivate::BufferCache),
92 fDeleteBufferGroup(0)
94 CALLED();
96 AddNodeKind(B_BUFFER_CONSUMER);
100 /*static*/ void
101 BBufferConsumer::NotifyLateProducer(const media_source& whatSource,
102 bigtime_t howMuch, bigtime_t performanceTime)
104 CALLED();
105 if (IS_INVALID_SOURCE(whatSource))
106 return;
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,
114 sizeof(command));
118 status_t
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,
122 void *_reserved_)
124 CALLED();
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 "
132 "(8000 limit)\n");
135 producer_video_clipping_changed_command* command;
136 size_t size = sizeof(producer_video_clipping_changed_command)
137 + shortCount * sizeof(short);
138 command
139 = static_cast<producer_video_clipping_changed_command*>(malloc(size));
140 if (command == NULL)
141 return B_NO_MEMORY;
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,
154 command, size);
156 free(command);
157 return status;
161 status_t
162 BBufferConsumer::SetOutputEnabled(const media_source &source,
163 const media_destination &destination,
164 bool enabled,
165 void *user_data,
166 int32 *change_tag,
167 void *_reserved_)
169 CALLED();
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));
189 status_t
190 BBufferConsumer::RequestFormatChange(const media_source &source,
191 const media_destination &destination,
192 const media_format &to_format,
193 void *user_data,
194 int32 *change_tag,
195 void *_reserved_)
197 CALLED();
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));
217 status_t
218 BBufferConsumer::RequestAdditionalBuffer(const media_source &source,
219 BBuffer *prev_buffer,
220 void *_reserved)
222 CALLED();
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;
232 //command.prev_tag =
234 return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command));
238 status_t
239 BBufferConsumer::RequestAdditionalBuffer(const media_source& source,
240 bigtime_t startTime, void *_reserved)
242 CALLED();
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));
258 status_t
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_)
263 CALLED();
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;
272 if (group != NULL) {
273 if (group->CountBuffers(&buffer_count) != B_OK)
274 return B_ERROR;
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)
292 return B_ERROR;
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,
303 command, size);
305 if (status == B_OK) {
306 // XXX will leak memory if port write failed
307 delete fDeleteBufferGroup;
308 fDeleteBufferGroup = will_reclaim ? NULL : group;
310 return status;
314 status_t
315 BBufferConsumer::SendLatencyChange(const media_source& source,
316 const media_destination& destination, bigtime_t newLatency, uint32 flags)
318 CALLED();
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 %" B_PRId32 "/%" B_PRId32 " to "
332 "%" B_PRId32 "/%" B_PRId32 " changed to %" B_PRId64 "\n", source.port, source.id,
333 destination.port, destination.id, newLatency);
335 return SendToPort(source.port, PRODUCER_LATENCY_CHANGED, &command,
336 sizeof(command));
340 status_t
341 BBufferConsumer::HandleMessage(int32 message, const void* data, size_t size)
343 PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message, ID());
344 status_t rv;
345 switch (message) {
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));
355 return B_OK;
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));
365 return B_OK;
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));
374 return B_OK;
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");
386 } else {
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);
396 return B_OK;
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);
403 return B_OK;
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));
412 return B_OK;
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));
422 return B_OK;
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));
431 return B_OK;
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));
452 return B_OK;
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));
461 return B_OK;
464 return B_ERROR;
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)
475 CALLED();
476 // may be implemented by derived classes
477 return B_ERROR;
481 // #pragma mark - private BBufferConsumer
485 not implemented:
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,
496 const int16 *shorts,
497 int32 short_count,
498 const media_video_display_info &display,
499 int32 *change_tag)
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");
507 producer_video_clipping_changed_command *command;
508 size_t size;
509 status_t rv;
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);
524 free(command);
525 return rv;
529 /*! Deprecated function for BeOS R4.
531 /*static*/ status_t
532 BBufferConsumer::RequestFormatChange(const media_source& source,
533 const media_destination& destination, media_format* format,
534 int32* _changeTag)
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;
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,
553 sizeof(command));
557 /*! Deprecated function for BeOS R4.
559 /*static*/ status_t
560 BBufferConsumer::SetOutputEnabled(const media_source& source, bool enabled,
561 int32* _changeTag)
563 CALLED();
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,
578 sizeof(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; }