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