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