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 "BufferCache.h"
31#include <BufferConsumer.h>
32
33#include <stdlib.h>
34#include <string.h>
35
36#include <BufferProducer.h>
37#include <BufferGroup.h>
38#include <Buffer.h>
39#include <TimeSource.h>
40
41#include <debug.h>
42#include <MediaMisc.h>
43#include <DataExchange.h>
44
45
46
47BBufferConsumer::~BBufferConsumer()
48{
49	CALLED();
50	delete fBufferCache;
51	delete fDeleteBufferGroup;
52}
53
54
55// #pragma mark - public BBufferConsumer
56
57
58media_type
59BBufferConsumer::ConsumerType()
60{
61	CALLED();
62	return fConsumerType;
63}
64
65
66/*static*/ status_t
67BBufferConsumer::RegionToClipData(const BRegion* region, int32* _format,
68	int32 *_size, void* data)
69{
70	CALLED();
71
72	int count = *_size / sizeof(int16);
73	status_t status = BBufferProducer::clip_region_to_shorts(region,
74		static_cast<int16 *>(data), count, &count);
75
76	*_size = count * sizeof(int16);
77	*_format = BBufferProducer::B_CLIP_SHORT_RUNS;
78
79	return status;
80}
81
82
83// #pragma mark - protected BBufferConsumer
84
85
86BBufferConsumer::BBufferConsumer(media_type consumerType)
87	:
88	BMediaNode("called by BBufferConsumer"),
89	fConsumerType(consumerType),
90	fBufferCache(new BPrivate::BufferCache),
91	fDeleteBufferGroup(0)
92{
93	CALLED();
94
95	AddNodeKind(B_BUFFER_CONSUMER);
96}
97
98
99/*static*/ void
100BBufferConsumer::NotifyLateProducer(const media_source& whatSource,
101	bigtime_t howMuch, bigtime_t performanceTime)
102{
103	CALLED();
104	if (IS_INVALID_SOURCE(whatSource))
105		return;
106
107	producer_late_notice_received_command command;
108	command.source = whatSource;
109	command.how_much = howMuch;
110	command.performance_time = performanceTime;
111
112	SendToPort(whatSource.port, PRODUCER_LATE_NOTICE_RECEIVED, &command,
113		sizeof(command));
114}
115
116
117status_t
118BBufferConsumer::SetVideoClippingFor(const media_source& output,
119	const media_destination& destination, const int16* shorts, int32 shortCount,
120	const media_video_display_info& display, void* userData, int32* _changeTag,
121	void *_reserved_)
122{
123	CALLED();
124	if (IS_INVALID_SOURCE(output))
125		return B_MEDIA_BAD_SOURCE;
126	if (IS_INVALID_DESTINATION(destination))
127		return B_MEDIA_BAD_DESTINATION;
128	if (shortCount > int(B_MEDIA_MESSAGE_SIZE
129			- sizeof(producer_video_clipping_changed_command)) / 2) {
130		debugger("BBufferConsumer::SetVideoClippingFor short_count too large "
131			"(8000 limit)\n");
132	}
133
134	producer_video_clipping_changed_command* command;
135	size_t size = sizeof(producer_video_clipping_changed_command)
136		+ shortCount * sizeof(short);
137	command
138		= static_cast<producer_video_clipping_changed_command*>(malloc(size));
139	if (command == NULL)
140		return B_NO_MEMORY;
141
142	command->source = output;
143	command->destination = destination;
144	command->display = display;
145	command->user_data = userData;
146	command->change_tag = NewChangeTag();
147	command->short_count = shortCount;
148	memcpy(command->shorts, shorts, shortCount * sizeof(short));
149	if (_changeTag != NULL)
150		*_changeTag = command->change_tag;
151
152	status_t status = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED,
153		command, size);
154
155	free(command);
156	return status;
157}
158
159
160status_t
161BBufferConsumer::SetOutputEnabled(const media_source &source,
162								  const media_destination &destination,
163								  bool enabled,
164								  void *user_data,
165								  int32 *change_tag,
166								  void *_reserved_)
167{
168	CALLED();
169	if (IS_INVALID_SOURCE(source))
170		return B_MEDIA_BAD_SOURCE;
171	if (IS_INVALID_DESTINATION(destination))
172		return B_MEDIA_BAD_DESTINATION;
173
174	producer_enable_output_command command;
175
176	command.source = source;
177	command.destination = destination;
178	command.enabled = enabled;
179	command.user_data = user_data;
180	command.change_tag = NewChangeTag();
181	if (change_tag != NULL)
182		*change_tag = command.change_tag;
183
184	return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command, sizeof(command));
185}
186
187
188status_t
189BBufferConsumer::RequestFormatChange(const media_source &source,
190									 const media_destination &destination,
191									 const media_format &to_format,
192									 void *user_data,
193									 int32 *change_tag,
194									 void *_reserved_)
195{
196	CALLED();
197	if (IS_INVALID_SOURCE(source))
198		return B_MEDIA_BAD_SOURCE;
199	if (IS_INVALID_DESTINATION(destination))
200		return B_MEDIA_BAD_DESTINATION;
201
202	producer_format_change_requested_command command;
203
204	command.source = source;
205	command.destination = destination;
206	command.format = to_format;
207	command.user_data = user_data;
208	command.change_tag = NewChangeTag();
209	if (change_tag != NULL)
210		*change_tag = command.change_tag;
211
212	return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command, sizeof(command));
213}
214
215
216status_t
217BBufferConsumer::RequestAdditionalBuffer(const media_source &source,
218										 BBuffer *prev_buffer,
219										 void *_reserved)
220{
221	CALLED();
222	if (IS_INVALID_SOURCE(source))
223		return B_MEDIA_BAD_SOURCE;
224
225	producer_additional_buffer_requested_command command;
226
227	command.source = source;
228	command.prev_buffer = prev_buffer->ID();
229	command.prev_time = 0;
230	command.has_seek_tag = false;
231	//command.prev_tag =
232
233	return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &command, sizeof(command));
234}
235
236
237status_t
238BBufferConsumer::RequestAdditionalBuffer(const media_source& source,
239	bigtime_t startTime, void *_reserved)
240{
241	CALLED();
242	if (IS_INVALID_SOURCE(source))
243		return B_MEDIA_BAD_SOURCE;
244
245	producer_additional_buffer_requested_command command;
246
247	command.source = source;
248	command.prev_buffer = 0;
249	command.prev_time = startTime;
250	command.has_seek_tag = false;
251
252	return SendToPort(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED,
253		&command, sizeof(command));
254}
255
256
257status_t
258BBufferConsumer::SetOutputBuffersFor(const media_source &source,
259	const media_destination &destination, BBufferGroup *group, void *user_data,
260	int32 *change_tag, bool will_reclaim, void *_reserved_)
261{
262	CALLED();
263
264	if (IS_INVALID_SOURCE(source))
265		return B_MEDIA_BAD_SOURCE;
266	if (IS_INVALID_DESTINATION(destination))
267		return B_MEDIA_BAD_DESTINATION;
268
269	producer_set_buffer_group_command *command;
270	BBuffer **buffers;
271	int32 buffer_count;
272	size_t size;
273	status_t rv;
274
275	if (group == 0) {
276		buffer_count = 0;
277	} else {
278		if (B_OK != group->CountBuffers(&buffer_count))
279			return B_ERROR;
280	}
281
282	if (buffer_count != 0) {
283		buffers = new BBuffer * [buffer_count];
284		if (B_OK != group->GetBufferList(buffer_count, buffers)) {
285			delete [] buffers;
286			return B_ERROR;
287		}
288	} else {
289		buffers = NULL;
290	}
291
292	size = sizeof(producer_set_buffer_group_command) + buffer_count * sizeof(media_buffer_id);
293	command = static_cast<producer_set_buffer_group_command *>(malloc(size));
294	command->source = source;
295	command->destination = destination;
296	command->user_data = user_data;
297	command->change_tag = NewChangeTag();
298	command->buffer_count = buffer_count;
299	for (int32 i = 0; i < buffer_count; i++)
300		command->buffers[i] = buffers[i]->ID();
301
302	delete [] buffers;
303
304	if (change_tag != NULL)
305		*change_tag = command->change_tag;
306
307	rv = SendToPort(source.port, PRODUCER_SET_BUFFER_GROUP, command, size);
308	free(command);
309
310	if (rv == B_OK) {
311		// XXX will leak memory if port write failed
312		delete fDeleteBufferGroup;
313		fDeleteBufferGroup = will_reclaim ? NULL : group;
314	}
315	return rv;
316}
317
318
319status_t
320BBufferConsumer::SendLatencyChange(const media_source& source,
321	const media_destination& destination, bigtime_t newLatency, uint32 flags)
322{
323	CALLED();
324	if (IS_INVALID_SOURCE(source))
325		return B_MEDIA_BAD_SOURCE;
326	if (IS_INVALID_DESTINATION(destination))
327		return B_MEDIA_BAD_DESTINATION;
328
329	producer_latency_changed_command command;
330
331	command.source = source;
332	command.destination = destination;
333	command.latency = newLatency;
334	command.flags = flags;
335
336	TRACE("###### BBufferConsumer::SendLatencyChange: latency from %ld/%ld to "
337		"%ld/%ld changed to %Ld\n", source.port, source.id, destination.port,
338		destination.id, newLatency);
339
340	return SendToPort(source.port, PRODUCER_LATENCY_CHANGED, &command,
341		sizeof(command));
342}
343
344
345status_t
346BBufferConsumer::HandleMessage(int32 message, const void* data, size_t size)
347{
348	PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message, ID());
349	status_t rv;
350	switch (message) {
351		case CONSUMER_ACCEPT_FORMAT:
352		{
353			const consumer_accept_format_request* request
354				= static_cast<const consumer_accept_format_request*>(data);
355
356			consumer_accept_format_reply reply;
357			reply.format = request->format;
358			status_t status = AcceptFormat(request->dest, &reply.format);
359			request->SendReply(status, &reply, sizeof(reply));
360			return B_OK;
361		}
362
363		case CONSUMER_GET_NEXT_INPUT:
364		{
365			const consumer_get_next_input_request *request = static_cast<const consumer_get_next_input_request *>(data);
366			consumer_get_next_input_reply reply;
367			reply.cookie = request->cookie;
368			rv = GetNextInput(&reply.cookie, &reply.input);
369			request->SendReply(rv, &reply, sizeof(reply));
370			return B_OK;
371		}
372
373		case CONSUMER_DISPOSE_INPUT_COOKIE:
374		{
375			const consumer_dispose_input_cookie_request *request = static_cast<const consumer_dispose_input_cookie_request *>(data);
376			consumer_dispose_input_cookie_reply reply;
377			DisposeInputCookie(request->cookie);
378			request->SendReply(B_OK, &reply, sizeof(reply));
379			return B_OK;
380		}
381
382		case CONSUMER_BUFFER_RECEIVED:
383		{
384			const consumer_buffer_received_command* command
385				= static_cast<const consumer_buffer_received_command*>(data);
386
387			BBuffer* buffer = fBufferCache->GetBuffer(command->buffer);
388			buffer->SetHeader(&command->header);
389
390			PRINT(4, "calling BBufferConsumer::BufferReceived buffer %ld at "
391				"perf %Ld and TimeSource()->Now() is %Ld\n",
392				buffer->Header()->buffer, buffer->Header()->start_time,
393				TimeSource()->Now());
394
395			BufferReceived(buffer);
396			return B_OK;
397		}
398
399		case CONSUMER_PRODUCER_DATA_STATUS:
400		{
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;
404		}
405
406		case CONSUMER_GET_LATENCY_FOR:
407		{
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;
413		}
414
415		case CONSUMER_CONNECTED:
416		{
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;
423		}
424
425		case CONSUMER_DISCONNECTED:
426		{
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;
432		}
433
434		case CONSUMER_FORMAT_CHANGED:
435		{
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));
440
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;
453		}
454
455		case CONSUMER_SEEK_TAG_REQUESTED:
456		{
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;
462		}
463	}
464	return B_ERROR;
465}
466
467status_t
468BBufferConsumer::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)
474{
475	CALLED();
476	// may be implemented by derived classes
477	return B_ERROR;
478}
479
480
481// #pragma mark - private BBufferConsumer
482
483
484/*
485not implemented:
486BBufferConsumer::BBufferConsumer()
487BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone)
488BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone)
489*/
490
491
492/*!	Deprecated function for BeOS R4.
493*/
494/* static */ status_t
495BBufferConsumer::SetVideoClippingFor(const media_source &output,
496									 const int16 *shorts,
497									 int32 short_count,
498									 const media_video_display_info &display,
499									 int32 *change_tag)
500{
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");
506
507	producer_video_clipping_changed_command *command;
508	size_t size;
509	status_t rv;
510
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;
522
523	rv = SendToPort(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, command, size);
524	free(command);
525	return rv;
526}
527
528
529/*!	Deprecated function for BeOS R4.
530*/
531/*static*/ status_t
532BBufferConsumer::RequestFormatChange(const media_source& source,
533	const media_destination& destination, media_format* format,
534	int32* _changeTag)
535{
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;
541
542	producer_format_change_requested_command command;
543
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;
551
552	return SendToPort(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &command,
553		sizeof(command));
554}
555
556
557/*!	Deprecated function for BeOS R4.
558*/
559/*static*/ status_t
560BBufferConsumer::SetOutputEnabled(const media_source& source, bool enabled,
561	int32* _changeTag)
562{
563	CALLED();
564	if (IS_INVALID_SOURCE(source))
565		return B_MEDIA_BAD_SOURCE;
566
567	producer_enable_output_command command;
568
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;
576
577	return SendToPort(source.port, PRODUCER_ENABLE_OUTPUT, &command,
578		sizeof(command));
579}
580
581
582status_t BBufferConsumer::_Reserved_BufferConsumer_0(void*) { return B_ERROR; }
583status_t BBufferConsumer::_Reserved_BufferConsumer_1(void*) { return B_ERROR; }
584status_t BBufferConsumer::_Reserved_BufferConsumer_2(void*) { return B_ERROR; }
585status_t BBufferConsumer::_Reserved_BufferConsumer_3(void*) { return B_ERROR; }
586status_t BBufferConsumer::_Reserved_BufferConsumer_4(void*) { return B_ERROR; }
587status_t BBufferConsumer::_Reserved_BufferConsumer_5(void*) { return B_ERROR; }
588status_t BBufferConsumer::_Reserved_BufferConsumer_6(void*) { return B_ERROR; }
589status_t BBufferConsumer::_Reserved_BufferConsumer_7(void*) { return B_ERROR; }
590status_t BBufferConsumer::_Reserved_BufferConsumer_8(void*) { return B_ERROR; }
591status_t BBufferConsumer::_Reserved_BufferConsumer_9(void*) { return B_ERROR; }
592status_t BBufferConsumer::_Reserved_BufferConsumer_10(void*) { return B_ERROR; }
593status_t BBufferConsumer::_Reserved_BufferConsumer_11(void*) { return B_ERROR; }
594status_t BBufferConsumer::_Reserved_BufferConsumer_12(void*) { return B_ERROR; }
595status_t BBufferConsumer::_Reserved_BufferConsumer_13(void*) { return B_ERROR; }
596status_t BBufferConsumer::_Reserved_BufferConsumer_14(void*) { return B_ERROR; }
597status_t BBufferConsumer::_Reserved_BufferConsumer_15(void*) { return B_ERROR; }
598
599