xref: /haiku/src/kits/media/BufferConsumer.cpp (revision e5430a086c769ea76c3944046b1f07cf049c1ae0)
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 /* to comply with the license above, do not remove the following line */
31 static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>";
32 
33 #include <BufferConsumer.h>
34 #include <BufferProducer.h>
35 #include <BufferGroup.h>
36 #include <Buffer.h>
37 #include <TimeSource.h> //for debugging
38 #include <malloc.h>
39 #include "debug.h"
40 #include "MediaMisc.h"
41 #include "DataExchange.h"
42 #include "BufferIdCache.h"
43 
44 /*************************************************************
45  * protected BBufferConsumer
46  *************************************************************/
47 
48 /* virtual */
49 BBufferConsumer::~BBufferConsumer()
50 {
51 	CALLED();
52 	delete fBufferCache;
53 	if (fDeleteBufferGroup)
54 		delete fDeleteBufferGroup;
55 }
56 
57 
58 /*************************************************************
59  * public BBufferConsumer
60  *************************************************************/
61 
62 media_type
63 BBufferConsumer::ConsumerType()
64 {
65 	CALLED();
66 	return fConsumerType;
67 }
68 
69 
70 /* static */ status_t
71 BBufferConsumer::RegionToClipData(const BRegion *region,
72 								  int32 *format,
73 								  int32 *ioSize,
74 								  void *data)
75 {
76 	CALLED();
77 
78 	status_t rv;
79 	int count;
80 
81 	count = *ioSize / sizeof(int16);
82 	rv = BBufferProducer::clip_region_to_shorts(region, static_cast<int16 *>(data), count, &count);
83 	*ioSize	= count * sizeof(int16);
84 	*format = BBufferProducer::B_CLIP_SHORT_RUNS;
85 
86 	return rv;
87 }
88 
89 /*************************************************************
90  * protected BBufferConsumer
91  *************************************************************/
92 
93 /* explicit */
94 BBufferConsumer::BBufferConsumer(media_type consumer_type) :
95 	BMediaNode("called by BBufferConsumer"),
96 	fConsumerType(consumer_type),
97 	fBufferCache(new _buffer_id_cache),
98 	fDeleteBufferGroup(0)
99 {
100 	CALLED();
101 
102 	AddNodeKind(B_BUFFER_CONSUMER);
103 }
104 
105 
106 /* static */ void
107 BBufferConsumer::NotifyLateProducer(const media_source &what_source,
108 									bigtime_t how_much,
109 									bigtime_t performance_time)
110 {
111 	CALLED();
112 	if (IS_INVALID_SOURCE(what_source))
113 		return;
114 
115 	producer_late_notice_received_command command;
116 	command.source = what_source;
117 	command.how_much = how_much;
118 	command.performance_time = performance_time;
119 
120 	SendToPort(what_source.port, PRODUCER_LATE_NOTICE_RECEIVED, &command, sizeof(command));
121 }
122 
123 
124 status_t
125 BBufferConsumer::SetVideoClippingFor(const media_source &output,
126 									 const media_destination &destination,
127 									 const int16 *shorts,
128 									 int32 short_count,
129 									 const media_video_display_info &display,
130 									 void *user_data,
131 									 int32 *change_tag,
132 									 void *_reserved_)
133 {
134 	CALLED();
135 	if (IS_INVALID_SOURCE(output))
136 		return B_MEDIA_BAD_SOURCE;
137 	if (IS_INVALID_DESTINATION(destination))
138 		return B_MEDIA_BAD_DESTINATION;
139 	if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(producer_video_clipping_changed_command)) / 2)
140 		debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n");
141 
142 	producer_video_clipping_changed_command *command;
143 	size_t size;
144 	status_t rv;
145 
146 	size = sizeof(producer_video_clipping_changed_command) + short_count * sizeof(short);
147 	command = static_cast<producer_video_clipping_changed_command *>(malloc(size));
148 	command->source = output;
149 	command->destination = destination;
150 	command->display = display;
151 	command->user_data = user_data;
152 	command->change_tag = NewChangeTag();
153 	command->short_count = short_count;
154 	memcpy(command->shorts, shorts, short_count * sizeof(short));
155 	if (change_tag != NULL)
156 		*change_tag = command->change_tag;
157 
158 	rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size);
159 	free(command);
160 	return rv;
161 }
162 
163 
164 status_t
165 BBufferConsumer::SetOutputEnabled(const media_source &source,
166 								  const media_destination &destination,
167 								  bool enabled,
168 								  void *user_data,
169 								  int32 *change_tag,
170 								  void *_reserved_)
171 {
172 	CALLED();
173 	if (IS_INVALID_SOURCE(source))
174 		return B_MEDIA_BAD_SOURCE;
175 	if (IS_INVALID_DESTINATION(destination))
176 		return B_MEDIA_BAD_DESTINATION;
177 
178 	producer_enable_output_command command;
179 
180 	command.source = source;
181 	command.destination = destination;
182 	command.enabled = enabled;
183 	command.user_data = user_data;
184 	command.change_tag = NewChangeTag();
185 	if (change_tag != NULL)
186 		*change_tag = command.change_tag;
187 
188 	return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command));
189 }
190 
191 
192 status_t
193 BBufferConsumer::RequestFormatChange(const media_source &source,
194 									 const media_destination &destination,
195 									 const media_format &to_format,
196 									 void *user_data,
197 									 int32 *change_tag,
198 									 void *_reserved_)
199 {
200 	CALLED();
201 	if (IS_INVALID_SOURCE(source))
202 		return B_MEDIA_BAD_SOURCE;
203 	if (IS_INVALID_DESTINATION(destination))
204 		return B_MEDIA_BAD_DESTINATION;
205 
206 	producer_format_change_requested_command command;
207 
208 	command.source = source;
209 	command.destination = destination;
210 	command.format = to_format;
211 	command.user_data = user_data;
212 	command.change_tag = NewChangeTag();
213 	if (change_tag != NULL)
214 		*change_tag = command.change_tag;
215 
216 	return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command));
217 }
218 
219 
220 status_t
221 BBufferConsumer::RequestAdditionalBuffer(const media_source &source,
222 										 BBuffer *prev_buffer,
223 										 void *_reserved)
224 {
225 	CALLED();
226 	if (IS_INVALID_SOURCE(source))
227 		return B_MEDIA_BAD_SOURCE;
228 
229 	producer_additional_buffer_requested_command command;
230 
231 	command.source = source;
232 	command.prev_buffer = prev_buffer->ID();
233 	command.prev_time = 0;
234 	command.has_seek_tag = false;
235 	//command.prev_tag =
236 
237 	return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command));
238 }
239 
240 
241 status_t
242 BBufferConsumer::RequestAdditionalBuffer(const media_source &source,
243 										 bigtime_t start_time,
244 										 void *_reserved)
245 {
246 	CALLED();
247 	if (IS_INVALID_SOURCE(source))
248 		return B_MEDIA_BAD_SOURCE;
249 
250 	producer_additional_buffer_requested_command command;
251 
252 	command.source = source;
253 	command.prev_buffer = 0;
254 	command.prev_time = start_time;
255 	command.has_seek_tag = false;
256 	//command.prev_tag =
257 
258 	return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command));
259 }
260 
261 
262 status_t
263 BBufferConsumer::SetOutputBuffersFor(const media_source &source,
264 									 const media_destination &destination,
265 									 BBufferGroup *group,
266 									 void *user_data,
267 									 int32 *change_tag,
268 									 bool will_reclaim,
269 									 void *_reserved_)
270 {
271 	CALLED();
272 
273 	if (IS_INVALID_SOURCE(source))
274 		return B_MEDIA_BAD_SOURCE;
275 	if (IS_INVALID_DESTINATION(destination))
276 		return B_MEDIA_BAD_DESTINATION;
277 
278 	producer_set_buffer_group_command *command;
279 	BBuffer **buffers;
280 	int32 buffer_count;
281 	size_t size;
282 	status_t rv;
283 
284 	if (group == 0) {
285 		buffer_count = 0;
286 	} else {
287 		if (B_OK != group->CountBuffers(&buffer_count))
288 			return B_ERROR;
289 	}
290 
291 	if (buffer_count != 0) {
292 		buffers = new BBuffer * [buffer_count];
293 		if (B_OK != group->GetBufferList(buffer_count, buffers)) {
294 			delete [] buffers;
295 			return B_ERROR;
296 		}
297 	} else {
298 		buffers = NULL;
299 	}
300 
301 	size = sizeof(producer_set_buffer_group_command) + buffer_count * sizeof(media_buffer_id);
302 	command = static_cast<producer_set_buffer_group_command *>(malloc(size));
303 	command->source = source;
304 	command->destination = destination;
305 	command->user_data = user_data;
306 	command->change_tag = NewChangeTag();
307 	command->buffer_count = buffer_count;
308 	for (int32 i = 0; i < buffer_count; i++)
309 		command->buffers[i] = buffers[i]->ID();
310 
311 	delete [] buffers;
312 
313 	if (change_tag != NULL)
314 		*change_tag = command->change_tag;
315 
316 	rv = SendToPort(source.port, PRODUCER_SET_BUFFER_GROUP, command, size);
317 	free(command);
318 
319 	if (rv == B_OK) {
320 		if (fDeleteBufferGroup) // XXX will leak memory if port write failed
321 			delete fDeleteBufferGroup;
322 		fDeleteBufferGroup = will_reclaim ? NULL : group;
323 	}
324 	return rv;
325 }
326 
327 
328 status_t
329 BBufferConsumer::SendLatencyChange(const media_source &source,
330 								   const media_destination &destination,
331 								   bigtime_t my_new_latency,
332 								   uint32 flags)
333 {
334 	CALLED();
335 	if (IS_INVALID_SOURCE(source))
336 		return B_MEDIA_BAD_SOURCE;
337 	if (IS_INVALID_DESTINATION(destination))
338 		return B_MEDIA_BAD_DESTINATION;
339 
340 	producer_latency_changed_command command;
341 
342 	command.source = source;
343 	command.destination = destination;
344 	command.latency = my_new_latency;
345 	command.flags = flags;
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 			TRACE("calling BBufferConsumer::BufferReceived buffer %ld at perf %Ld and TimeSource()->Now() is %Ld\n", buffer->Header()->buffer, buffer->Header()->start_time, TimeSource()->Now());
398 			BufferReceived(buffer);
399 			return B_OK;
400 		}
401 
402 		case CONSUMER_PRODUCER_DATA_STATUS:
403 		{
404 			const consumer_producer_data_status_command *command = static_cast<const consumer_producer_data_status_command *>(data);
405 			ProducerDataStatus(command->for_whom, command->status, command->at_performance_time);
406 			return B_OK;
407 		}
408 
409 		case CONSUMER_GET_LATENCY_FOR:
410 		{
411 			const consumer_get_latency_for_request *request = static_cast<const consumer_get_latency_for_request *>(data);
412 			consumer_get_latency_for_reply reply;
413 			rv = GetLatencyFor(request->for_whom, &reply.latency, &reply.timesource);
414 			request->SendReply(rv, &reply, sizeof(reply));
415 			return B_OK;
416 		}
417 
418 		case CONSUMER_CONNECTED:
419 		{
420 			const consumer_connected_request *request = static_cast<const consumer_connected_request *>(data);
421 			consumer_connected_reply reply;
422 			reply.input = request->input;
423 			rv = Connected(request->input.source, request->input.destination, request->input.format, &reply.input);
424 			request->SendReply(rv, &reply, sizeof(reply));
425 			return B_OK;
426 		}
427 
428 		case CONSUMER_DISCONNECTED:
429 		{
430 			const consumer_disconnected_request *request = static_cast<const consumer_disconnected_request *>(data);
431 			consumer_disconnected_reply reply;
432 			Disconnected(request->source, request->destination);
433 			request->SendReply(B_OK, &reply, sizeof(reply));
434 			return B_OK;
435 		}
436 
437 		case CONSUMER_FORMAT_CHANGED:
438 		{
439 			const consumer_format_changed_request *request = static_cast<const consumer_format_changed_request *>(data);
440 			consumer_format_changed_reply reply;
441 			rv = FormatChanged(request->producer, request->consumer, request->change_tag, request->format);
442 			request->SendReply(rv, &reply, sizeof(reply));
443 
444 			// XXX is this RequestCompleted() correct?
445 			node_request_completed_command completedcommand;
446 			completedcommand.info.what = media_request_info::B_FORMAT_CHANGED;
447 			completedcommand.info.change_tag = request->change_tag;
448 			completedcommand.info.status = reply.result;
449 			//completedcommand.info.cookie
450 			completedcommand.info.user_data = 0;
451 			completedcommand.info.source = request->producer;
452 			completedcommand.info.destination = request->consumer;
453 			completedcommand.info.format = request->format;
454 			SendToPort(request->consumer.port, NODE_REQUEST_COMPLETED, &completedcommand, sizeof(completedcommand));
455 			return B_OK;
456 		}
457 
458 		case CONSUMER_SEEK_TAG_REQUESTED:
459 		{
460 			const consumer_seek_tag_requested_request *request = static_cast<const consumer_seek_tag_requested_request *>(data);
461 			consumer_seek_tag_requested_reply reply;
462 			rv = SeekTagRequested(request->destination, request->target_time, request->flags, &reply.seek_tag, &reply.tagged_time, &reply.flags);
463 			request->SendReply(rv, &reply, sizeof(reply));
464 			return B_OK;
465 		}
466 
467 	};
468 	return B_ERROR;
469 }
470 
471 status_t
472 BBufferConsumer::SeekTagRequested(const media_destination &destination,
473 								  bigtime_t in_target_time,
474 								  uint32 in_flags,
475 								  media_seek_tag *out_seek_tag,
476 								  bigtime_t *out_tagged_time,
477 								  uint32 *out_flags)
478 {
479 	CALLED();
480 	// may be implemented by derived classes
481 	return B_ERROR;
482 }
483 
484 /*************************************************************
485  * private BBufferConsumer
486  *************************************************************/
487 
488 /*
489 not implemented:
490 BBufferConsumer::BBufferConsumer()
491 BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone)
492 BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone)
493 */
494 
495 /* deprecated function for R4 */
496 /* static */ status_t
497 BBufferConsumer::SetVideoClippingFor(const media_source &output,
498 									 const int16 *shorts,
499 									 int32 short_count,
500 									 const media_video_display_info &display,
501 									 int32 *change_tag)
502 {
503 	CALLED();
504 	if (IS_INVALID_SOURCE(output))
505 		return B_MEDIA_BAD_SOURCE;
506 	if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(producer_video_clipping_changed_command)) / 2)
507 		debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n");
508 
509 	producer_video_clipping_changed_command *command;
510 	size_t size;
511 	status_t rv;
512 
513 	size = sizeof(producer_video_clipping_changed_command) + short_count * sizeof(short);
514 	command = static_cast<producer_video_clipping_changed_command *>(malloc(size));
515 	command->source = output;
516 	command->destination = media_destination::null;
517 	command->display = display;
518 	command->user_data = 0;
519 	command->change_tag = NewChangeTag();
520 	command->short_count = short_count;
521 	memcpy(command->shorts, shorts, short_count * sizeof(short));
522 	if (change_tag != NULL)
523 		*change_tag = command->change_tag;
524 
525 	rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size);
526 	free(command);
527 	return rv;
528 }
529 
530 
531 /* deprecated function for R4 */
532 /* static */ status_t
533 BBufferConsumer::RequestFormatChange(const media_source &source,
534 									 const media_destination &destination,
535 									 media_format *in_to_format,
536 									 int32 *change_tag)
537 {
538 	CALLED();
539 	if (IS_INVALID_SOURCE(source))
540 		return B_MEDIA_BAD_SOURCE;
541 	if (IS_INVALID_DESTINATION(destination))
542 		return B_MEDIA_BAD_DESTINATION;
543 
544 	producer_format_change_requested_command command;
545 
546 	command.source = source;
547 	command.destination = destination;
548 	command.format = *in_to_format;
549 	command.user_data = 0;
550 	command.change_tag = NewChangeTag();
551 	if (change_tag != NULL)
552 		*change_tag = command.change_tag;
553 
554 	return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command));
555 }
556 
557 
558 /* deprecated function for R4 */
559 /* static */ status_t
560 BBufferConsumer::SetOutputEnabled(const media_source &source,
561 								  bool enabled,
562 								  int32 *change_tag)
563 {
564 	CALLED();
565 	if (IS_INVALID_SOURCE(source))
566 		return B_MEDIA_BAD_SOURCE;
567 
568 	producer_enable_output_command command;
569 
570 	command.source = source;
571 	command.destination = media_destination::null;
572 	command.enabled = enabled;
573 	command.user_data = 0;
574 	command.change_tag = NewChangeTag();
575 	if (change_tag != NULL)
576 		*change_tag = command.change_tag;
577 
578 	return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command));
579 }
580 
581 
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; }
598 
599