xref: /haiku/src/kits/media/BufferProducer.cpp (revision 2807c36668a1730dd59bc39de65e0b8f88cd5d0d)
1 /***********************************************************************
2  * AUTHOR: Marcus Overhagen
3  *   FILE: BufferProducer.cpp
4  *  DESCR:
5  ***********************************************************************/
6 #include <BufferProducer.h>
7 #include <BufferGroup.h>
8 #include <Buffer.h>
9 #include "debug.h"
10 #include "DataExchange.h"
11 
12 /*************************************************************
13  * protected BBufferProducer
14  *************************************************************/
15 
16 BBufferProducer::~BBufferProducer()
17 {
18 	CALLED();
19 }
20 
21 /*************************************************************
22  * public BBufferProducer
23  *************************************************************/
24 
25 /* static */ status_t
26 BBufferProducer::ClipDataToRegion(int32 format,
27 								  int32 size,
28 								  const void *data,
29 								  BRegion *region)
30 {
31 	CALLED();
32 
33 	if (format != B_CLIP_SHORT_RUNS)
34 		return B_MEDIA_BAD_CLIP_FORMAT;
35 
36 	return clip_shorts_to_region((const int16 *)data, size / sizeof(int16), region);
37 }
38 
39 media_type
40 BBufferProducer::ProducerType()
41 {
42 	CALLED();
43 	return fProducerType;
44 }
45 
46 /*************************************************************
47  * protected BBufferProducer
48  *************************************************************/
49 
50 /* explicit */
51 BBufferProducer::BBufferProducer(media_type producer_type) :
52 	BMediaNode("called by BBufferProducer"),
53 	fProducerType(producer_type),
54 	fInitialLatency(0),
55 	fInitialFlags(0)
56 {
57 	CALLED();
58 
59 	AddNodeKind(B_BUFFER_PRODUCER);
60 }
61 
62 
63 status_t
64 BBufferProducer::VideoClippingChanged(const media_source &for_source,
65 									  int16 num_shorts,
66 									  int16 *clip_data,
67 									  const media_video_display_info &display,
68 									  int32 *_deprecated_)
69 {
70 	CALLED();
71 	// may be implemented by derived classes
72 	return B_ERROR;
73 }
74 
75 
76 status_t
77 BBufferProducer::GetLatency(bigtime_t *out_lantency)
78 {
79 	UNIMPLEMENTED();
80 
81 	// XXX The default implementation of GetLatency() finds the maximum
82 	// latency of your currently-available outputs by iterating over
83 	// them, and returns that value in outLatency
84 
85 	return B_ERROR;
86 }
87 
88 
89 status_t
90 BBufferProducer::SetPlayRate(int32 numer,
91 							 int32 denom)
92 {
93 	CALLED();
94 	// may be implemented by derived classes
95 	return B_ERROR;
96 }
97 
98 
99 status_t
100 BBufferProducer::HandleMessage(int32 message,
101 							   const void *data,
102 							   size_t size)
103 {
104 	INFO("BBufferProducer::HandleMessage %#lx, node %ld\n", message, fNodeID);
105 	status_t rv;
106 	switch (message) {
107 
108 		case PRODUCER_FORMAT_SUGGESTION_REQUESTED:
109 		{
110 			const producer_format_suggestion_requested_request *request = static_cast<const producer_format_suggestion_requested_request *>(data);
111 			producer_format_suggestion_requested_reply reply;
112 			rv = FormatSuggestionRequested(request->type, request->quality, &reply.format);
113 			request->SendReply(rv, &reply, sizeof(reply));
114 			return B_OK;
115 		}
116 
117 		case PRODUCER_FORMAT_PROPOSAL:
118 		{
119 			const producer_format_proposal_request *request = static_cast<const producer_format_proposal_request *>(data);
120 			producer_format_proposal_reply reply;
121 			reply.format = request->format;
122 			rv = FormatProposal(request->output, &reply.format);
123 			request->SendReply(rv, &reply, sizeof(reply));
124 			return B_OK;
125 		}
126 
127 		case PRODUCER_PREPARE_TO_CONNECT:
128 		{
129 			const producer_prepare_to_connect_request *request = static_cast<const producer_prepare_to_connect_request *>(data);
130 			producer_prepare_to_connect_reply reply;
131 			reply.format = request->format;
132 			memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH);
133 			rv = PrepareToConnect(request->source, request->destination, &reply.format, &reply.out_source, reply.name);
134 			request->SendReply(rv, &reply, sizeof(reply));
135 			return B_OK;
136 		}
137 
138 		case PRODUCER_CONNECT:
139 		{
140 			const producer_connect_request *request = static_cast<const producer_connect_request *>(data);
141 			producer_connect_reply reply;
142 			memcpy(reply.name, request->name, B_MEDIA_NAME_LENGTH);
143 			Connect(request->error, request->source, request->destination, request->format, reply.name);
144 			request->SendReply(B_OK, &reply, sizeof(reply));
145 			return B_OK;
146 		}
147 
148 		case PRODUCER_DISCONNECT:
149 		{
150 			const producer_disconnect_request *request = static_cast<const producer_disconnect_request *>(data);
151 			producer_disconnect_reply reply;
152 			Disconnect(request->source, request->destination);
153 			request->SendReply(B_OK, &reply, sizeof(reply));
154 			return B_OK;
155 		}
156 
157 		case PRODUCER_GET_INITIAL_LATENCY:
158 		{
159 			const producer_get_initial_latency_request *request = static_cast<const producer_get_initial_latency_request *>(data);
160 			producer_get_initial_latency_reply reply;
161 			reply.initial_latency = fInitialLatency;
162 			reply.flags = fInitialFlags;
163 			request->SendReply(B_OK, &reply, sizeof(reply));
164 			return B_OK;
165 		}
166 
167 		case PRODUCER_SET_PLAY_RATE:
168 		{
169 			const producer_set_play_rate_request *request = static_cast<const producer_set_play_rate_request *>(data);
170 			producer_set_play_rate_reply reply;
171 			rv = SetPlayRate(request->numer, request->denom);
172 			request->SendReply(rv, &reply, sizeof(reply));
173 			return B_OK;
174 		}
175 
176 		case PRODUCER_GET_LATENCY:
177 		{
178 			const producer_get_latency_request *request = static_cast<const producer_get_latency_request *>(data);
179 			producer_get_latency_reply reply;
180 			rv = GetLatency(&reply.latency);
181 			request->SendReply(rv, &reply, sizeof(reply));
182 			return B_OK;
183 		}
184 
185 		case PRODUCER_GET_NEXT_OUTPUT:
186 		{
187 			const producer_get_next_output_request *request = static_cast<const producer_get_next_output_request *>(data);
188 			producer_get_next_output_reply reply;
189 			reply.cookie = request->cookie;
190 			rv = GetNextOutput(&reply.cookie, &reply.output);
191 			request->SendReply(rv, &reply, sizeof(reply));
192 			return B_OK;
193 		}
194 
195 		case PRODUCER_DISPOSE_OUTPUT_COOKIE:
196 		{
197 			const producer_dispose_output_cookie_request *request = static_cast<const producer_dispose_output_cookie_request *>(data);
198 			producer_dispose_output_cookie_reply reply;
199 			DisposeOutputCookie(request->cookie);
200 			request->SendReply(B_OK, &reply, sizeof(reply));
201 			return B_OK;
202 		}
203 
204 		case PRODUCER_SET_BUFFER_GROUP:
205 		{
206 			const producer_set_buffer_group_command *command = static_cast<const producer_set_buffer_group_command *>(data);
207 			node_request_completed_command replycommand;
208 			BBufferGroup *group;
209 			group = command->buffer_count != 0 ? new BBufferGroup(command->buffer_count, command->buffers) : NULL;
210 			rv = SetBufferGroup(command->source, group);
211 			if (command->destination == media_destination::null)
212 				return B_OK;
213 			replycommand.info.what = media_request_info::B_SET_OUTPUT_BUFFERS_FOR;
214 			replycommand.info.change_tag = command->change_tag;
215 			replycommand.info.status = rv;
216 			replycommand.info.cookie = (int32)group;
217 			replycommand.info.user_data = command->user_data;
218 			replycommand.info.source = command->source;
219 			replycommand.info.destination = command->destination;
220 			SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, &replycommand, sizeof(replycommand));
221 			return B_OK;
222 		}
223 
224 		case PRODUCER_FORMAT_CHANGE_REQUESTED:
225 		{
226 			const producer_format_change_requested_command *command = static_cast<const producer_format_change_requested_command *>(data);
227 			node_request_completed_command replycommand;
228 			replycommand.info.format = command->format;
229 			rv = FormatChangeRequested(command->source, command->destination, &replycommand.info.format, NULL);
230 			if (command->destination == media_destination::null)
231 				return B_OK;
232 			replycommand.info.what = media_request_info::B_REQUEST_FORMAT_CHANGE;
233 			replycommand.info.change_tag = command->change_tag;
234 			replycommand.info.status = rv;
235 			//replycommand.info.cookie
236 			replycommand.info.user_data = command->user_data;
237 			replycommand.info.source = command->source;
238 			replycommand.info.destination = command->destination;
239 			SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, &replycommand, sizeof(replycommand));
240 			return B_OK;
241 		}
242 
243 
244 		case PRODUCER_VIDEO_CLIPPING_CHANGED:
245 		{
246 			const producer_video_clipping_changed_command *command = static_cast<const producer_video_clipping_changed_command *>(data);
247 			node_request_completed_command replycommand;
248 			rv = VideoClippingChanged(command->source, command->short_count, (int16 *)command->shorts, command->display, NULL);
249 			if (command->destination == media_destination::null)
250 				return B_OK;
251 			replycommand.info.what = media_request_info::B_SET_VIDEO_CLIPPING_FOR;
252 			replycommand.info.change_tag = command->change_tag;
253 			replycommand.info.status = rv;
254 			//replycommand.info.cookie
255 			replycommand.info.user_data = command->user_data;
256 			replycommand.info.source = command->source;
257 			replycommand.info.destination = command->destination;
258 			replycommand.info.format.type = B_MEDIA_RAW_VIDEO;
259 			replycommand.info.format.u.raw_video.display = command->display;
260 			SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, &replycommand, sizeof(replycommand));
261 			return B_OK;
262 		}
263 
264 		case PRODUCER_ADDITIONAL_BUFFER_REQUESTED:
265 		{
266 			const producer_additional_buffer_requested_command *command = static_cast<const producer_additional_buffer_requested_command *>(data);
267 			AdditionalBufferRequested(command->source, command->prev_buffer, command->prev_time, command->has_seek_tag ? &command->prev_tag : NULL);
268 			return B_OK;
269 		}
270 
271 		case PRODUCER_LATENCY_CHANGED:
272 		{
273 			const producer_latency_changed_command *command = static_cast<const producer_latency_changed_command *>(data);
274 			LatencyChanged(command->source, command->destination, command->latency, command->flags);
275 			return B_OK;
276 		}
277 
278 		case PRODUCER_LATE_NOTICE_RECEIVED:
279 		{
280 			const producer_late_notice_received_command *command = static_cast<const producer_late_notice_received_command *>(data);
281 			LateNoticeReceived(command->source, command->how_much, command->performance_time);
282 			return B_OK;
283 		}
284 
285 		case PRODUCER_ENABLE_OUTPUT:
286 		{
287 			const producer_enable_output_command *command = static_cast<const producer_enable_output_command *>(data);
288 			node_request_completed_command replycommand;
289 			EnableOutput(command->source, command->enabled, NULL);
290 			if (command->destination == media_destination::null)
291 				return B_OK;
292 			replycommand.info.what = media_request_info::B_SET_OUTPUT_ENABLED;
293 			replycommand.info.change_tag = command->change_tag;
294 			replycommand.info.status = B_OK;
295 			//replycommand.info.cookie
296 			replycommand.info.user_data = command->user_data;
297 			replycommand.info.source = command->source;
298 			replycommand.info.destination = command->destination;
299 			//replycommand.info.format
300 			SendToPort(command->destination.port, NODE_REQUEST_COMPLETED, &replycommand, sizeof(replycommand));
301 			return B_OK;
302 		}
303 
304 	};
305 	return B_ERROR;
306 }
307 
308 
309 void
310 BBufferProducer::AdditionalBufferRequested(const media_source &source,
311 										   media_buffer_id prev_buffer,
312 										   bigtime_t prev_time,
313 										   const media_seek_tag *prev_tag)
314 {
315 	CALLED();
316 	// may be implemented by derived classes
317 }
318 
319 
320 void
321 BBufferProducer::LatencyChanged(const media_source &source,
322 								const media_destination &destination,
323 								bigtime_t new_latency,
324 								uint32 flags)
325 {
326 	CALLED();
327 	// may be implemented by derived classes
328 }
329 
330 
331 status_t
332 BBufferProducer::SendBuffer(BBuffer *buffer,
333 							const media_destination &destination)
334 {
335 	CALLED();
336 	if (destination == media_destination::null)
337 		return B_MEDIA_BAD_DESTINATION;
338 	if (buffer == NULL)
339 		return B_BAD_VALUE;
340 
341 	consumer_buffer_received_command command;
342 	command.buffer = buffer->ID();
343 	command.header = *(buffer->Header());
344 	command.header.buffer = command.buffer; // buffer->ID();
345 	command.header.destination = destination.id;
346 
347 	return SendToPort(destination.port, CONSUMER_BUFFER_RECEIVED, &command, sizeof(command));
348 }
349 
350 
351 status_t
352 BBufferProducer::SendDataStatus(int32 status,
353 								const media_destination &destination,
354 								bigtime_t at_time)
355 {
356 	CALLED();
357 	if (destination == media_destination::null)
358 		return B_MEDIA_BAD_DESTINATION;
359 
360 	consumer_producer_data_status_command command;
361 	command.for_whom = destination;
362 	command.status = status;
363 	command.at_performance_time = at_time;
364 
365 	return SendToPort(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &command, sizeof(command));
366 }
367 
368 
369 status_t
370 BBufferProducer::ProposeFormatChange(media_format *format,
371 									 const media_destination &for_destination)
372 {
373 	CALLED();
374 	if (for_destination == media_destination::null)
375 		return B_MEDIA_BAD_DESTINATION;
376 
377 	consumer_accept_format_request request;
378 	consumer_accept_format_reply reply;
379 	status_t rv;
380 
381 	request.dest = for_destination;
382 	request.format = *format;
383 	rv = QueryPort(for_destination.port, CONSUMER_ACCEPT_FORMAT, &request, sizeof(request), &reply, sizeof(reply));
384 	if (rv != B_OK)
385 		return rv;
386 
387 	*format = reply.format;
388 	return B_OK;
389 }
390 
391 
392 status_t
393 BBufferProducer::ChangeFormat(const media_source &for_source,
394 							  const media_destination &for_destination,
395 							  media_format *format)
396 {
397 	CALLED();
398 	if (for_source == media_source::null)
399 		return B_MEDIA_BAD_SOURCE;
400 	if (for_destination == media_destination::null)
401 		return B_MEDIA_BAD_DESTINATION;
402 
403 	consumer_format_changed_request request;
404 	consumer_format_changed_reply reply;
405 
406 	request.producer = for_source;
407 	request.consumer = for_destination;
408 	request.format = *format;
409 
410 	// we use a request/reply to make this synchronous
411 	return QueryPort(for_destination.port, CONSUMER_FORMAT_CHANGED, &request, sizeof(request), &reply, sizeof(reply));
412 }
413 
414 
415 status_t
416 BBufferProducer::FindLatencyFor(const media_destination &for_destination,
417 								bigtime_t *out_latency,
418 								media_node_id *out_timesource)
419 {
420 	CALLED();
421 	if (for_destination == media_destination::null)
422 		return B_MEDIA_BAD_DESTINATION;
423 
424 	status_t rv;
425 	consumer_get_latency_for_request request;
426 	consumer_get_latency_for_reply reply;
427 
428 	request.for_whom = for_destination;
429 
430 	rv = QueryPort(for_destination.port, CONSUMER_GET_LATENCY_FOR, &request, sizeof(request), &reply, sizeof(reply));
431 	if (rv != B_OK)
432 		return rv;
433 
434 	*out_latency = reply.latency;
435 	*out_timesource = reply.timesource;
436 	return rv;
437 }
438 
439 
440 status_t
441 BBufferProducer::FindSeekTag(const media_destination &for_destination,
442 							 bigtime_t in_target_time,
443 							 media_seek_tag *out_tag,
444 							 bigtime_t *out_tagged_time,
445 							 uint32 *out_flags,
446 							 uint32 in_flags)
447 {
448 	CALLED();
449 	if (for_destination == media_destination::null)
450 		return B_MEDIA_BAD_DESTINATION;
451 
452 	status_t rv;
453 	consumer_seek_tag_requested_request request;
454 	consumer_seek_tag_requested_reply reply;
455 
456 	request.destination = for_destination;
457 	request.target_time = in_target_time;
458 	request.flags = in_flags;
459 
460 	rv = QueryPort(for_destination.port, CONSUMER_SEEK_TAG_REQUESTED, &request, sizeof(request), &reply, sizeof(reply));
461 	if (rv != B_OK)
462 		return rv;
463 
464 	*out_tag = reply.seek_tag;
465 	*out_tagged_time = reply.tagged_time;
466 	*out_flags = reply.flags;
467 	return rv;
468 }
469 
470 
471 void
472 BBufferProducer::SetInitialLatency(bigtime_t inInitialLatency,
473 								   uint32 flags)
474 {
475 	fInitialLatency = inInitialLatency;
476 	fInitialFlags = flags;
477 }
478 
479 /*************************************************************
480  * private BBufferProducer
481  *************************************************************/
482 
483 /*
484 private unimplemented
485 BBufferProducer::BBufferProducer()
486 BBufferProducer::BBufferProducer(const BBufferProducer &clone)
487 BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone)
488 */
489 
490 status_t BBufferProducer::_Reserved_BufferProducer_0(void *) { return B_ERROR; }
491 status_t BBufferProducer::_Reserved_BufferProducer_1(void *) { return B_ERROR; }
492 status_t BBufferProducer::_Reserved_BufferProducer_2(void *) { return B_ERROR; }
493 status_t BBufferProducer::_Reserved_BufferProducer_3(void *) { return B_ERROR; }
494 status_t BBufferProducer::_Reserved_BufferProducer_4(void *) { return B_ERROR; }
495 status_t BBufferProducer::_Reserved_BufferProducer_5(void *) { return B_ERROR; }
496 status_t BBufferProducer::_Reserved_BufferProducer_6(void *) { return B_ERROR; }
497 status_t BBufferProducer::_Reserved_BufferProducer_7(void *) { return B_ERROR; }
498 status_t BBufferProducer::_Reserved_BufferProducer_8(void *) { return B_ERROR; }
499 status_t BBufferProducer::_Reserved_BufferProducer_9(void *) { return B_ERROR; }
500 status_t BBufferProducer::_Reserved_BufferProducer_10(void *) { return B_ERROR; }
501 status_t BBufferProducer::_Reserved_BufferProducer_11(void *) { return B_ERROR; }
502 status_t BBufferProducer::_Reserved_BufferProducer_12(void *) { return B_ERROR; }
503 status_t BBufferProducer::_Reserved_BufferProducer_13(void *) { return B_ERROR; }
504 status_t BBufferProducer::_Reserved_BufferProducer_14(void *) { return B_ERROR; }
505 status_t BBufferProducer::_Reserved_BufferProducer_15(void *) { return B_ERROR; }
506 
507 
508 status_t
509 BBufferProducer::clip_shorts_to_region(const int16 *data,
510 									   int count,
511 									   BRegion *output)
512 {
513 	UNIMPLEMENTED();
514 
515 	return B_ERROR;
516 }
517 
518 
519 status_t
520 BBufferProducer::clip_region_to_shorts(const BRegion *input,
521 									   int16 *data,
522 									   int max_count,
523 									   int *out_count)
524 {
525 	UNIMPLEMENTED();
526 
527 	return B_ERROR;
528 }
529 
530