xref: /haiku/src/kits/media/MediaRoster.cpp (revision dfb2ad6148f303a0ee57faecc282953d11156067)
1 /***********************************************************************
2  * AUTHOR: Marcus Overhagen
3  *   FILE: MediaRoster.cpp
4  *  DESCR:
5  ***********************************************************************/
6 #include <MediaRoster.h>
7 #include <Locker.h>
8 #include <Message.h>
9 #include <Messenger.h>
10 #include <StopWatch.h>
11 #include <OS.h>
12 #include <String.h>
13 #include <TimeSource.h>
14 #define	DEBUG 3
15 #include <Debug.h>
16 #include "debug.h"
17 #include "TStack.h"
18 #include "PortPool.h"
19 #include "SystemTimeSource.h"
20 #include "ServerInterface.h"
21 #include "DataExchange.h"
22 #include "DormantNodeManager.h"
23 #include "Notifications.h"
24 
25 namespace BPrivate { namespace media {
26 	extern team_id team;
27 } } // BPrivate::media
28 
29 using namespace BPrivate::media;
30 
31 // the BMediaRoster destructor is private,
32 // but _DefaultDeleter is a friend class of
33 // the BMediaRoster an thus can delete it
34 class _DefaultDeleter
35 {
36 public:
37 	~_DefaultDeleter() { delete BMediaRoster::_sDefault; }
38 };
39 
40 _DefaultDeleter _deleter;
41 
42 namespace BPrivate { namespace media { namespace mediaroster {
43 
44 status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id = NULL, BString * out_input_name = NULL);
45 status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info = NULL, const media_input *input = NULL);
46 status_t GetAllOutputs(const media_node & node, Stack<media_output> *stack);
47 status_t GetAllInputs(const media_node & node, Stack<media_input> *stack);
48 status_t PublishOutputs(const media_node & node, Stack<media_output> *stack);
49 status_t PublishInputs(const media_node & node, Stack<media_input> *stack);
50 
51 status_t
52 GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name)
53 {
54 	if (out_node == NULL)
55 		return B_BAD_VALUE;
56 
57 	server_get_node_request request;
58 	server_get_node_reply reply;
59 	status_t rv;
60 
61 	request.type = type;
62 	request.team = team;
63 	rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply, sizeof(reply));
64 	if (rv != B_OK)
65 		return rv;
66 
67 	*out_node = reply.node;
68 	if (out_input_id)
69 		*out_input_id = reply.input_id;
70 	if (out_input_name)
71 		*out_input_name = reply.input_name;
72 	return rv;
73 }
74 
75 status_t
76 SetNode(node_type type, const media_node *node, const dormant_node_info *info, const media_input *input)
77 {
78 	server_set_node_request request;
79 	server_set_node_reply reply;
80 
81 	request.type = type;
82 	request.use_node = node ? true : false;
83 	if (node)
84 		request.node = *node;
85 	request.use_dni = info ? true : false;
86 	if (info)
87 		request.dni = *info;
88 	request.use_input = input ? true : false;
89 	if (input)
90 		request.input = *input;
91 
92 	return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply, sizeof(reply));
93 }
94 
95 status_t
96 GetAllOutputs(const media_node & node, Stack<media_output> *stack)
97 {
98 	int32 cookie;
99 	status_t rv;
100 	status_t result;
101 
102 	result = B_OK;
103 	cookie = 0;
104 	for (;;) {
105 		producer_get_next_output_request request;
106 		producer_get_next_output_reply reply;
107 		request.cookie = cookie;
108 		rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request, sizeof(request), &reply, sizeof(reply));
109 		if (rv != B_OK)
110 			break;
111 		cookie = reply.cookie;
112 		if (!stack->Push(reply.output)) {
113 			TRACE("GetAllOutputs: stack->Push failed\n");
114 			result = B_ERROR;
115 		}
116 	}
117 
118 	producer_dispose_output_cookie_request request;
119 	producer_dispose_output_cookie_reply reply;
120 	QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply));
121 
122 	return result;
123 }
124 
125 status_t
126 GetAllInputs(const media_node & node, Stack<media_input> *stack)
127 {
128 	int32 cookie;
129 	status_t rv;
130 	status_t result;
131 
132 	result = B_OK;
133 	cookie = 0;
134 	for (;;) {
135 		consumer_get_next_input_request request;
136 		consumer_get_next_input_reply reply;
137 		request.cookie = cookie;
138 		rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request, sizeof(request), &reply, sizeof(reply));
139 		if (rv != B_OK)
140 			break;
141 		cookie = reply.cookie;
142 		if (!stack->Push(reply.input)) {
143 			TRACE("GetAllInputs: stack->Push failed\n");
144 			result = B_ERROR;
145 		}
146 	}
147 
148 	consumer_dispose_input_cookie_request request;
149 	consumer_dispose_input_cookie_reply reply;
150 	QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply));
151 
152 	return result;
153 }
154 
155 status_t
156 PublishOutputs(const media_node & node, Stack<media_output> *stack)
157 {
158 	server_publish_outputs_request request;
159 	server_publish_outputs_reply reply;
160 	media_output *output;
161 	media_output *outputs;
162 	int32 count;
163 	status_t rv;
164 
165 	count = stack->CountItems();
166 	TRACE("PublishOutputs: publishing %ld\n", count);
167 
168 	request.node = node;
169 	request.count = count;
170 	if (count > MAX_OUTPUTS) {
171 		void *start_addr;
172 		size_t size;
173 		size = ((count * sizeof(media_output)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
174 		request.area = create_area("publish outputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
175 		if (request.area < B_OK) {
176 			TRACE("PublishOutputs: failed to create area, %#lx\n", request.area);
177 			return (status_t)request.area;
178 		}
179 		outputs = static_cast<media_output *>(start_addr);
180 	} else {
181 		request.area = -1;
182 		outputs = request.outputs;
183 	}
184 	TRACE("PublishOutputs: area %#lx\n", request.area);
185 
186 	for (int32 i = 0; i != count; i++) {
187 		stack->GetPointerAt(i, &output);
188 		outputs[i] = *output;
189 	}
190 
191 	rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request), &reply, sizeof(reply));
192 
193 	if (request.area != -1)
194 		delete_area(request.area);
195 
196 	return rv;
197 }
198 
199 status_t
200 PublishInputs(const media_node & node, Stack<media_input> *stack)
201 {
202 	server_publish_inputs_request request;
203 	server_publish_inputs_reply reply;
204 	media_input *input;
205 	media_input *inputs;
206 	int32 count;
207 	status_t rv;
208 
209 	count = stack->CountItems();
210 	TRACE("PublishInputs: publishing %ld\n", count);
211 
212 	request.node = node;
213 	request.count = count;
214 	if (count > MAX_INPUTS) {
215 		void *start_addr;
216 		size_t size;
217 		size = ((count * sizeof(media_input)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
218 		request.area = create_area("publish inputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
219 		if (request.area < B_OK) {
220 			TRACE("PublishInputs: failed to create area, %#lx\n", request.area);
221 			return (status_t)request.area;
222 		}
223 		inputs = static_cast<media_input *>(start_addr);
224 	} else {
225 		request.area = -1;
226 		inputs = request.inputs;
227 	}
228 	TRACE("PublishInputs: area %#lx\n", request.area);
229 
230 	for (int32 i = 0; i != count; i++) {
231 		stack->GetPointerAt(i, &input);
232 		inputs[i] = *input;
233 	}
234 
235 	rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request), &reply, sizeof(reply));
236 
237 	if (request.area != -1)
238 		delete_area(request.area);
239 
240 	return rv;
241 }
242 
243 } } } // namespace BPrivate::media::mediaroster
244 
245 using namespace BPrivate::media::mediaroster;
246 
247 /*************************************************************
248  * public BMediaRoster
249  *************************************************************/
250 
251 status_t
252 BMediaRoster::GetVideoInput(media_node * out_node)
253 {
254 	CALLED();
255 	return GetNode(VIDEO_INPUT, out_node);
256 }
257 
258 
259 status_t
260 BMediaRoster::GetAudioInput(media_node * out_node)
261 {
262 	CALLED();
263 	return GetNode(AUDIO_INPUT, out_node);
264 }
265 
266 
267 status_t
268 BMediaRoster::GetVideoOutput(media_node * out_node)
269 {
270 	CALLED();
271 	return GetNode(VIDEO_OUTPUT, out_node);
272 }
273 
274 
275 status_t
276 BMediaRoster::GetAudioMixer(media_node * out_node)
277 {
278 	CALLED();
279 	return GetNode(AUDIO_MIXER, out_node);
280 }
281 
282 
283 status_t
284 BMediaRoster::GetAudioOutput(media_node * out_node)
285 {
286 	CALLED();
287 	return GetNode(AUDIO_OUTPUT, out_node);
288 }
289 
290 
291 status_t
292 BMediaRoster::GetAudioOutput(media_node * out_node,
293 							 int32 * out_input_id,
294 							 BString * out_input_name)
295 {
296 	CALLED();
297 	return GetNode(AUDIO_OUTPUT_EX, out_node, out_input_id, out_input_name);
298 }
299 
300 
301 status_t
302 BMediaRoster::GetTimeSource(media_node * out_node)
303 {
304 	CALLED();
305 	return GetNode(TIME_SOURCE, out_node);
306 }
307 
308 
309 status_t
310 BMediaRoster::SetVideoInput(const media_node & producer)
311 {
312 	CALLED();
313 	return SetNode(VIDEO_INPUT, &producer);
314 }
315 
316 
317 status_t
318 BMediaRoster::SetVideoInput(const dormant_node_info & producer)
319 {
320 	CALLED();
321 	return SetNode(VIDEO_INPUT, NULL, &producer);
322 }
323 
324 
325 status_t
326 BMediaRoster::SetAudioInput(const media_node & producer)
327 {
328 	CALLED();
329 	return SetNode(AUDIO_INPUT, &producer);
330 }
331 
332 
333 status_t
334 BMediaRoster::SetAudioInput(const dormant_node_info & producer)
335 {
336 	CALLED();
337 	return SetNode(AUDIO_INPUT, NULL, &producer);
338 }
339 
340 
341 status_t
342 BMediaRoster::SetVideoOutput(const media_node & consumer)
343 {
344 	CALLED();
345 	return SetNode(VIDEO_OUTPUT, &consumer);
346 }
347 
348 
349 status_t
350 BMediaRoster::SetVideoOutput(const dormant_node_info & consumer)
351 {
352 	CALLED();
353 	return SetNode(VIDEO_OUTPUT, NULL, &consumer);
354 }
355 
356 
357 status_t
358 BMediaRoster::SetAudioOutput(const media_node & consumer)
359 {
360 	CALLED();
361 	return SetNode(AUDIO_OUTPUT, &consumer);
362 }
363 
364 
365 status_t
366 BMediaRoster::SetAudioOutput(const media_input & input_to_output)
367 {
368 	CALLED();
369 	return SetNode(AUDIO_OUTPUT, NULL, NULL, &input_to_output);
370 }
371 
372 
373 status_t
374 BMediaRoster::SetAudioOutput(const dormant_node_info & consumer)
375 {
376 	CALLED();
377 	return SetNode(AUDIO_OUTPUT, NULL, &consumer);
378 }
379 
380 
381 status_t
382 BMediaRoster::GetNodeFor(media_node_id node,
383 						 media_node * clone)
384 {
385 	CALLED();
386 	if (clone == NULL)
387 		return B_BAD_VALUE;
388 	if (node <= 0)
389 		return B_MEDIA_BAD_NODE;
390 
391 	server_get_node_for_request request;
392 	server_get_node_for_reply reply;
393 	status_t rv;
394 
395 	request.nodeid = node;
396 	request.team = team;
397 
398 	rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply));
399 	if (rv != B_OK)
400 		return rv;
401 
402 	*clone = reply.clone;
403 	return B_OK;
404 }
405 
406 
407 status_t
408 BMediaRoster::GetSystemTimeSource(media_node * clone)
409 {
410 	CALLED();
411 	return GetNode(SYSTEM_TIME_SOURCE, clone);
412 }
413 
414 
415 status_t
416 BMediaRoster::ReleaseNode(const media_node & node)
417 {
418 	CALLED();
419 	if (node.node <= 0)
420 		return B_MEDIA_BAD_NODE;
421 
422 	server_release_node_request request;
423 	server_release_node_reply reply;
424 
425 	request.node = node;
426 	request.team = team;
427 
428 	return QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply, sizeof(reply));
429 }
430 
431 
432 BTimeSource *
433 BMediaRoster::MakeTimeSourceFor(const media_node & for_node)
434 {
435 	BROKEN();
436 	return new _SysTimeSource(); // XXX fix this
437 }
438 
439 
440 status_t
441 BMediaRoster::Connect(const media_source & from,
442 					  const media_destination & to,
443 					  media_format * io_format,
444 					  media_output * out_output,
445 					  media_input * out_input)
446 {
447 	return BMediaRoster::Connect(from, to, io_format, out_output, out_input, 0);
448 }
449 
450 
451 status_t
452 BMediaRoster::Connect(const media_source & from,
453 					  const media_destination & to,
454 					  media_format * io_format,
455 					  media_output * out_output,
456 					  media_input * out_input,
457 					  uint32 in_flags,
458 					  void * _reserved)
459 {
460 	CALLED();
461 	if (io_format == NULL || out_output == NULL || out_input == NULL)
462 		return B_BAD_VALUE;
463 	if (from == media_source::null) {
464 		TRACE("BMediaRoster::Connect: media_source invalid\n");
465 		return B_MEDIA_BAD_SOURCE;
466 	}
467 	if (to == media_destination::null) {
468 		TRACE("BMediaRoster::Connect: media_destination invalid\n");
469 		return B_MEDIA_BAD_DESTINATION;
470 	}
471 
472 	status_t rv;
473 	producer_format_proposal_request request1;
474 	producer_format_proposal_reply reply1;
475 
476 	// BBufferProducer::FormatProposal
477 	request1.output = from;
478 	request1.format = *io_format;
479 	rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1, sizeof(request1), &reply1, sizeof(reply1));
480 	if (rv != B_OK) {
481 		TRACE("BMediaRoster::Connect: aborted after BBufferProducer::FormatProposal, status = %#lx\n",rv);
482 		return rv;
483 	}
484 	// reply1.format now contains the format proposed by the producer
485 
486 	consumer_accept_format_request request2;
487 	consumer_accept_format_reply reply2;
488 
489 	// BBufferConsumer::AcceptFormat
490 	request2.dest = to;
491 	request2.format = reply1.format;
492 	rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2, sizeof(request2), &reply2, sizeof(reply2));
493 	if (rv != B_OK) {
494 		TRACE("BMediaRoster::Connect: aborted after BBufferConsumer::AcceptFormat, status = %#lx\n",rv);
495 		return rv;
496 	}
497 	// reply2.format now contains the format accepted by the consumer
498 
499 	// BBufferProducer::PrepareToConnect
500 	producer_prepare_to_connect_request request3;
501 	producer_prepare_to_connect_reply reply3;
502 
503 	request3.source = from;
504 	request3.destination = to;
505 	request3.format = reply2.format;
506 	strcpy(request3.name, "XXX some default name"); // XXX fix this
507 	rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3, sizeof(request3), &reply3, sizeof(reply3));
508 	if (rv != B_OK) {
509 		TRACE("BMediaRoster::Connect: aborted after BBufferProducer::PrepareToConnect, status = %#lx\n",rv);
510 		return rv;
511 	}
512 	// reply3.format is still our pretty media format
513 	// reply3.out_source the real source to be used for the connection
514 	// reply3.name the name BBufferConsumer::Connected will see in the outInput->name argument
515 
516 	// BBufferConsumer::Connected
517 	consumer_connected_request request4;
518 	consumer_connected_reply reply4;
519 	status_t con_status;
520 
521 	request4.producer = reply3.out_source;
522 	request4.where = to;
523 	request4.with_format = reply3.format;
524 	con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4, sizeof(request4), &reply4, sizeof(reply4));
525 	if (con_status != B_OK) {
526 		TRACE("BMediaRoster::Connect: aborting after BBufferConsumer::Connected, status = %#lx\n",con_status);
527 		// we do NOT return here!
528 	}
529 	// con_status contains the status code to be supplied to BBufferProducer::Connect's status argument
530 	// reply4.input contains the media_input that describes the connection from the consumer point of view
531 
532 	// BBufferProducer::Connect
533 	producer_connect_request request5;
534 	producer_connect_reply reply5;
535 
536 	request5.error = con_status;
537 	request5.source = reply3.out_source;
538 	request5.destination = reply4.input.destination;
539 	request5.format = reply3.format; // XXX reply4.input.format ???
540 	strcpy(request5.name, reply4.input.name);
541 	rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5, sizeof(request5), &reply5, sizeof(reply5));
542 	if (con_status != B_OK) {
543 		TRACE("BMediaRoster::Connect: aborted\n");
544 		return con_status;
545 	}
546 	if (rv != B_OK) {
547 		TRACE("BMediaRoster::Connect: aborted after BBufferProducer::Connect, status = %#lx\n",rv);
548 		return rv;
549 	}
550 	// reply5.name contains the name assigned to the connection by the producer
551 
552 	// find the output node
553 	// XXX isn't there a easier way?
554 	media_node sourcenode;
555 	GetNodeFor(NodeIDFor(from.port), &sourcenode);
556 	ReleaseNode(sourcenode);
557 
558 	// initilize connection info
559 	*io_format = reply3.format;
560 	*out_input = reply4.input;
561 	out_output->node = sourcenode;
562 	out_output->source = reply4.input.source;
563 	out_output->destination = reply4.input.destination;
564 	out_output->format = reply4.input.format;
565 	strcpy(out_output->name, reply5.name);
566 
567 	// the connection is now made
568 
569 
570 	// XXX register connection with server
571 	// XXX we should just send a notification, instead of republishing all endpoints
572 	Stack<media_output> outstack;
573 	Stack<media_input> instack;
574 	if (B_OK == GetAllOutputs(out_output->node , &outstack))
575 		PublishOutputs(out_output->node , &outstack);
576 	if (B_OK == GetAllInputs(out_input->node , &instack))
577 		PublishInputs(out_input->node, &instack);
578 
579 
580 	// XXX if (mute) BBufferProducer::EnableOutput(false)
581 	if (in_flags & B_CONNECT_MUTED) {
582 	}
583 
584 
585 	// send a notification
586 	BPrivate::media::notifications::ConnectionMade(*out_input, *out_output, *io_format);
587 
588 	return B_OK;
589 };
590 
591 
592 status_t
593 BMediaRoster::Disconnect(media_node_id source_nodeid,
594 						 const media_source & source,
595 						 media_node_id destination_nodeid,
596 						 const media_destination & destination)
597 {
598 	CALLED();
599 	if (source_nodeid <= 0) {
600 		TRACE("BMediaRoster::Disconnect: source media_node_id invalid\n");
601 		return B_MEDIA_BAD_SOURCE;
602 	}
603 	if (destination_nodeid <= 0) {
604 		TRACE("BMediaRoster::Disconnect: source media_node_id invalid\n");
605 		return B_MEDIA_BAD_DESTINATION;
606 	}
607 	if (source == media_source::null) {
608 		TRACE("BMediaRoster::Disconnect: media_source invalid\n");
609 		return B_MEDIA_BAD_SOURCE;
610 	}
611 	if (destination == media_destination::null) {
612 		TRACE("BMediaRoster::Disconnect: media_destination invalid\n");
613 		return B_MEDIA_BAD_DESTINATION;
614 	}
615 
616 	producer_disconnect_request request2;
617 	producer_disconnect_reply reply2;
618 	consumer_disconnected_request request1;
619 	consumer_disconnected_reply reply1;
620 	status_t rv1, rv2;
621 
622 	// XXX we should ask the server if this connection really exists
623 
624 	request1.source = source;
625 	request1.destination = destination;
626 	request2.source = source;
627 	request2.destination = destination;
628 
629 	rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1, sizeof(request1), &reply1, sizeof(reply1));
630 	rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2, sizeof(request2), &reply2, sizeof(reply2));
631 
632 	// XXX unregister connection with server
633 	// XXX we should just send a notification, instead of republishing all endpoints
634 	Stack<media_output> outstack;
635 	Stack<media_input> instack;
636 	media_node sourcenode;
637 	media_node destnode;
638 	if (B_OK == GetNodeFor(source_nodeid, &sourcenode)) {
639 		if (B_OK == GetAllOutputs(sourcenode , &outstack))
640 			PublishOutputs(sourcenode , &outstack);
641 		ReleaseNode(sourcenode);
642 	} else TRACE("BMediaRoster::Disconnect: source GetNodeFor failed\n");
643 	if (B_OK == GetNodeFor(destination_nodeid, &destnode)) {
644 		if (B_OK == GetAllInputs(destnode , &instack))
645 			PublishInputs(destnode, &instack);
646 		ReleaseNode(destnode);
647 	} else TRACE("BMediaRoster::Disconnect: dest GetNodeFor failed\n");
648 
649 
650 	// send a notification
651 	BPrivate::media::notifications::ConnectionBroken(source, destination);
652 
653 	return (rv1 != B_OK || rv2 != B_OK) ? B_ERROR : B_OK;
654 }
655 
656 
657 status_t
658 BMediaRoster::StartNode(const media_node & node,
659 						bigtime_t at_performance_time)
660 {
661 	CALLED();
662 	if (node.node <= 0)
663 		return B_MEDIA_BAD_NODE;
664 
665 	node_start_command msg;
666 	msg.performance_time = at_performance_time;
667 
668 	return write_port(node.port, NODE_START, &msg, sizeof(msg));
669 }
670 
671 
672 status_t
673 BMediaRoster::StopNode(const media_node & node,
674 					   bigtime_t at_performance_time,
675 					   bool immediate)
676 {
677 	CALLED();
678 	if (node.node <= 0)
679 		return B_MEDIA_BAD_NODE;
680 
681 	node_stop_command msg;
682 	msg.performance_time = at_performance_time;
683 	msg.immediate = immediate;
684 
685 	return write_port(node.port, NODE_STOP, &msg, sizeof(msg));
686 }
687 
688 
689 status_t
690 BMediaRoster::SeekNode(const media_node & node,
691 					   bigtime_t to_media_time,
692 					   bigtime_t at_performance_time)
693 {
694 	CALLED();
695 	if (node.node <= 0)
696 		return B_MEDIA_BAD_NODE;
697 
698 	node_seek_command msg;
699 	msg.media_time = to_media_time;
700 	msg.performance_time = at_performance_time;
701 
702 	return write_port(node.port, NODE_SEEK, &msg, sizeof(msg));
703 }
704 
705 
706 status_t
707 BMediaRoster::StartTimeSource(const media_node & node,
708 							  bigtime_t at_real_time)
709 {
710 	CALLED();
711 	if (node.node <= 0)
712 		return B_MEDIA_BAD_NODE;
713 	if ((node.kind & B_TIME_SOURCE) == 0)
714 		return B_MEDIA_BAD_NODE;
715 
716 	BTimeSource::time_source_op_info msg;
717 	msg.op = BTimeSource::B_TIMESOURCE_START;
718 	msg.real_time = at_real_time;
719 
720 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
721 }
722 
723 
724 status_t
725 BMediaRoster::StopTimeSource(const media_node & node,
726 							 bigtime_t at_real_time,
727 							 bool immediate)
728 {
729 	CALLED();
730 	if (node.node <= 0)
731 		return B_MEDIA_BAD_NODE;
732 	if ((node.kind & B_TIME_SOURCE) == 0)
733 		return B_MEDIA_BAD_NODE;
734 
735 	BTimeSource::time_source_op_info msg;
736 	msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY : BTimeSource::B_TIMESOURCE_STOP;
737 	msg.real_time = at_real_time;
738 
739 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
740 }
741 
742 
743 status_t
744 BMediaRoster::SeekTimeSource(const media_node & node,
745 							 bigtime_t to_performance_time,
746 							 bigtime_t at_real_time)
747 {
748 	CALLED();
749 	if (node.node <= 0)
750 		return B_MEDIA_BAD_NODE;
751 	if ((node.kind & B_TIME_SOURCE) == 0)
752 		return B_MEDIA_BAD_NODE;
753 
754 	BTimeSource::time_source_op_info msg;
755 	msg.op = BTimeSource::B_TIMESOURCE_SEEK;
756 	msg.real_time = at_real_time;
757 	msg.performance_time = to_performance_time;
758 
759 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
760 }
761 
762 
763 status_t
764 BMediaRoster::SyncToNode(const media_node & node,
765 						 bigtime_t at_time,
766 						 bigtime_t timeout)
767 {
768 	UNIMPLEMENTED();
769 	return B_ERROR;
770 }
771 
772 
773 status_t
774 BMediaRoster::SetRunModeNode(const media_node & node,
775 							 BMediaNode::run_mode mode)
776 {
777 	CALLED();
778 	if (node.node <= 0)
779 		return B_MEDIA_BAD_NODE;
780 
781 	node_set_run_mode_command msg;
782 	msg.mode = mode;
783 
784 	return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg));
785 }
786 
787 
788 status_t
789 BMediaRoster::PrerollNode(const media_node & node)
790 {
791 	CALLED();
792 	if (node.node <= 0)
793 		return B_MEDIA_BAD_NODE;
794 
795 	char dummy;
796 	return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy));
797 }
798 
799 
800 status_t
801 BMediaRoster::RollNode(const media_node & node,
802 					   bigtime_t startPerformance,
803 					   bigtime_t stopPerformance,
804 					   bigtime_t atMediaTime)
805 {
806 	UNIMPLEMENTED();
807 	return B_ERROR;
808 }
809 
810 
811 status_t
812 BMediaRoster::SetProducerRunModeDelay(const media_node & node,
813 									  bigtime_t delay,
814 									  BMediaNode::run_mode mode)
815 {
816 	UNIMPLEMENTED();
817 	return B_ERROR;
818 }
819 
820 
821 status_t
822 BMediaRoster::SetProducerRate(const media_node & producer,
823 							  int32 numer,
824 							  int32 denom)
825 {
826 	CALLED();
827 	if (producer.node == 0)
828 		return B_MEDIA_BAD_NODE;
829 	if ((producer.kind & B_BUFFER_PRODUCER) == 0)
830 		return B_MEDIA_BAD_NODE;
831 
832 	producer_set_play_rate_request msg;
833 	producer_set_play_rate_reply reply;
834 	status_t rv;
835 	int32 code;
836 
837 	msg.numer = numer;
838 	msg.denom = denom;
839 	msg.reply_port = _PortPool->GetPort();
840 	rv = write_port(producer.node, PRODUCER_SET_PLAY_RATE, &msg, sizeof(msg));
841 	if (rv != B_OK) {
842 		_PortPool->PutPort(msg.reply_port);
843 		return rv;
844 	}
845 	rv = read_port(msg.reply_port, &code, &reply, sizeof(reply));
846 	_PortPool->PutPort(msg.reply_port);
847 	return (rv < B_OK) ? rv : reply.result;
848 }
849 
850 
851 /* Nodes will have available inputs/outputs as long as they are capable */
852 /* of accepting more connections. The node may create an additional */
853 /* output or input as the currently available is taken into usage. */
854 status_t
855 BMediaRoster::GetLiveNodeInfo(const media_node & node,
856 							  live_node_info * out_live_info)
857 {
858 	CALLED();
859 	if (out_live_info == NULL)
860 		return B_BAD_VALUE;
861 	if (node.node <= 0)
862 		return B_MEDIA_BAD_NODE;
863 
864 	server_get_live_node_info_request request;
865 	server_get_live_node_info_reply reply;
866 	status_t rv;
867 
868 	request.node = node;
869 
870 	rv = QueryServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request), &reply, sizeof(reply));
871 	if (rv != B_OK)
872 		return rv;
873 
874 	*out_live_info = reply.live_info;
875 	return B_OK;
876 }
877 
878 
879 status_t
880 BMediaRoster::GetLiveNodes(live_node_info * out_live_nodes,
881 						   int32 * io_total_count,
882 						   const media_format * has_input,
883 						   const media_format * has_output,
884 						   const char * name,
885 						   uint64 node_kinds)
886 {
887 	CALLED();
888 	if (out_live_nodes == NULL || io_total_count == NULL)
889 		return B_BAD_VALUE;
890 	if (*io_total_count <= 0)
891 		return B_BAD_VALUE;
892 
893 	// XXX we also support the wildcard search as GetDormantNodes does. This needs to be documented
894 
895 	server_get_live_nodes_request request;
896 	server_get_live_nodes_reply reply;
897 	status_t rv;
898 
899 	request.maxcount = *io_total_count;
900 	request.has_input = (bool) has_input;
901 	if (has_input)
902 		request.inputformat = *has_input; // XXX we should not make a flat copy of media_format
903 	request.has_output = (bool) has_output;
904 	if (has_output)
905 		request.outputformat = *has_output; // XXX we should not make a flat copy of media_format
906 	request.has_name = (bool) name;
907 	if (name) {
908 		int len = strlen(name);
909 		len = min_c(len, (int)sizeof(request.name) - 1);
910 		memcpy(request.name, name, len);
911 		request.name[len] = 0;
912 	}
913 	request.require_kinds = node_kinds;
914 
915 	rv = QueryServer(SERVER_GET_LIVE_NODES, &request, sizeof(request), &reply, sizeof(reply));
916 	if (rv != B_OK) {
917 		TRACE("BMediaRoster::GetLiveNodes failed\n");
918 		*io_total_count = 0;
919 		return rv;
920 	}
921 
922 	if (reply.count > MAX_LIVE_INFO) {
923 		live_node_info *live_info;
924 		area_id clone;
925 
926 		clone = clone_area("live_node_info clone", reinterpret_cast<void **>(&live_info), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, reply.area);
927 		if (clone < B_OK) {
928 			TRACE("BMediaRoster::GetLiveNodes failed to clone area, %#lx\n", clone);
929 			delete_area(reply.area);
930 			*io_total_count = 0;
931 			return B_ERROR;
932 		}
933 
934 		for (int32 i = 0; i < reply.count; i++) {
935 			out_live_nodes[i] = live_info[i];
936 		}
937 
938 		delete_area(clone);
939 		delete_area(reply.area);
940 	} else {
941 		for (int32 i = 0; i < reply.count; i++) {
942 			out_live_nodes[i] = reply.live_info[i];
943 		}
944 	}
945 	*io_total_count = reply.count;
946 
947 	return B_OK;
948 }
949 
950 
951 status_t
952 BMediaRoster::GetFreeInputsFor(const media_node & node,
953 							   media_input * out_free_inputs,
954 							   int32 buf_num_inputs,
955 							   int32 * out_total_count,
956 							   media_type filter_type)
957 {
958 	CALLED();
959 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
960 		return B_MEDIA_BAD_NODE;
961 	if (out_free_inputs == NULL || out_total_count == NULL)
962 		return B_BAD_VALUE;
963 
964 	Stack<media_input> stack;
965 	media_input *input;
966 	status_t rv;
967 
968 	*out_total_count = 0;
969 
970 	rv = GetAllInputs(node, &stack);
971 	if (B_OK != rv)
972 		return rv;
973 
974 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
975 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != input->format.type)
976 			continue; // media_type used, but doesn't match
977 		if (input->source != media_source::null)
978 			continue; // consumer source already connected
979 		out_free_inputs[i] = *input;
980 		*out_total_count += 1;
981 		buf_num_inputs -= 1;
982 		if (buf_num_inputs == 0)
983 			break;
984 	}
985 
986 	PublishInputs(node, &stack);
987 	return B_OK;
988 }
989 
990 
991 status_t
992 BMediaRoster::GetConnectedInputsFor(const media_node & node,
993 									media_input * out_active_inputs,
994 									int32 buf_num_inputs,
995 									int32 * out_total_count)
996 {
997 	CALLED();
998 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
999 		return B_MEDIA_BAD_NODE;
1000 	if (out_active_inputs == NULL || out_total_count == NULL)
1001 		return B_BAD_VALUE;
1002 
1003 	Stack<media_input> stack;
1004 	media_input *input;
1005 	status_t rv;
1006 
1007 	*out_total_count = 0;
1008 
1009 	rv = GetAllInputs(node, &stack);
1010 	if (B_OK != rv)
1011 		return rv;
1012 
1013 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
1014 		if (input->source == media_source::null)
1015 			continue; // consumer source not connected
1016 		out_active_inputs[i] = *input;
1017 		*out_total_count += 1;
1018 		buf_num_inputs -= 1;
1019 		if (buf_num_inputs == 0)
1020 			break;
1021 	}
1022 
1023 	PublishInputs(node, &stack);
1024 	return B_OK;
1025 }
1026 
1027 
1028 status_t
1029 BMediaRoster::GetAllInputsFor(const media_node & node,
1030 							  media_input * out_inputs,
1031 							  int32 buf_num_inputs,
1032 							  int32 * out_total_count)
1033 {
1034 	CALLED();
1035 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
1036 		return B_MEDIA_BAD_NODE;
1037 	if (out_inputs == NULL || out_total_count == NULL)
1038 		return B_BAD_VALUE;
1039 
1040 	Stack<media_input> stack;
1041 	media_input *input;
1042 	status_t rv;
1043 
1044 	*out_total_count = 0;
1045 
1046 	rv = GetAllInputs(node, &stack);
1047 	if (B_OK != rv)
1048 		return rv;
1049 
1050 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
1051 		out_inputs[i] = *input;
1052 		*out_total_count += 1;
1053 		buf_num_inputs -= 1;
1054 		if (buf_num_inputs == 0)
1055 			break;
1056 	}
1057 
1058 	PublishInputs(node, &stack);
1059 	return B_OK;
1060 }
1061 
1062 
1063 status_t
1064 BMediaRoster::GetFreeOutputsFor(const media_node & node,
1065 								media_output * out_free_outputs,
1066 								int32 buf_num_outputs,
1067 								int32 * out_total_count,
1068 								media_type filter_type)
1069 {
1070 	CALLED();
1071 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1072 		return B_MEDIA_BAD_NODE;
1073 	if (out_free_outputs == NULL || out_total_count == NULL)
1074 		return B_BAD_VALUE;
1075 
1076 	Stack<media_output> stack;
1077 	media_output *output;
1078 	status_t rv;
1079 
1080 	*out_total_count = 0;
1081 
1082 	rv = GetAllOutputs(node, &stack);
1083 	if (B_OK != rv)
1084 		return rv;
1085 
1086 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1087 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != output->format.type)
1088 			continue; // media_type used, but doesn't match
1089 		if (output->destination != media_destination::null)
1090 			continue; // producer destination already connected
1091 		out_free_outputs[i] = *output;
1092 		*out_total_count += 1;
1093 		buf_num_outputs -= 1;
1094 		if (buf_num_outputs == 0)
1095 			break;
1096 	}
1097 
1098 	PublishOutputs(node, &stack);
1099 	return B_OK;
1100 }
1101 
1102 
1103 status_t
1104 BMediaRoster::GetConnectedOutputsFor(const media_node & node,
1105 									 media_output * out_active_outputs,
1106 									 int32 buf_num_outputs,
1107 									 int32 * out_total_count)
1108 {
1109 	CALLED();
1110 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1111 		return B_MEDIA_BAD_NODE;
1112 	if (out_active_outputs == NULL || out_total_count == NULL)
1113 		return B_BAD_VALUE;
1114 
1115 	Stack<media_output> stack;
1116 	media_output *output;
1117 	status_t rv;
1118 
1119 	*out_total_count = 0;
1120 
1121 	rv = GetAllOutputs(node, &stack);
1122 	if (B_OK != rv)
1123 		return rv;
1124 
1125 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1126 		if (output->destination == media_destination::null)
1127 			continue; // producer destination not connected
1128 		out_active_outputs[i] = *output;
1129 		*out_total_count += 1;
1130 		buf_num_outputs -= 1;
1131 		if (buf_num_outputs == 0)
1132 			break;
1133 	}
1134 
1135 	PublishOutputs(node, &stack);
1136 	return B_OK;
1137 }
1138 
1139 
1140 status_t
1141 BMediaRoster::GetAllOutputsFor(const media_node & node,
1142 							   media_output * out_outputs,
1143 							   int32 buf_num_outputs,
1144 							   int32 * out_total_count)
1145 {
1146 	CALLED();
1147 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1148 		return B_MEDIA_BAD_NODE;
1149 	if (out_outputs == NULL || out_total_count == NULL)
1150 		return B_BAD_VALUE;
1151 
1152 	Stack<media_output> stack;
1153 	media_output *output;
1154 	status_t rv;
1155 
1156 	*out_total_count = 0;
1157 
1158 	rv = GetAllOutputs(node, &stack);
1159 	if (B_OK != rv)
1160 		return rv;
1161 
1162 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1163 		out_outputs[i] = *output;
1164 		*out_total_count += 1;
1165 		buf_num_outputs -= 1;
1166 		if (buf_num_outputs == 0)
1167 			break;
1168 	}
1169 
1170 	PublishOutputs(node, &stack);
1171 	return B_OK;
1172 }
1173 
1174 
1175 status_t
1176 BMediaRoster::StartWatching(const BMessenger & where)
1177 {
1178 	CALLED();
1179 	if (!where.IsValid()) {
1180 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1181 		return B_BAD_VALUE;
1182 	}
1183 	return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD);
1184 }
1185 
1186 
1187 status_t
1188 BMediaRoster::StartWatching(const BMessenger & where,
1189 							int32 notificationType)
1190 {
1191 	CALLED();
1192 	if (!where.IsValid()) {
1193 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1194 		return B_BAD_VALUE;
1195 	}
1196 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1197 		TRACE("BMediaRoster::StartWatching: notificationType invalid!\n");
1198 		return B_BAD_VALUE;
1199 	}
1200 	return BPrivate::media::notifications::Register(where, media_node::null, notificationType);
1201 }
1202 
1203 
1204 status_t
1205 BMediaRoster::StartWatching(const BMessenger & where,
1206 							const media_node & node,
1207 							int32 notificationType)
1208 {
1209 	CALLED();
1210 	if (!where.IsValid()) {
1211 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1212 		return B_BAD_VALUE;
1213 	}
1214 	if (node.node <= 0) {
1215 		TRACE("BMediaRoster::StartWatching: node invalid!\n");
1216 		return B_MEDIA_BAD_NODE;
1217 	}
1218 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1219 		TRACE("BMediaRoster::StartWatching: notificationType invalid!\n");
1220 		return B_BAD_VALUE;
1221 	}
1222 	return BPrivate::media::notifications::Register(where, node, notificationType);
1223 }
1224 
1225 
1226 status_t
1227 BMediaRoster::StopWatching(const BMessenger & where)
1228 {
1229 	CALLED();
1230 	// messenger may already be invalid, so we don't check this
1231 	return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD);
1232 }
1233 
1234 
1235 status_t
1236 BMediaRoster::StopWatching(const BMessenger & where,
1237 						   int32 notificationType)
1238 {
1239 	CALLED();
1240 	// messenger may already be invalid, so we don't check this
1241 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1242 		TRACE("BMediaRoster::StopWatching: notificationType invalid!\n");
1243 		return B_BAD_VALUE;
1244 	}
1245 	return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType);
1246 }
1247 
1248 
1249 status_t
1250 BMediaRoster::StopWatching(const BMessenger & where,
1251 						   const media_node & node,
1252 						   int32 notificationType)
1253 {
1254 	CALLED();
1255 	// messenger may already be invalid, so we don't check this
1256 	if (node.node <= 0) {
1257 		TRACE("BMediaRoster::StopWatching: node invalid!\n");
1258 		return B_MEDIA_BAD_NODE;
1259 	}
1260 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1261 		TRACE("BMediaRoster::StopWatching: notificationType invalid!\n");
1262 		return B_BAD_VALUE;
1263 	}
1264 	return BPrivate::media::notifications::Unregister(where, node, notificationType);
1265 }
1266 
1267 
1268 status_t
1269 BMediaRoster::RegisterNode(BMediaNode * node)
1270 {
1271 	CALLED();
1272 	if (node == NULL)
1273 		return B_BAD_VALUE;
1274 
1275 	status_t rv;
1276 	BMediaAddOn *addon;
1277 	int32 addon_flavor_id;
1278 	media_addon_id addon_id;
1279 
1280 	addon_flavor_id = 0;
1281 	addon = node->AddOn(&addon_flavor_id);
1282 	addon_id = addon ? addon->AddonID() : -1;
1283 
1284 	server_register_node_request request;
1285 	server_register_node_reply reply;
1286 
1287 	request.addon_id = addon_id;
1288 	request.addon_flavor_id = addon_flavor_id;
1289 	strcpy(request.name, node->Name());
1290 	request.kinds = node->Kinds();
1291 	request.port = node->ControlPort();
1292 	request.team = team;
1293 
1294 	TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port %ld, kinds %#Lx, team %ld, name '%s'\n", request.port, request.kinds, request.team, request.name);
1295 
1296 	rv = QueryServer(SERVER_REGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1297 	if (rv != B_OK) {
1298 		TRACE("BMediaRoster::RegisterNode: failed to register node %s (error %#lx)\n", node->Name(), rv);
1299 		return rv;
1300 	}
1301 
1302 	// we are a friend class of BMediaNode and initilize this member variable
1303 	node->fNodeID = reply.nodeid;
1304 	ASSERT(reply.nodeid == node->Node().node);
1305 	ASSERT(reply.nodeid == node->ID());
1306 
1307 	// call the callback
1308 	node->NodeRegistered();
1309 
1310 /*
1311 	// register existing inputs and outputs with the
1312 	// media_server, this allows GetLiveNodes() to work
1313 	// with created, but unconnected nodes.
1314 	if (node->Kinds() & B_BUFFER_PRODUCER) {
1315 		Stack<media_output> stack;
1316 		if (B_OK == GetAllOutputs(node->Node(), &stack))
1317 			PublishOutputs(node->Node(), &stack);
1318 	} else if (node->Kinds() & B_BUFFER_CONSUMER) {
1319 		Stack<media_input> stack;
1320 		if (B_OK == GetAllInputs(node->Node(), &stack))
1321 			PublishInputs(node->Node(), &stack);
1322 	}
1323 */
1324 
1325 	BPrivate::media::notifications::NodesCreated(&reply.nodeid, 1);
1326 /*
1327 	TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id);
1328 	TRACE("BMediaRoster::RegisterNode: node this               %p\n", node);
1329 	TRACE("BMediaRoster::RegisterNode: node fConsumerThis      %p\n", node->fConsumerThis);
1330 	TRACE("BMediaRoster::RegisterNode: node fProducerThis      %p\n", node->fProducerThis);
1331 	TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n", node->fFileInterfaceThis);
1332 	TRACE("BMediaRoster::RegisterNode: node fControllableThis  %p\n", node->fControllableThis);
1333 	TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis    %p\n", node->fTimeSourceThis);
1334 */
1335 
1336 	return B_OK;
1337 }
1338 
1339 
1340 status_t
1341 BMediaRoster::UnregisterNode(BMediaNode * node)
1342 {
1343 	CALLED();
1344 	if (node == NULL)
1345 		return B_BAD_VALUE;
1346 
1347 	if (node->fRefCount != 0) {
1348 		TRACE("BMediaRoster::UnregisterNode: Warning node name '%s' has local reference count of %ld\n", node->Name(), node->fRefCount);
1349 		// no return here, we continue and unregister!
1350 	}
1351 	if (node->ID() == -2) {
1352 		TRACE("BMediaRoster::UnregisterNode: Warning node name '%s' already unregistered\n", node->Name());
1353 		return B_OK;
1354 	}
1355 
1356 	server_unregister_node_request request;
1357 	server_unregister_node_reply reply;
1358 	status_t rv;
1359 
1360 	request.nodeid = node->ID();
1361 	request.team = team;
1362 
1363 	// send a notification
1364 	BPrivate::media::notifications::NodesDeleted(&request.nodeid, 1);
1365 
1366 	rv = QueryServer(SERVER_UNREGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1367 	if (rv != B_OK) {
1368 		TRACE("BMediaRoster::UnregisterNode: failed to unregister node name '%s' (error %#lx)\n", node->Name(), rv);
1369 		return rv;
1370 	}
1371 
1372 	if (reply.addon_id != -1)
1373 		_DormantNodeManager->PutAddon(reply.addon_id);
1374 
1375 	// we are a friend class of BMediaNode and invalidate this member variable
1376 	node->fNodeID = -2;
1377 
1378 	return B_OK;
1379 }
1380 
1381 
1382 //	thread safe for multiple calls to Roster()
1383 /* static */ BMediaRoster *
1384 BMediaRoster::Roster(status_t* out_error)
1385 {
1386 	static BLocker locker("BMediaRoster::Roster locker");
1387 	locker.Lock();
1388 	if (_sDefault == NULL) {
1389 		_sDefault = new BMediaRoster();
1390 		if (out_error != NULL)
1391 			*out_error = B_OK;
1392 	} else {
1393 		if (out_error != NULL)
1394 			*out_error = B_OK;
1395 	}
1396 	locker.Unlock();
1397 	return _sDefault;
1398 }
1399 
1400 
1401 //	won't create it if there isn't one
1402 //	not thread safe if you call Roster() at the same time
1403 /* static */ BMediaRoster *
1404 BMediaRoster::CurrentRoster()
1405 {
1406 	return _sDefault;
1407 }
1408 
1409 
1410 status_t
1411 BMediaRoster::SetTimeSourceFor(media_node_id node,
1412 							   media_node_id time_source)
1413 {
1414 	UNIMPLEMENTED();
1415 	return B_ERROR;
1416 }
1417 
1418 
1419 status_t
1420 BMediaRoster::GetParameterWebFor(const media_node & node,
1421 								 BParameterWeb ** out_web)
1422 {
1423 	UNIMPLEMENTED();
1424 	return B_ERROR;
1425 }
1426 
1427 
1428 status_t
1429 BMediaRoster::StartControlPanel(const media_node & node,
1430 								BMessenger * out_messenger)
1431 {
1432 	UNIMPLEMENTED();
1433 	return B_ERROR;
1434 }
1435 
1436 
1437 status_t
1438 BMediaRoster::GetDormantNodes(dormant_node_info * out_info,
1439 							  int32 * io_count,
1440 							  const media_format * has_input /* = NULL */,
1441 							  const media_format * has_output /* = NULL */,
1442 							  const char * name /* = NULL */,
1443 							  uint64 require_kinds /* = NULL */,
1444 							  uint64 deny_kinds /* = NULL */)
1445 {
1446 	CALLED();
1447 	if (out_info == NULL)
1448 		return B_BAD_VALUE;
1449 	if (io_count == NULL)
1450 		return B_BAD_VALUE;
1451 	if (*io_count <= 0)
1452 		return B_BAD_VALUE;
1453 
1454 	xfer_server_get_dormant_nodes msg;
1455 	port_id port;
1456 	status_t rv;
1457 
1458 	port = find_port("media_server port");
1459 	if (port <= B_OK)
1460 		return B_ERROR;
1461 
1462 	msg.maxcount = *io_count;
1463 	msg.has_input = (bool) has_input;
1464 	if (has_input)
1465 		msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format
1466 	msg.has_output = (bool) has_output;
1467 	if (has_output)
1468 		msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format
1469 	msg.has_name = (bool) name;
1470 	if (name) {
1471 		int len = strlen(name);
1472 		len = min_c(len, (int)sizeof(msg.name) - 1);
1473 		memcpy(msg.name, name, len);
1474 		msg.name[len] = 0;
1475 	}
1476 	msg.require_kinds = require_kinds;
1477 	msg.deny_kinds = deny_kinds;
1478 	msg.reply_port = _PortPool->GetPort();
1479 
1480 	rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg));
1481 	if (rv != B_OK) {
1482 		_PortPool->PutPort(msg.reply_port);
1483 		return rv;
1484 	}
1485 
1486 	xfer_server_get_dormant_nodes_reply reply;
1487 	int32 code;
1488 
1489 	rv = read_port(msg.reply_port, &code, &reply, sizeof(reply));
1490 	if (rv < B_OK) {
1491 		_PortPool->PutPort(msg.reply_port);
1492 		return rv;
1493 	}
1494 
1495 	*io_count = reply.count;
1496 
1497 	if (*io_count > 0) {
1498 		rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info));
1499 		if (rv < B_OK)
1500 			reply.result = rv;
1501 	}
1502 	_PortPool->PutPort(msg.reply_port);
1503 
1504 	return reply.result;
1505 }
1506 
1507 
1508 status_t
1509 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
1510 									 media_node * out_node,
1511 									 uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ )
1512 {
1513 	CALLED();
1514 	if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) {
1515 		printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n");
1516 		return B_BAD_VALUE;
1517 	}
1518 	if (out_node == 0)
1519 		return B_BAD_VALUE;
1520 
1521 	// XXX we should not trust the values passed in by the user,
1522 	// XXX and ask the server to determine where to insta
1523 
1524 
1525 // XXX SOMETHING IS VERY WRONG HERE
1526 //	if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) {
1527 	if (flags & B_FLAVOR_IS_LOCAL) {
1528 		return InstantiateDormantNode(in_info,out_node);
1529 	}
1530 
1531 // XXX SOMETHING IS VERY WRONG HERE
1532 //	if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) {
1533 	if (flags & B_FLAVOR_IS_GLOBAL) {
1534 		// forward this request into the media_addon_server,
1535 		// which in turn will call InstantiateDormantNode()
1536 		// to create it there localy
1537 		addonserver_instantiate_dormant_node_request request;
1538 		addonserver_instantiate_dormant_node_reply reply;
1539 		status_t rv;
1540 
1541 		request.info = in_info;
1542 		rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply));
1543 		if (rv == B_OK) {
1544 			*out_node = reply.node;
1545 		}
1546 		return rv;
1547 	}
1548 
1549 // XXX SOMETHING IS VERY WRONG HERE
1550 	printf("Error: BMediaRoster::InstantiateDormantNode addon_id %d, flavor_id %d, flags %#08lx\n", (int)in_info.addon, (int)in_info.flavor_id, flags);
1551 
1552 	return B_ERROR;
1553 }
1554 
1555 
1556 status_t
1557 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
1558 									 media_node * out_node)
1559 {
1560 	CALLED();
1561 
1562 	// to instantiate a dormant node in the current address space, we need to
1563 	// either load the add-on from file and create a new BMediaAddOn class, or
1564 	// reuse the cached BMediaAddOn from a previous call
1565 	// call BMediaAddOn::InstantiateNodeFor()
1566 	// and cache the BMediaAddOn after that for later reuse.
1567 	// BeOS R5 does not seem to delete it when the application quits
1568 	// if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
1569 	// resides in the media_addon_server
1570 
1571 	// RegisterNode() is called automatically for nodes instantiated from add-ons
1572 
1573 	//XXX TEST!
1574 	BMediaAddOn *addon;
1575 	BMediaNode *node;
1576 	BMessage config;
1577 	status_t out_error;
1578 	status_t rv;
1579 	addon = _DormantNodeManager->GetAddon(in_info.addon);
1580 	if (!addon) {
1581 		printf("BMediaRoster::InstantiateDormantNode: GetAddon failed\n");
1582 		return B_ERROR;
1583 	}
1584 	flavor_info temp; // XXX fix this!
1585 	temp.name = "XXX flavor_info name";
1586 	temp.info = "XXX flavor_info info";
1587 	temp.internal_id = in_info.flavor_id;
1588 	node = addon->InstantiateNodeFor(&temp, &config, &out_error);
1589 	if (!node) {
1590 		printf("BMediaRoster::InstantiateDormantNode: InstantiateNodeFor failed\n");
1591 		_DormantNodeManager->PutAddon(in_info.addon);
1592 		return B_ERROR;
1593 	}
1594 	rv = RegisterNode(node);
1595 	if (rv != B_OK) {
1596 		printf("BMediaRoster::InstantiateDormantNode: RegisterNode failed\n");
1597 		delete node;
1598 		_DormantNodeManager->PutAddon(in_info.addon);
1599 		return B_ERROR;
1600 	}
1601 
1602 	// XXX we must remember in_info.addon and call
1603 	// XXX _DormantNodeManager->PutAddon when the
1604 	// XXX node is unregistered
1605 	// should be handled by RegisterNode() and UnegisterNode() now
1606 
1607 	*out_node = node->Node();
1608 	return B_OK;
1609 }
1610 
1611 
1612 status_t
1613 BMediaRoster::GetDormantNodeFor(const media_node & node,
1614 								dormant_node_info * out_info)
1615 {
1616 	CALLED();
1617 	if (out_info == NULL)
1618 		return B_BAD_VALUE;
1619 	if (node.node <= 0)
1620 		return B_MEDIA_BAD_NODE;
1621 
1622 	server_get_dormant_node_for_request request;
1623 	server_get_dormant_node_for_reply reply;
1624 	status_t rv;
1625 
1626 	request.node = node;
1627 
1628 	rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply));
1629 	if (rv != B_OK)
1630 		return rv;
1631 
1632 	*out_info = reply.node_info;
1633 	return B_OK;
1634 }
1635 
1636 
1637 status_t
1638 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant,
1639 									  dormant_flavor_info * out_flavor)
1640 {
1641 	CALLED();
1642 
1643 	xfer_server_get_dormant_flavor_info msg;
1644 	xfer_server_get_dormant_flavor_info_reply *reply;
1645 	port_id port;
1646 	status_t rv;
1647 	int32 code;
1648 
1649 	port = find_port("media_server port");
1650 	if (port <= B_OK)
1651 		return B_ERROR;
1652 
1653 	reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000);
1654 	if (reply == 0)
1655 		return B_ERROR;
1656 
1657 	msg.addon 		= in_dormant.addon;
1658 	msg.flavor_id 	= in_dormant.flavor_id;
1659 	msg.reply_port 	= _PortPool->GetPort();
1660 	rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg));
1661 	if (rv != B_OK) {
1662 		free(reply);
1663 		_PortPool->PutPort(msg.reply_port);
1664 		return rv;
1665 	}
1666 	rv = read_port(msg.reply_port, &code, reply, 16000);
1667 	_PortPool->PutPort(msg.reply_port);
1668 
1669 	if (rv < B_OK) {
1670 		free(reply);
1671 		return rv;
1672 	}
1673 
1674 	if (reply->result == B_OK)
1675 		rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size);
1676 	else
1677 		rv = reply->result;
1678 
1679 	free(reply);
1680 	return rv;
1681 }
1682 
1683 
1684 status_t
1685 BMediaRoster::GetLatencyFor(const media_node & producer,
1686 							bigtime_t * out_latency)
1687 {
1688 	UNIMPLEMENTED();
1689 	*out_latency = 0;
1690 	return B_ERROR;
1691 }
1692 
1693 
1694 status_t
1695 BMediaRoster::GetInitialLatencyFor(const media_node & producer,
1696 								   bigtime_t * out_latency,
1697 								   uint32 * out_flags)
1698 {
1699 	UNIMPLEMENTED();
1700 	*out_latency = 0;
1701 	*out_flags = 0;
1702 	return B_ERROR;
1703 }
1704 
1705 
1706 status_t
1707 BMediaRoster::GetStartLatencyFor(const media_node & time_source,
1708 								 bigtime_t * out_latency)
1709 {
1710 	UNIMPLEMENTED();
1711 	*out_latency = 0;
1712 	return B_ERROR;
1713 }
1714 
1715 
1716 status_t
1717 BMediaRoster::GetFileFormatsFor(const media_node & file_interface,
1718 								media_file_format * out_formats,
1719 								int32 * io_num_infos)
1720 {
1721 	UNIMPLEMENTED();
1722 	return B_ERROR;
1723 }
1724 
1725 
1726 status_t
1727 BMediaRoster::SetRefFor(const media_node & file_interface,
1728 						const entry_ref & file,
1729 						bool create_and_truncate,
1730 						bigtime_t * out_length)	/* if create is false */
1731 {
1732 	UNIMPLEMENTED();
1733 	return B_ERROR;
1734 }
1735 
1736 
1737 status_t
1738 BMediaRoster::GetRefFor(const media_node & node,
1739 						entry_ref * out_file,
1740 						BMimeType * mime_type)
1741 {
1742 	UNIMPLEMENTED();
1743 	return B_ERROR;
1744 }
1745 
1746 
1747 status_t
1748 BMediaRoster::SniffRefFor(const media_node & file_interface,
1749 						  const entry_ref & file,
1750 						  BMimeType * mime_type,
1751 						  float * out_capability)
1752 {
1753 	UNIMPLEMENTED();
1754 	return B_ERROR;
1755 }
1756 
1757 
1758 /* This is the generic "here's a file, now can someone please play it" interface */
1759 status_t
1760 BMediaRoster::SniffRef(const entry_ref & file,
1761 					   uint64 require_node_kinds,		/* if you need an EntityInterface or BufferConsumer or something */
1762 					   dormant_node_info * out_node,
1763 					   BMimeType * mime_type)
1764 {
1765 	UNIMPLEMENTED();
1766 	return B_ERROR;
1767 }
1768 
1769 
1770 status_t
1771 BMediaRoster::GetDormantNodeForType(const BMimeType & type,
1772 									uint64 require_node_kinds,
1773 									dormant_node_info * out_node)
1774 {
1775 	UNIMPLEMENTED();
1776 	return B_ERROR;
1777 }
1778 
1779 
1780 status_t
1781 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node,
1782 									media_file_format * out_read_formats,
1783 									int32 in_read_count,
1784 									int32 * out_read_count)
1785 {
1786 	UNIMPLEMENTED();
1787 	return B_ERROR;
1788 }
1789 
1790 
1791 status_t
1792 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node,
1793 									 media_file_format * out_write_formats,
1794 									 int32 in_write_count,
1795 									 int32 * out_write_count)
1796 {
1797 	UNIMPLEMENTED();
1798 	return B_ERROR;
1799 }
1800 
1801 
1802 status_t
1803 BMediaRoster::GetFormatFor(const media_output & output,
1804 						   media_format * io_format,
1805 						   uint32 flags)
1806 {
1807 	UNIMPLEMENTED();
1808 	return B_ERROR;
1809 }
1810 
1811 
1812 status_t
1813 BMediaRoster::GetFormatFor(const media_input & input,
1814 						   media_format * io_format,
1815 						   uint32 flags)
1816 {
1817 	UNIMPLEMENTED();
1818 	return B_ERROR;
1819 }
1820 
1821 
1822 status_t
1823 BMediaRoster::GetFormatFor(const media_node & node,
1824 						   media_format * io_format,
1825 						   float quality)
1826 {
1827 	UNIMPLEMENTED();
1828 	return B_ERROR;
1829 }
1830 
1831 
1832 ssize_t
1833 BMediaRoster::GetNodeAttributesFor(const media_node & node,
1834 								   media_node_attribute * outArray,
1835 								   size_t inMaxCount)
1836 {
1837 	UNIMPLEMENTED();
1838 	return B_ERROR;
1839 }
1840 
1841 
1842 media_node_id
1843 BMediaRoster::NodeIDFor(port_id source_or_destination_port)
1844 {
1845 	CALLED();
1846 
1847 	server_node_id_for_request request;
1848 	server_node_id_for_reply reply;
1849 	status_t rv;
1850 
1851 	request.port = source_or_destination_port;
1852 
1853 	rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, sizeof(reply));
1854 	if (rv != B_OK) {
1855 		TRACE("BMediaRoster::NodeIDFor: failed (error %#lx)\n", rv);
1856 		return -1;
1857 	}
1858 
1859 	return reply.nodeid;
1860 }
1861 
1862 
1863 status_t
1864 BMediaRoster::GetInstancesFor(media_addon_id addon,
1865 							  int32 flavor,
1866 							  media_node_id * out_id,
1867 							  int32 * io_count)
1868 {
1869 	CALLED();
1870 	if (out_id == NULL || io_count == NULL)
1871 		return B_BAD_VALUE;
1872 	if (*io_count <= 0)
1873 		return B_BAD_VALUE;
1874 
1875 	server_get_instances_for_request request;
1876 	server_get_instances_for_reply reply;
1877 	status_t rv;
1878 
1879 	request.maxcount = *io_count;
1880 	request.addon_id = addon;
1881 	request.addon_flavor_id = flavor;
1882 
1883 	rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), &reply, sizeof(reply));
1884 	if (rv != B_OK) {
1885 		TRACE("BMediaRoster::GetLiveNodes failed\n");
1886 		return rv;
1887 	}
1888 
1889 	*io_count = reply.count;
1890 	if (reply.count > 0)
1891 		memcpy(out_id, reply.node_id, sizeof(media_node_id) * reply.count);
1892 
1893 	return B_OK;
1894 }
1895 
1896 
1897 status_t
1898 BMediaRoster::SetRealtimeFlags(uint32 in_enabled)
1899 {
1900 	UNIMPLEMENTED();
1901 	return B_ERROR;
1902 }
1903 
1904 
1905 status_t
1906 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled)
1907 {
1908 	UNIMPLEMENTED();
1909 	return B_ERROR;
1910 }
1911 
1912 
1913 ssize_t
1914 BMediaRoster::AudioBufferSizeFor(int32 channel_count,
1915 								 uint32 sample_format,
1916 								 float frame_rate,
1917 								 bus_type bus_kind)
1918 {
1919 	UNIMPLEMENTED();
1920 	return 4096;
1921 }
1922 
1923 
1924 /* Use MediaFlags to inquire about specific features of the Media Kit. */
1925 /* Returns < 0 for "not present", positive size for output data size. */
1926 /* 0 means that the capability is present, but no data about it. */
1927 /* static */ ssize_t
1928 BMediaRoster::MediaFlags(media_flags cap,
1929 						 void * buf,
1930 						 size_t maxSize)
1931 {
1932 	UNIMPLEMENTED();
1933 	return 0;
1934 }
1935 
1936 
1937 
1938 /* BLooper overrides */
1939 /* virtual */ void
1940 BMediaRoster::MessageReceived(BMessage * message)
1941 {
1942 	UNIMPLEMENTED();
1943 }
1944 
1945 /* virtual */ bool
1946 BMediaRoster::QuitRequested()
1947 {
1948 	UNIMPLEMENTED();
1949 	return true;
1950 }
1951 
1952 /* virtual */ BHandler *
1953 BMediaRoster::ResolveSpecifier(BMessage *msg,
1954 				 int32 index,
1955 				 BMessage *specifier,
1956 				 int32 form,
1957 				 const char *property)
1958 {
1959 	UNIMPLEMENTED();
1960 	return 0;
1961 }
1962 
1963 
1964 /* virtual */ status_t
1965 BMediaRoster::GetSupportedSuites(BMessage *data)
1966 {
1967 	UNIMPLEMENTED();
1968 	return B_ERROR;
1969 }
1970 
1971 
1972 BMediaRoster::~BMediaRoster()
1973 {
1974 	CALLED();
1975 	BMessage msg(MEDIA_SERVER_UNREGISTER_APP);
1976 	BMessage reply;
1977 	msg.AddInt32("team",team);
1978 	QueryServer(&msg, &reply);
1979 }
1980 
1981 
1982 /*************************************************************
1983  * private BMediaRoster
1984  *************************************************************/
1985 
1986 // deprecated call
1987 status_t
1988 BMediaRoster::SetOutputBuffersFor(const media_source & output,
1989 								  BBufferGroup * group,
1990 								  bool will_reclaim )
1991 {
1992 	UNIMPLEMENTED();
1993 	debugger("BMediaRoster::SetOutputBuffersFor missing\n");
1994 	return B_ERROR;
1995 }
1996 
1997 
1998 /* FBC stuffing (Mmmh, Stuffing!) */
1999 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; }
2000 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; }
2001 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; }
2002 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; }
2003 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; }
2004 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; }
2005 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; }
2006 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; }
2007 
2008 
2009 BMediaRoster::BMediaRoster() :
2010 	BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY)
2011 {
2012 	CALLED();
2013 	BMessage msg(MEDIA_SERVER_REGISTER_APP);
2014 	BMessage reply;
2015 	msg.AddInt32("team",team);
2016 	QueryServer(&msg,&reply);
2017 }
2018 
2019 /* static */ status_t
2020 BMediaRoster::ParseCommand(BMessage & reply)
2021 {
2022 	UNIMPLEMENTED();
2023 	return B_ERROR;
2024 }
2025 
2026 
2027 
2028 status_t
2029 BMediaRoster::GetDefaultInfo(media_node_id for_default,
2030 							 BMessage & out_config)
2031 {
2032 	UNIMPLEMENTED();
2033 	return B_ERROR;
2034 }
2035 
2036 
2037 
2038 status_t
2039 BMediaRoster::SetRunningDefault(media_node_id for_default,
2040 								const media_node & node)
2041 {
2042 	UNIMPLEMENTED();
2043 	return B_ERROR;
2044 }
2045 
2046 
2047 /*************************************************************
2048  * static BMediaRoster variables
2049  *************************************************************/
2050 
2051 bool BMediaRoster::_isMediaServer;
2052 port_id BMediaRoster::_mReplyPort;
2053 int32 BMediaRoster::_mReplyPortRes;
2054 int32 BMediaRoster::_mReplyPortUnavailCount;
2055 BMediaRoster * BMediaRoster::_sDefault = NULL;
2056 
2057