xref: /haiku/src/kits/media/MediaRoster.cpp (revision 85dfab2ba84a3d225d384beb92deb3b658734714)
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 #undef 	DEBUG
15 #define	DEBUG 3
16 #include <Debug.h>
17 #include "debug.h"
18 #include "TStack.h"
19 #include "PortPool.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 	UNIMPLEMENTED();
436 	return 0;
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 	xfer_node_start 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 	xfer_node_stop 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 	xfer_node_seek 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 	xfer_node_set_run_mode 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 	xfer_producer_set_play_rate msg;
833 	xfer_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 = QueryAddonServer(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 		return rv;
919 	}
920 
921 	if (reply.count > MAX_LIVE_INFO) {
922 		live_node_info *live_info;
923 		area_id clone;
924 
925 		clone = clone_area("live_node_info clone", reinterpret_cast<void **>(&live_info), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, reply.area);
926 		if (clone < B_OK) {
927 			TRACE("BMediaRoster::GetLiveNodes failed to clone area, %#lx\n", clone);
928 			delete_area(reply.area);
929 			return B_ERROR;
930 		}
931 
932 		for (int32 i = 0; i < reply.count; i++) {
933 			out_live_nodes[i] = live_info[i];
934 		}
935 
936 		delete_area(clone);
937 		delete_area(reply.area);
938 	} else {
939 		for (int32 i = 0; i < reply.count; i++) {
940 			out_live_nodes[i] = reply.live_info[i];
941 		}
942 	}
943 	*io_total_count = reply.count;
944 
945 	return B_OK;
946 }
947 
948 
949 status_t
950 BMediaRoster::GetFreeInputsFor(const media_node & node,
951 							   media_input * out_free_inputs,
952 							   int32 buf_num_inputs,
953 							   int32 * out_total_count,
954 							   media_type filter_type)
955 {
956 	CALLED();
957 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
958 		return B_MEDIA_BAD_NODE;
959 	if (out_free_inputs == NULL || out_total_count == NULL)
960 		return B_BAD_VALUE;
961 
962 	Stack<media_input> stack;
963 	media_input *input;
964 	status_t rv;
965 
966 	rv = GetAllInputs(node, &stack);
967 	if (B_OK != rv)
968 		return rv;
969 
970 	*out_total_count = 0;
971 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
972 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != input->format.type)
973 			continue; // media_type used, but doesn't match
974 		if (input->source != media_source::null)
975 			continue; // consumer source already connected
976 		out_free_inputs[i] = *input;
977 		*out_total_count += 1;
978 		buf_num_inputs -= 1;
979 		if (buf_num_inputs == 0)
980 			break;
981 	}
982 
983 	PublishInputs(node, &stack);
984 	return B_OK;
985 }
986 
987 
988 status_t
989 BMediaRoster::GetConnectedInputsFor(const media_node & node,
990 									media_input * out_active_inputs,
991 									int32 buf_num_inputs,
992 									int32 * out_total_count)
993 {
994 	CALLED();
995 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
996 		return B_MEDIA_BAD_NODE;
997 	if (out_active_inputs == NULL || out_total_count == NULL)
998 		return B_BAD_VALUE;
999 
1000 	Stack<media_input> stack;
1001 	media_input *input;
1002 	status_t rv;
1003 
1004 	rv = GetAllInputs(node, &stack);
1005 	if (B_OK != rv)
1006 		return rv;
1007 
1008 	*out_total_count = 0;
1009 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
1010 		if (input->source == media_source::null)
1011 			continue; // consumer source not connected
1012 		out_active_inputs[i] = *input;
1013 		*out_total_count += 1;
1014 		buf_num_inputs -= 1;
1015 		if (buf_num_inputs == 0)
1016 			break;
1017 	}
1018 
1019 	PublishInputs(node, &stack);
1020 	return B_OK;
1021 }
1022 
1023 
1024 status_t
1025 BMediaRoster::GetAllInputsFor(const media_node & node,
1026 							  media_input * out_inputs,
1027 							  int32 buf_num_inputs,
1028 							  int32 * out_total_count)
1029 {
1030 	CALLED();
1031 	if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0)
1032 		return B_MEDIA_BAD_NODE;
1033 	if (out_inputs == NULL || out_total_count == NULL)
1034 		return B_BAD_VALUE;
1035 
1036 	Stack<media_input> stack;
1037 	media_input *input;
1038 	status_t rv;
1039 
1040 	rv = GetAllInputs(node, &stack);
1041 	if (B_OK != rv)
1042 		return rv;
1043 
1044 	*out_total_count = 0;
1045 	for (int32 i = 0; stack.GetPointerAt(i, &input); i++) {
1046 		out_inputs[i] = *input;
1047 		*out_total_count += 1;
1048 		buf_num_inputs -= 1;
1049 		if (buf_num_inputs == 0)
1050 			break;
1051 	}
1052 
1053 	PublishInputs(node, &stack);
1054 	return B_OK;
1055 }
1056 
1057 
1058 status_t
1059 BMediaRoster::GetFreeOutputsFor(const media_node & node,
1060 								media_output * out_free_outputs,
1061 								int32 buf_num_outputs,
1062 								int32 * out_total_count,
1063 								media_type filter_type)
1064 {
1065 	CALLED();
1066 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1067 		return B_MEDIA_BAD_NODE;
1068 	if (out_free_outputs == NULL || out_total_count == NULL)
1069 		return B_BAD_VALUE;
1070 
1071 	Stack<media_output> stack;
1072 	media_output *output;
1073 	status_t rv;
1074 
1075 	rv = GetAllOutputs(node, &stack);
1076 	if (B_OK != rv)
1077 		return rv;
1078 
1079 	*out_total_count = 0;
1080 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1081 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != output->format.type)
1082 			continue; // media_type used, but doesn't match
1083 		if (output->destination != media_destination::null)
1084 			continue; // producer destination already connected
1085 		out_free_outputs[i] = *output;
1086 		*out_total_count += 1;
1087 		buf_num_outputs -= 1;
1088 		if (buf_num_outputs == 0)
1089 			break;
1090 	}
1091 
1092 	PublishOutputs(node, &stack);
1093 	return B_OK;
1094 }
1095 
1096 
1097 status_t
1098 BMediaRoster::GetConnectedOutputsFor(const media_node & node,
1099 									 media_output * out_active_outputs,
1100 									 int32 buf_num_outputs,
1101 									 int32 * out_total_count)
1102 {
1103 	CALLED();
1104 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1105 		return B_MEDIA_BAD_NODE;
1106 	if (out_active_outputs == NULL || out_total_count == NULL)
1107 		return B_BAD_VALUE;
1108 
1109 	Stack<media_output> stack;
1110 	media_output *output;
1111 	status_t rv;
1112 
1113 	rv = GetAllOutputs(node, &stack);
1114 	if (B_OK != rv)
1115 		return rv;
1116 
1117 	*out_total_count = 0;
1118 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1119 		if (output->destination == media_destination::null)
1120 			continue; // producer destination not connected
1121 		out_active_outputs[i] = *output;
1122 		*out_total_count += 1;
1123 		buf_num_outputs -= 1;
1124 		if (buf_num_outputs == 0)
1125 			break;
1126 	}
1127 
1128 	PublishOutputs(node, &stack);
1129 	return B_OK;
1130 }
1131 
1132 
1133 status_t
1134 BMediaRoster::GetAllOutputsFor(const media_node & node,
1135 							   media_output * out_outputs,
1136 							   int32 buf_num_outputs,
1137 							   int32 * out_total_count)
1138 {
1139 	CALLED();
1140 	if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0)
1141 		return B_MEDIA_BAD_NODE;
1142 	if (out_outputs == NULL || out_total_count == NULL)
1143 		return B_BAD_VALUE;
1144 
1145 	Stack<media_output> stack;
1146 	media_output *output;
1147 	status_t rv;
1148 
1149 	rv = GetAllOutputs(node, &stack);
1150 	if (B_OK != rv)
1151 		return rv;
1152 
1153 	*out_total_count = 0;
1154 	for (int32 i = 0; stack.GetPointerAt(i, &output); i++) {
1155 		out_outputs[i] = *output;
1156 		*out_total_count += 1;
1157 		buf_num_outputs -= 1;
1158 		if (buf_num_outputs == 0)
1159 			break;
1160 	}
1161 
1162 	PublishOutputs(node, &stack);
1163 	return B_OK;
1164 }
1165 
1166 
1167 status_t
1168 BMediaRoster::StartWatching(const BMessenger & where)
1169 {
1170 	CALLED();
1171 	if (!where.IsValid()) {
1172 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1173 		return B_BAD_VALUE;
1174 	}
1175 	return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD);
1176 }
1177 
1178 
1179 status_t
1180 BMediaRoster::StartWatching(const BMessenger & where,
1181 							int32 notificationType)
1182 {
1183 	CALLED();
1184 	if (!where.IsValid()) {
1185 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1186 		return B_BAD_VALUE;
1187 	}
1188 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1189 		TRACE("BMediaRoster::StartWatching: notificationType invalid!\n");
1190 		return B_BAD_VALUE;
1191 	}
1192 	return BPrivate::media::notifications::Register(where, media_node::null, notificationType);
1193 }
1194 
1195 
1196 status_t
1197 BMediaRoster::StartWatching(const BMessenger & where,
1198 							const media_node & node,
1199 							int32 notificationType)
1200 {
1201 	CALLED();
1202 	if (!where.IsValid()) {
1203 		TRACE("BMediaRoster::StartWatching: messenger invalid!\n");
1204 		return B_BAD_VALUE;
1205 	}
1206 	if (node.node <= 0) {
1207 		TRACE("BMediaRoster::StartWatching: node invalid!\n");
1208 		return B_MEDIA_BAD_NODE;
1209 	}
1210 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1211 		TRACE("BMediaRoster::StartWatching: notificationType invalid!\n");
1212 		return B_BAD_VALUE;
1213 	}
1214 	return BPrivate::media::notifications::Register(where, node, notificationType);
1215 }
1216 
1217 
1218 status_t
1219 BMediaRoster::StopWatching(const BMessenger & where)
1220 {
1221 	CALLED();
1222 	// messenger may already be invalid, so we don't check this
1223 	return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD);
1224 }
1225 
1226 
1227 status_t
1228 BMediaRoster::StopWatching(const BMessenger & where,
1229 						   int32 notificationType)
1230 {
1231 	CALLED();
1232 	// messenger may already be invalid, so we don't check this
1233 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1234 		TRACE("BMediaRoster::StopWatching: notificationType invalid!\n");
1235 		return B_BAD_VALUE;
1236 	}
1237 	return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType);
1238 }
1239 
1240 
1241 status_t
1242 BMediaRoster::StopWatching(const BMessenger & where,
1243 						   const media_node & node,
1244 						   int32 notificationType)
1245 {
1246 	CALLED();
1247 	// messenger may already be invalid, so we don't check this
1248 	if (node.node <= 0) {
1249 		TRACE("BMediaRoster::StopWatching: node invalid!\n");
1250 		return B_MEDIA_BAD_NODE;
1251 	}
1252 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1253 		TRACE("BMediaRoster::StopWatching: notificationType invalid!\n");
1254 		return B_BAD_VALUE;
1255 	}
1256 	return BPrivate::media::notifications::Unregister(where, node, notificationType);
1257 }
1258 
1259 
1260 status_t
1261 BMediaRoster::RegisterNode(BMediaNode * node)
1262 {
1263 	CALLED();
1264 	if (node == NULL)
1265 		return B_BAD_VALUE;
1266 
1267 	status_t rv;
1268 	BMediaAddOn *addon;
1269 	int32 addon_flavor_id;
1270 	media_addon_id addon_id;
1271 
1272 	addon_flavor_id = 0;
1273 	addon = node->AddOn(&addon_flavor_id);
1274 	addon_id = addon ? addon->AddonID() : -1;
1275 
1276 	server_register_node_request request;
1277 	server_register_node_reply reply;
1278 
1279 	request.addon_id = addon_id;
1280 	request.addon_flavor_id = addon_flavor_id;
1281 	strcpy(request.name, node->Name());
1282 	request.kinds = node->Kinds();
1283 	request.port = node->ControlPort();
1284 	request.team = team;
1285 
1286 	rv = QueryServer(SERVER_REGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1287 	if (rv != B_OK) {
1288 		TRACE("BMediaRoster::RegisterNode: failed to register node %s (error %#lx)\n", node->Name(), rv);
1289 		return rv;
1290 	}
1291 
1292 	// we are a friend class of BMediaNode and initilize this member variable
1293 	node->fNodeID = reply.nodeid;
1294 	ASSERT(reply.nodeid == node->Node().node);
1295 	ASSERT(reply.nodeid == node->ID());
1296 
1297 	// call the callback
1298 	node->NodeRegistered();
1299 
1300 	// register existing inputs and outputs with the
1301 	// media_server, this allows GetLiveNodes() to work
1302 	// with created, but unconnected nodes.
1303 	if (node->Kinds() & B_BUFFER_PRODUCER) {
1304 		Stack<media_output> stack;
1305 		if (B_OK == GetAllOutputs(node->Node(), &stack))
1306 			PublishOutputs(node->Node(), &stack);
1307 	} else if (node->Kinds() & B_BUFFER_CONSUMER) {
1308 		Stack<media_input> stack;
1309 		if (B_OK == GetAllInputs(node->Node(), &stack))
1310 			PublishInputs(node->Node(), &stack);
1311 	}
1312 
1313 	TRACE("BMediaRoster::RegisterNode: registered node %s, id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id);
1314 
1315 	return B_OK;
1316 }
1317 
1318 
1319 status_t
1320 BMediaRoster::UnregisterNode(BMediaNode * node)
1321 {
1322 	CALLED();
1323 	if (node == NULL)
1324 		return B_BAD_VALUE;
1325 
1326 	if (node->fRefCount != 0) {
1327 		TRACE("BMediaRoster::UnregisterNode: Warning node %s has local reference count of %ld\n", node->Name(), node->fRefCount);
1328 		// no return here, we continue and unregister!
1329 	}
1330 	if (node->ID() == -2) {
1331 		TRACE("BMediaRoster::UnregisterNode: Warning node %s already unregistered\n", node->Name());
1332 		return B_OK;
1333 	}
1334 
1335 	server_unregister_node_request request;
1336 	server_unregister_node_reply reply;
1337 	status_t rv;
1338 
1339 	request.nodeid = node->ID();
1340 	request.team = team;
1341 
1342 	rv = QueryServer(SERVER_UNREGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1343 	if (rv != B_OK) {
1344 		TRACE("BMediaRoster::UnregisterNode: failed to unregister node %s (error %#lx)\n", node->Name(), rv);
1345 		return rv;
1346 	}
1347 
1348 	if (reply.addon_id != -1)
1349 		_DormantNodeManager->PutAddon(reply.addon_id);
1350 
1351 	// we are a friend class of BMediaNode and initilize this member variable
1352 	node->fNodeID = -2;
1353 
1354 	return B_OK;
1355 }
1356 
1357 
1358 //	thread safe for multiple calls to Roster()
1359 /* static */ BMediaRoster *
1360 BMediaRoster::Roster(status_t* out_error)
1361 {
1362 	CALLED();
1363 	static BLocker locker("BMediaRoster::Roster locker");
1364 	locker.Lock();
1365 	if (_sDefault == NULL) {
1366 		_sDefault = new BMediaRoster();
1367 		if (out_error != NULL)
1368 			*out_error = B_OK;
1369 	} else {
1370 		if (out_error != NULL)
1371 			*out_error = B_OK;
1372 	}
1373 	locker.Unlock();
1374 	return _sDefault;
1375 }
1376 
1377 
1378 //	won't create it if there isn't one
1379 //	not thread safe if you call Roster() at the same time
1380 /* static */ BMediaRoster *
1381 BMediaRoster::CurrentRoster()
1382 {
1383 	CALLED();
1384 	return _sDefault;
1385 }
1386 
1387 
1388 status_t
1389 BMediaRoster::SetTimeSourceFor(media_node_id node,
1390 							   media_node_id time_source)
1391 {
1392 	UNIMPLEMENTED();
1393 	return B_ERROR;
1394 }
1395 
1396 
1397 status_t
1398 BMediaRoster::GetParameterWebFor(const media_node & node,
1399 								 BParameterWeb ** out_web)
1400 {
1401 	UNIMPLEMENTED();
1402 	return B_ERROR;
1403 }
1404 
1405 
1406 status_t
1407 BMediaRoster::StartControlPanel(const media_node & node,
1408 								BMessenger * out_messenger)
1409 {
1410 	UNIMPLEMENTED();
1411 	return B_ERROR;
1412 }
1413 
1414 
1415 status_t
1416 BMediaRoster::GetDormantNodes(dormant_node_info * out_info,
1417 							  int32 * io_count,
1418 							  const media_format * has_input /* = NULL */,
1419 							  const media_format * has_output /* = NULL */,
1420 							  const char * name /* = NULL */,
1421 							  uint64 require_kinds /* = NULL */,
1422 							  uint64 deny_kinds /* = NULL */)
1423 {
1424 	CALLED();
1425 	if (out_info == NULL)
1426 		return B_BAD_VALUE;
1427 	if (io_count == NULL)
1428 		return B_BAD_VALUE;
1429 	if (*io_count <= 0)
1430 		return B_BAD_VALUE;
1431 
1432 	xfer_server_get_dormant_nodes msg;
1433 	port_id port;
1434 	status_t rv;
1435 
1436 	port = find_port("media_server port");
1437 	if (port <= B_OK)
1438 		return B_ERROR;
1439 
1440 	msg.maxcount = *io_count;
1441 	msg.has_input = (bool) has_input;
1442 	if (has_input)
1443 		msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format
1444 	msg.has_output = (bool) has_output;
1445 	if (has_output)
1446 		msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format
1447 	msg.has_name = (bool) name;
1448 	if (name) {
1449 		int len = strlen(name);
1450 		len = min_c(len, (int)sizeof(msg.name) - 1);
1451 		memcpy(msg.name, name, len);
1452 		msg.name[len] = 0;
1453 	}
1454 	msg.require_kinds = require_kinds;
1455 	msg.deny_kinds = deny_kinds;
1456 	msg.reply_port = _PortPool->GetPort();
1457 
1458 	rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg));
1459 	if (rv != B_OK) {
1460 		_PortPool->PutPort(msg.reply_port);
1461 		return rv;
1462 	}
1463 
1464 	xfer_server_get_dormant_nodes_reply reply;
1465 	int32 code;
1466 
1467 	rv = read_port(msg.reply_port, &code, &reply, sizeof(reply));
1468 	if (rv < B_OK) {
1469 		_PortPool->PutPort(msg.reply_port);
1470 		return rv;
1471 	}
1472 
1473 	*io_count = reply.count;
1474 
1475 	if (*io_count > 0) {
1476 		rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info));
1477 		if (rv < B_OK)
1478 			reply.result = rv;
1479 	}
1480 	_PortPool->PutPort(msg.reply_port);
1481 
1482 	return reply.result;
1483 }
1484 
1485 
1486 status_t
1487 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
1488 									 media_node * out_node,
1489 									 uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ )
1490 {
1491 	CALLED();
1492 	if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) {
1493 		printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n");
1494 		return B_BAD_VALUE;
1495 	}
1496 	if (out_node == 0)
1497 		return B_BAD_VALUE;
1498 
1499 	// XXX we should not trust the values passed in by the user,
1500 	// XXX and ask the server to determine where to insta
1501 
1502 
1503 // XXX SOMETHING IS VERY WRONG HERE
1504 //	if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) {
1505 	if (flags & B_FLAVOR_IS_LOCAL) {
1506 		return InstantiateDormantNode(in_info,out_node);
1507 	}
1508 
1509 // XXX SOMETHING IS VERY WRONG HERE
1510 //	if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) {
1511 	if (flags & B_FLAVOR_IS_GLOBAL) {
1512 		// forward this request into the media_addon_server,
1513 		// which in turn will call InstantiateDormantNode()
1514 		// to create it there localy
1515 		addonserver_instantiate_dormant_node_request request;
1516 		addonserver_instantiate_dormant_node_reply reply;
1517 		status_t rv;
1518 
1519 		request.info = in_info;
1520 		rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply));
1521 		if (rv == B_OK) {
1522 			*out_node = reply.node;
1523 		}
1524 		return rv;
1525 	}
1526 
1527 // XXX SOMETHING IS VERY WRONG HERE
1528 	printf("Error: BMediaRoster::InstantiateDormantNode addon_id %d, flavor_id %d, flags %#08lx\n", (int)in_info.addon, (int)in_info.flavor_id, flags);
1529 
1530 	return B_ERROR;
1531 }
1532 
1533 
1534 status_t
1535 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
1536 									 media_node * out_node)
1537 {
1538 	CALLED();
1539 
1540 	// to instantiate a dormant node in the current address space, we need to
1541 	// either load the add-on from file and create a new BMediaAddOn class, or
1542 	// reuse the cached BMediaAddOn from a previous call
1543 	// call BMediaAddOn::InstantiateNodeFor()
1544 	// and cache the BMediaAddOn after that for later reuse.
1545 	// BeOS R5 does not seem to delete it when the application quits
1546 	// if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
1547 	// resides in the media_addon_server
1548 
1549 	// RegisterNode() is called automatically for nodes instantiated from add-ons
1550 
1551 	//XXX TEST!
1552 	BMediaAddOn *addon;
1553 	BMediaNode *node;
1554 	BMessage config;
1555 	status_t out_error;
1556 	status_t rv;
1557 	addon = _DormantNodeManager->GetAddon(in_info.addon);
1558 	if (!addon) {
1559 		printf("BMediaRoster::InstantiateDormantNode: GetAddon failed\n");
1560 		return B_ERROR;
1561 	}
1562 	flavor_info temp;
1563 	temp.internal_id = in_info.flavor_id;
1564 	node = addon->InstantiateNodeFor(&temp, &config, &out_error);
1565 	if (!node) {
1566 		printf("BMediaRoster::InstantiateDormantNode: InstantiateNodeFor failed\n");
1567 		_DormantNodeManager->PutAddon(in_info.addon);
1568 		return B_ERROR;
1569 	}
1570 	rv = RegisterNode(node);
1571 	if (rv != B_OK) {
1572 		printf("BMediaRoster::InstantiateDormantNode: RegisterNode failed\n");
1573 		delete node;
1574 		_DormantNodeManager->PutAddon(in_info.addon);
1575 		return B_ERROR;
1576 	}
1577 
1578 	// XXX we must remember in_info.addon and call
1579 	// XXX _DormantNodeManager->PutAddon when the
1580 	// XXX node is unregistered
1581 	// should be handled by RegisterNode() and UnegisterNode() now
1582 
1583 	*out_node = node->Node();
1584 	return B_OK;
1585 }
1586 
1587 
1588 status_t
1589 BMediaRoster::GetDormantNodeFor(const media_node & node,
1590 								dormant_node_info * out_info)
1591 {
1592 	CALLED();
1593 	if (out_info == NULL)
1594 		return B_BAD_VALUE;
1595 	if (node.node <= 0)
1596 		return B_MEDIA_BAD_NODE;
1597 
1598 	server_get_dormant_node_for_request request;
1599 	server_get_dormant_node_for_reply reply;
1600 	status_t rv;
1601 
1602 	request.node = node;
1603 
1604 	rv = QueryAddonServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply));
1605 	if (rv != B_OK)
1606 		return rv;
1607 
1608 	*out_info = reply.node_info;
1609 	return B_OK;
1610 }
1611 
1612 
1613 status_t
1614 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant,
1615 									  dormant_flavor_info * out_flavor)
1616 {
1617 	CALLED();
1618 
1619 	xfer_server_get_dormant_flavor_info msg;
1620 	xfer_server_get_dormant_flavor_info_reply *reply;
1621 	port_id port;
1622 	status_t rv;
1623 	int32 code;
1624 
1625 	port = find_port("media_server port");
1626 	if (port <= B_OK)
1627 		return B_ERROR;
1628 
1629 	reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000);
1630 	if (reply == 0)
1631 		return B_ERROR;
1632 
1633 	msg.addon 		= in_dormant.addon;
1634 	msg.flavor_id 	= in_dormant.flavor_id;
1635 	msg.reply_port 	= _PortPool->GetPort();
1636 	rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg));
1637 	if (rv != B_OK) {
1638 		free(reply);
1639 		_PortPool->PutPort(msg.reply_port);
1640 		return rv;
1641 	}
1642 	rv = read_port(msg.reply_port, &code, reply, 16000);
1643 	_PortPool->PutPort(msg.reply_port);
1644 
1645 	if (rv < B_OK) {
1646 		free(reply);
1647 		return rv;
1648 	}
1649 
1650 	if (reply->result == B_OK)
1651 		rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size);
1652 	else
1653 		rv = reply->result;
1654 
1655 	free(reply);
1656 	return rv;
1657 }
1658 
1659 
1660 status_t
1661 BMediaRoster::GetLatencyFor(const media_node & producer,
1662 							bigtime_t * out_latency)
1663 {
1664 	UNIMPLEMENTED();
1665 	*out_latency = 0;
1666 	return B_ERROR;
1667 }
1668 
1669 
1670 status_t
1671 BMediaRoster::GetInitialLatencyFor(const media_node & producer,
1672 								   bigtime_t * out_latency,
1673 								   uint32 * out_flags)
1674 {
1675 	UNIMPLEMENTED();
1676 	*out_latency = 0;
1677 	*out_flags = 0;
1678 	return B_ERROR;
1679 }
1680 
1681 
1682 status_t
1683 BMediaRoster::GetStartLatencyFor(const media_node & time_source,
1684 								 bigtime_t * out_latency)
1685 {
1686 	UNIMPLEMENTED();
1687 	*out_latency = 0;
1688 	return B_ERROR;
1689 }
1690 
1691 
1692 status_t
1693 BMediaRoster::GetFileFormatsFor(const media_node & file_interface,
1694 								media_file_format * out_formats,
1695 								int32 * io_num_infos)
1696 {
1697 	UNIMPLEMENTED();
1698 	return B_ERROR;
1699 }
1700 
1701 
1702 status_t
1703 BMediaRoster::SetRefFor(const media_node & file_interface,
1704 						const entry_ref & file,
1705 						bool create_and_truncate,
1706 						bigtime_t * out_length)	/* if create is false */
1707 {
1708 	UNIMPLEMENTED();
1709 	return B_ERROR;
1710 }
1711 
1712 
1713 status_t
1714 BMediaRoster::GetRefFor(const media_node & node,
1715 						entry_ref * out_file,
1716 						BMimeType * mime_type)
1717 {
1718 	UNIMPLEMENTED();
1719 	return B_ERROR;
1720 }
1721 
1722 
1723 status_t
1724 BMediaRoster::SniffRefFor(const media_node & file_interface,
1725 						  const entry_ref & file,
1726 						  BMimeType * mime_type,
1727 						  float * out_capability)
1728 {
1729 	UNIMPLEMENTED();
1730 	return B_ERROR;
1731 }
1732 
1733 
1734 /* This is the generic "here's a file, now can someone please play it" interface */
1735 status_t
1736 BMediaRoster::SniffRef(const entry_ref & file,
1737 					   uint64 require_node_kinds,		/* if you need an EntityInterface or BufferConsumer or something */
1738 					   dormant_node_info * out_node,
1739 					   BMimeType * mime_type)
1740 {
1741 	UNIMPLEMENTED();
1742 	return B_ERROR;
1743 }
1744 
1745 
1746 status_t
1747 BMediaRoster::GetDormantNodeForType(const BMimeType & type,
1748 									uint64 require_node_kinds,
1749 									dormant_node_info * out_node)
1750 {
1751 	UNIMPLEMENTED();
1752 	return B_ERROR;
1753 }
1754 
1755 
1756 status_t
1757 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node,
1758 									media_file_format * out_read_formats,
1759 									int32 in_read_count,
1760 									int32 * out_read_count)
1761 {
1762 	UNIMPLEMENTED();
1763 	return B_ERROR;
1764 }
1765 
1766 
1767 status_t
1768 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node,
1769 									 media_file_format * out_write_formats,
1770 									 int32 in_write_count,
1771 									 int32 * out_write_count)
1772 {
1773 	UNIMPLEMENTED();
1774 	return B_ERROR;
1775 }
1776 
1777 
1778 status_t
1779 BMediaRoster::GetFormatFor(const media_output & output,
1780 						   media_format * io_format,
1781 						   uint32 flags)
1782 {
1783 	UNIMPLEMENTED();
1784 	return B_ERROR;
1785 }
1786 
1787 
1788 status_t
1789 BMediaRoster::GetFormatFor(const media_input & input,
1790 						   media_format * io_format,
1791 						   uint32 flags)
1792 {
1793 	UNIMPLEMENTED();
1794 	return B_ERROR;
1795 }
1796 
1797 
1798 status_t
1799 BMediaRoster::GetFormatFor(const media_node & node,
1800 						   media_format * io_format,
1801 						   float quality)
1802 {
1803 	UNIMPLEMENTED();
1804 	return B_ERROR;
1805 }
1806 
1807 
1808 ssize_t
1809 BMediaRoster::GetNodeAttributesFor(const media_node & node,
1810 								   media_node_attribute * outArray,
1811 								   size_t inMaxCount)
1812 {
1813 	UNIMPLEMENTED();
1814 	return B_ERROR;
1815 }
1816 
1817 
1818 media_node_id
1819 BMediaRoster::NodeIDFor(port_id source_or_destination_port)
1820 {
1821 	CALLED();
1822 
1823 	server_node_id_for_request request;
1824 	server_node_id_for_reply reply;
1825 	status_t rv;
1826 
1827 	request.port = source_or_destination_port;
1828 
1829 	rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, sizeof(reply));
1830 	if (rv != B_OK) {
1831 		TRACE("BMediaRoster::NodeIDFor: failed (error %#lx)\n", rv);
1832 		return -1;
1833 	}
1834 
1835 	return reply.nodeid;
1836 }
1837 
1838 
1839 status_t
1840 BMediaRoster::GetInstancesFor(media_addon_id addon,
1841 							  int32 flavor,
1842 							  media_node_id * out_id,
1843 							  int32 * io_count)
1844 {
1845 	CALLED();
1846 	if (out_id == NULL || io_count == NULL)
1847 		return B_BAD_VALUE;
1848 	if (*io_count <= 0)
1849 		return B_BAD_VALUE;
1850 
1851 	server_get_instances_for_request request;
1852 	server_get_instances_for_reply reply;
1853 	status_t rv;
1854 
1855 	request.maxcount = *io_count;
1856 	request.addon_id = addon;
1857 	request.addon_flavor_id = flavor;
1858 
1859 	rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), &reply, sizeof(reply));
1860 	if (rv != B_OK) {
1861 		TRACE("BMediaRoster::GetLiveNodes failed\n");
1862 		return rv;
1863 	}
1864 
1865 	*io_count = reply.count;
1866 	if (reply.count > 0)
1867 		memcpy(out_id, reply.node_id, sizeof(media_node_id) * reply.count);
1868 
1869 	return B_OK;
1870 }
1871 
1872 
1873 status_t
1874 BMediaRoster::SetRealtimeFlags(uint32 in_enabled)
1875 {
1876 	UNIMPLEMENTED();
1877 	return B_ERROR;
1878 }
1879 
1880 
1881 status_t
1882 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled)
1883 {
1884 	UNIMPLEMENTED();
1885 	return B_ERROR;
1886 }
1887 
1888 
1889 ssize_t
1890 BMediaRoster::AudioBufferSizeFor(int32 channel_count,
1891 								 uint32 sample_format,
1892 								 float frame_rate,
1893 								 bus_type bus_kind)
1894 {
1895 	UNIMPLEMENTED();
1896 	return 4096;
1897 }
1898 
1899 
1900 /* Use MediaFlags to inquire about specific features of the Media Kit. */
1901 /* Returns < 0 for "not present", positive size for output data size. */
1902 /* 0 means that the capability is present, but no data about it. */
1903 /* static */ ssize_t
1904 BMediaRoster::MediaFlags(media_flags cap,
1905 						 void * buf,
1906 						 size_t maxSize)
1907 {
1908 	UNIMPLEMENTED();
1909 	return 0;
1910 }
1911 
1912 
1913 
1914 /* BLooper overrides */
1915 /* virtual */ void
1916 BMediaRoster::MessageReceived(BMessage * message)
1917 {
1918 	UNIMPLEMENTED();
1919 }
1920 
1921 /* virtual */ bool
1922 BMediaRoster::QuitRequested()
1923 {
1924 	UNIMPLEMENTED();
1925 	return true;
1926 }
1927 
1928 /* virtual */ BHandler *
1929 BMediaRoster::ResolveSpecifier(BMessage *msg,
1930 				 int32 index,
1931 				 BMessage *specifier,
1932 				 int32 form,
1933 				 const char *property)
1934 {
1935 	UNIMPLEMENTED();
1936 	return 0;
1937 }
1938 
1939 
1940 /* virtual */ status_t
1941 BMediaRoster::GetSupportedSuites(BMessage *data)
1942 {
1943 	UNIMPLEMENTED();
1944 	return B_ERROR;
1945 }
1946 
1947 
1948 BMediaRoster::~BMediaRoster()
1949 {
1950 	CALLED();
1951 	BMessage msg(MEDIA_SERVER_UNREGISTER_APP);
1952 	BMessage reply;
1953 	msg.AddInt32("team",team);
1954 	QueryServer(&msg, &reply);
1955 }
1956 
1957 
1958 /*************************************************************
1959  * private BMediaRoster
1960  *************************************************************/
1961 
1962 // deprecated call
1963 status_t
1964 BMediaRoster::SetOutputBuffersFor(const media_source & output,
1965 								  BBufferGroup * group,
1966 								  bool will_reclaim )
1967 {
1968 	UNIMPLEMENTED();
1969 	debugger("BMediaRoster::SetOutputBuffersFor missing\n");
1970 	return B_ERROR;
1971 }
1972 
1973 
1974 /* FBC stuffing (Mmmh, Stuffing!) */
1975 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; }
1976 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; }
1977 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; }
1978 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; }
1979 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; }
1980 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; }
1981 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; }
1982 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; }
1983 
1984 
1985 BMediaRoster::BMediaRoster() :
1986 	BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY)
1987 {
1988 	CALLED();
1989 	BMessage msg(MEDIA_SERVER_REGISTER_APP);
1990 	BMessage reply;
1991 	msg.AddInt32("team",team);
1992 	QueryServer(&msg,&reply);
1993 }
1994 
1995 /* static */ status_t
1996 BMediaRoster::ParseCommand(BMessage & reply)
1997 {
1998 	UNIMPLEMENTED();
1999 	return B_ERROR;
2000 }
2001 
2002 
2003 
2004 status_t
2005 BMediaRoster::GetDefaultInfo(media_node_id for_default,
2006 							 BMessage & out_config)
2007 {
2008 	UNIMPLEMENTED();
2009 	return B_ERROR;
2010 }
2011 
2012 
2013 
2014 status_t
2015 BMediaRoster::SetRunningDefault(media_node_id for_default,
2016 								const media_node & node)
2017 {
2018 	UNIMPLEMENTED();
2019 	return B_ERROR;
2020 }
2021 
2022 
2023 /*************************************************************
2024  * static BMediaRoster variables
2025  *************************************************************/
2026 
2027 bool BMediaRoster::_isMediaServer;
2028 port_id BMediaRoster::_mReplyPort;
2029 int32 BMediaRoster::_mReplyPortRes;
2030 int32 BMediaRoster::_mReplyPortUnavailCount;
2031 BMediaRoster * BMediaRoster::_sDefault = NULL;
2032 
2033