xref: /haiku/src/kits/media/MediaRoster.cpp (revision aa94570a34695672df9b47adda2257f75d8da880)
1 /*
2  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 /* to comply with the license above, do not remove the following line */
31 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>";
32 
33 #include <MediaRoster.h>
34 #include <Locker.h>
35 #include <Message.h>
36 #include <Messenger.h>
37 #include <StopWatch.h>
38 #include <OS.h>
39 #include <String.h>
40 #include <TimeSource.h>
41 #include <ParameterWeb.h>
42 #include <BufferProducer.h>
43 #include <BufferConsumer.h>
44 #include "debug.h"
45 #include "MediaRosterEx.h"
46 #include "MediaMisc.h"
47 #include "PortPool.h"
48 #include "ServerInterface.h"
49 #include "DataExchange.h"
50 #include "DormantNodeManager.h"
51 #include "Notifications.h"
52 #include "TimeSourceObjectManager.h"
53 
54 namespace BPrivate { namespace media {
55 
56 	// the BMediaRoster destructor is private,
57 	// but _DefaultDeleter is a friend class of
58 	// the BMediaRoster an thus can delete it
59 	class DefaultDeleter
60 	{
61 	public:
62 		~DefaultDeleter()
63 		{
64 			if (BMediaRoster::_sDefault) {
65 				BMediaRoster::_sDefault->Lock();
66 				BMediaRoster::_sDefault->Quit();
67 			}
68 		}
69 	};
70 
71 } } // BPrivate::media
72 using namespace BPrivate::media;
73 
74 // DefaultDeleter will delete the BMediaRoster object in it's destructor.
75 DefaultDeleter _deleter;
76 
77 status_t
78 BMediaRosterEx::SaveNodeConfiguration(BMediaNode *node)
79 {
80 	BMediaAddOn *addon;
81 	media_addon_id addonid;
82 	int32 flavorid;
83 	addon = node->AddOn(&flavorid);
84 	if (!addon) {
85 		// XXX this check incorrectly triggers on BeOS R5 BT848 node
86 		ERROR("BMediaRosterEx::SaveNodeConfiguration node %ld not instantiated from BMediaAddOn!\n", node->ID());
87 		return B_ERROR;
88 	}
89 	addonid = addon->AddonID();
90 
91 	// XXX fix this
92 	printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id %ld, flavor-id %ld config NOW!\n", addonid, flavorid);
93 	return B_OK;
94 }
95 
96 status_t
97 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonid, int32 flavorid, BMessage *out_msg)
98 {
99 	// XXX fix this
100 	out_msg->MakeEmpty(); // to be fully R5 compliant
101 	printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id %ld, flavor-id %ld config NOW!\n", addonid, flavorid);
102 	return B_OK;
103 }
104 
105 status_t
106 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonid, int32 flavorid)
107 {
108 	server_change_addon_flavor_instances_count_request request;
109 	server_change_addon_flavor_instances_count_reply reply;
110 
111 	request.addonid = addonid;
112 	request.flavorid = flavorid;
113 	request.delta = 1;
114 	request.team = team;
115 	return QueryServer(SERVER_CHANGE_ADDON_FLAVOR_INSTANCES_COUNT, &request, sizeof(request), &reply, sizeof(reply));
116 }
117 
118 status_t
119 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonid, int32 flavorid)
120 {
121 	server_change_addon_flavor_instances_count_request request;
122 	server_change_addon_flavor_instances_count_reply reply;
123 
124 	request.addonid = addonid;
125 	request.flavorid = flavorid;
126 	request.delta = -1;
127 	request.team = team;
128 	return QueryServer(SERVER_CHANGE_ADDON_FLAVOR_INSTANCES_COUNT, &request, sizeof(request), &reply, sizeof(reply));
129 }
130 
131 status_t
132 BMediaRosterEx::SetNodeCreator(media_node_id node, team_id creator)
133 {
134 	server_set_node_creator_request request;
135 	server_set_node_creator_reply reply;
136 
137 	request.node = node;
138 	request.creator = creator;
139 	return QueryServer(SERVER_SET_NODE_CREATOR, &request, sizeof(request), &reply, sizeof(reply));
140 }
141 
142 status_t
143 BMediaRosterEx::GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name)
144 {
145 	if (out_node == NULL)
146 		return B_BAD_VALUE;
147 
148 	server_get_node_request request;
149 	server_get_node_reply reply;
150 	status_t rv;
151 
152 	request.type = type;
153 	request.team = team;
154 	rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply, sizeof(reply));
155 	if (rv != B_OK)
156 		return rv;
157 
158 	*out_node = reply.node;
159 	if (out_input_id)
160 		*out_input_id = reply.input_id;
161 	if (out_input_name)
162 		*out_input_name = reply.input_name;
163 	return rv;
164 }
165 
166 status_t
167 BMediaRosterEx::SetNode(node_type type, const media_node *node, const dormant_node_info *info, const media_input *input)
168 {
169 	server_set_node_request request;
170 	server_set_node_reply reply;
171 
172 	request.type = type;
173 	request.use_node = node ? true : false;
174 	if (node)
175 		request.node = *node;
176 	request.use_dni = info ? true : false;
177 	if (info)
178 		request.dni = *info;
179 	request.use_input = input ? true : false;
180 	if (input)
181 		request.input = *input;
182 
183 	return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply, sizeof(reply));
184 }
185 
186 status_t
187 BMediaRosterEx::GetAllOutputs(const media_node & node, List<media_output> *list)
188 {
189 	int32 cookie;
190 	status_t rv;
191 	status_t result;
192 
193 	PRINT(4, "BMediaRosterEx::GetAllOutputs() node %ld, port %ld\n", node.node, node.port);
194 
195 	result = B_OK;
196 	cookie = 0;
197 	list->MakeEmpty();
198 	for (;;) {
199 		producer_get_next_output_request request;
200 		producer_get_next_output_reply reply;
201 		request.cookie = cookie;
202 		rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request, sizeof(request), &reply, sizeof(reply));
203 		if (rv != B_OK)
204 			break;
205 		cookie = reply.cookie;
206 		if (!list->Insert(reply.output)) {
207 			ERROR("GetAllOutputs: list->Insert failed\n");
208 			result = B_ERROR;
209 		}
210 		#if DEBUG >= 3
211 			PRINT(3," next cookie %ld, ", cookie);
212 			PRINT_OUTPUT("output ", reply.output);
213 		#endif
214 	}
215 
216 	producer_dispose_output_cookie_request request;
217 	producer_dispose_output_cookie_reply reply;
218 	QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply));
219 
220 	return result;
221 }
222 
223 status_t
224 BMediaRosterEx::GetAllOutputs(BBufferProducer *node, List<media_output> *list)
225 {
226 	int32 cookie;
227 	status_t result;
228 
229 	PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %ld, port %ld\n", node->ID(), node->ControlPort());
230 
231 	result = B_OK;
232 	cookie = 0;
233 	list->MakeEmpty();
234 	for (;;) {
235 		media_output output;
236 		if (B_OK != node->GetNextOutput(&cookie, &output))
237 			break;
238 		if (!list->Insert(output)) {
239 			ERROR("GetAllOutputs: list->Insert failed\n");
240 			result = B_ERROR;
241 		}
242 		#if DEBUG >= 3
243 			PRINT(3," next cookie %ld, ", cookie);
244 			PRINT_OUTPUT("output ", output);
245 		#endif
246 	}
247 	node->DisposeOutputCookie(cookie);
248 	return result;
249 }
250 
251 status_t
252 BMediaRosterEx::GetAllInputs(const media_node & node, List<media_input> *list)
253 {
254 	int32 cookie;
255 	status_t rv;
256 	status_t result;
257 
258 	PRINT(4, "BMediaRosterEx::GetAllInputs() node %ld, port %ld\n", node.node, node.port);
259 
260 	result = B_OK;
261 	cookie = 0;
262 	list->MakeEmpty();
263 	for (;;) {
264 		consumer_get_next_input_request request;
265 		consumer_get_next_input_reply reply;
266 		request.cookie = cookie;
267 		rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request, sizeof(request), &reply, sizeof(reply));
268 		if (rv != B_OK)
269 			break;
270 		cookie = reply.cookie;
271 		if (!list->Insert(reply.input)) {
272 			ERROR("GetAllInputs: list->Insert failed\n");
273 			result = B_ERROR;
274 		}
275 		#if DEBUG >= 3
276 			PRINT(3," next cookie %ld, ", cookie);
277 			PRINT_OUTPUT("input ", reply.input);
278 		#endif
279 	}
280 
281 	consumer_dispose_input_cookie_request request;
282 	consumer_dispose_input_cookie_reply reply;
283 	QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply));
284 
285 	return result;
286 }
287 
288 status_t
289 BMediaRosterEx::GetAllInputs(BBufferConsumer *node, List<media_input> *list)
290 {
291 	int32 cookie;
292 	status_t result;
293 
294 	PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %ld, port %ld\n", node->ID(), node->ControlPort());
295 
296 	result = B_OK;
297 	cookie = 0;
298 	list->MakeEmpty();
299 	for (;;) {
300 		media_input input;
301 		if (B_OK != node->GetNextInput(&cookie, &input))
302 			break;
303 		if (!list->Insert(input)) {
304 			ERROR("GetAllInputs: list->Insert failed\n");
305 			result = B_ERROR;
306 		}
307 		#if DEBUG >= 3
308 			PRINT(3," next cookie %ld, ", cookie);
309 			PRINT_INPUT("input ", input);
310 		#endif
311 	}
312 	node->DisposeInputCookie(cookie);
313 	return result;
314 }
315 
316 status_t
317 BMediaRosterEx::PublishOutputs(const media_node & node, List<media_output> *list)
318 {
319 	server_publish_outputs_request request;
320 	server_publish_outputs_reply reply;
321 	media_output *output;
322 	media_output *outputs;
323 	int32 count;
324 	status_t rv;
325 
326 	count = list->CountItems();
327 	TRACE("PublishOutputs: publishing %ld\n", count);
328 
329 	request.node = node;
330 	request.count = count;
331 	if (count > MAX_OUTPUTS) {
332 		void *start_addr;
333 		size_t size;
334 		size = ROUND_UP_TO_PAGE(count * sizeof(media_output));
335 		request.area = create_area("publish outputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
336 		if (request.area < B_OK) {
337 			ERROR("PublishOutputs: failed to create area, %#lx\n", request.area);
338 			return (status_t)request.area;
339 		}
340 		outputs = static_cast<media_output *>(start_addr);
341 	} else {
342 		request.area = -1;
343 		outputs = request.outputs;
344 	}
345 	TRACE("PublishOutputs: area %ld\n", request.area);
346 
347 	int i;
348 	for (i = 0, list->Rewind(); list->GetNext(&output); i++) {
349 		ASSERT(i < count);
350 		outputs[i] = *output;
351 	}
352 
353 	rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request), &reply, sizeof(reply));
354 
355 	if (request.area != -1)
356 		delete_area(request.area);
357 
358 	return rv;
359 }
360 
361 status_t
362 BMediaRosterEx::PublishInputs(const media_node & node, List<media_input> *list)
363 {
364 	server_publish_inputs_request request;
365 	server_publish_inputs_reply reply;
366 	media_input *input;
367 	media_input *inputs;
368 	int32 count;
369 	status_t rv;
370 
371 	count = list->CountItems();
372 	TRACE("PublishInputs: publishing %ld\n", count);
373 
374 	request.node = node;
375 	request.count = count;
376 	if (count > MAX_INPUTS) {
377 		void *start_addr;
378 		size_t size;
379 		size = ROUND_UP_TO_PAGE(count * sizeof(media_input));
380 		request.area = create_area("publish inputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
381 		if (request.area < B_OK) {
382 			ERROR("PublishInputs: failed to create area, %#lx\n", request.area);
383 			return (status_t)request.area;
384 		}
385 		inputs = static_cast<media_input *>(start_addr);
386 	} else {
387 		request.area = -1;
388 		inputs = request.inputs;
389 	}
390 	TRACE("PublishInputs: area %ld\n", request.area);
391 
392 	int i;
393 	for (i = 0, list->Rewind(); list->GetNext(&input); i++) {
394 		ASSERT(i < count);
395 		inputs[i] = *input;
396 	}
397 
398 	rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request), &reply, sizeof(reply));
399 
400 	if (request.area != -1)
401 		delete_area(request.area);
402 
403 	return rv;
404 }
405 
406 /*************************************************************
407  * public BMediaRoster
408  *************************************************************/
409 
410 status_t
411 BMediaRoster::GetVideoInput(media_node * out_node)
412 {
413 	CALLED();
414 	return MediaRosterEx(this)->GetNode(VIDEO_INPUT, out_node);
415 }
416 
417 
418 status_t
419 BMediaRoster::GetAudioInput(media_node * out_node)
420 {
421 	CALLED();
422 	return MediaRosterEx(this)->GetNode(AUDIO_INPUT, out_node);
423 }
424 
425 
426 status_t
427 BMediaRoster::GetVideoOutput(media_node * out_node)
428 {
429 	CALLED();
430 	return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT, out_node);
431 }
432 
433 
434 status_t
435 BMediaRoster::GetAudioMixer(media_node * out_node)
436 {
437 	CALLED();
438 	return MediaRosterEx(this)->GetNode(AUDIO_MIXER, out_node);
439 }
440 
441 
442 status_t
443 BMediaRoster::GetAudioOutput(media_node * out_node)
444 {
445 	CALLED();
446 	return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT, out_node);
447 }
448 
449 
450 status_t
451 BMediaRoster::GetAudioOutput(media_node * out_node,
452 							 int32 * out_input_id,
453 							 BString * out_input_name)
454 {
455 	CALLED();
456 	return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX, out_node, out_input_id, out_input_name);
457 }
458 
459 
460 status_t
461 BMediaRoster::GetTimeSource(media_node * out_node)
462 {
463 	CALLED();
464 	status_t rv;
465 
466 	// XXX need to do this in a nicer way.
467 
468 	rv = MediaRosterEx(this)->GetNode(TIME_SOURCE, out_node);
469 	if (rv != B_OK)
470 		return rv;
471 
472 	// We don't do reference counting for timesources, that's why we
473 	// release the node immediately.
474 	ReleaseNode(*out_node);
475 
476 	// we need to remember to not use this node with server side reference counting
477 	out_node->kind |= NODE_KIND_NO_REFCOUNTING;
478 
479 	return B_OK;
480 }
481 
482 
483 status_t
484 BMediaRoster::SetVideoInput(const media_node & producer)
485 {
486 	CALLED();
487 	return MediaRosterEx(this)->SetNode(VIDEO_INPUT, &producer);
488 }
489 
490 
491 status_t
492 BMediaRoster::SetVideoInput(const dormant_node_info & producer)
493 {
494 	CALLED();
495 	return MediaRosterEx(this)->SetNode(VIDEO_INPUT, NULL, &producer);
496 }
497 
498 
499 status_t
500 BMediaRoster::SetAudioInput(const media_node & producer)
501 {
502 	CALLED();
503 	return MediaRosterEx(this)->SetNode(AUDIO_INPUT, &producer);
504 }
505 
506 
507 status_t
508 BMediaRoster::SetAudioInput(const dormant_node_info & producer)
509 {
510 	CALLED();
511 	return MediaRosterEx(this)->SetNode(AUDIO_INPUT, NULL, &producer);
512 }
513 
514 
515 status_t
516 BMediaRoster::SetVideoOutput(const media_node & consumer)
517 {
518 	CALLED();
519 	return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, &consumer);
520 }
521 
522 
523 status_t
524 BMediaRoster::SetVideoOutput(const dormant_node_info & consumer)
525 {
526 	CALLED();
527 	return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, NULL, &consumer);
528 }
529 
530 
531 status_t
532 BMediaRoster::SetAudioOutput(const media_node & consumer)
533 {
534 	CALLED();
535 	return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, &consumer);
536 }
537 
538 
539 status_t
540 BMediaRoster::SetAudioOutput(const media_input & input_to_output)
541 {
542 	CALLED();
543 	return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, NULL, &input_to_output);
544 }
545 
546 
547 status_t
548 BMediaRoster::SetAudioOutput(const dormant_node_info & consumer)
549 {
550 	CALLED();
551 	return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, &consumer);
552 }
553 
554 
555 status_t
556 BMediaRoster::GetNodeFor(media_node_id node,
557 						 media_node * clone)
558 {
559 	CALLED();
560 	if (clone == NULL)
561 		return B_BAD_VALUE;
562 	if (node <= 0)
563 		return B_MEDIA_BAD_NODE;
564 
565 	server_get_node_for_request request;
566 	server_get_node_for_reply reply;
567 	status_t rv;
568 
569 	request.nodeid = node;
570 	request.team = team;
571 
572 	rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply));
573 	if (rv != B_OK)
574 		return rv;
575 
576 	*clone = reply.clone;
577 	return B_OK;
578 }
579 
580 
581 status_t
582 BMediaRoster::GetSystemTimeSource(media_node * clone)
583 {
584 	CALLED();
585 	status_t rv;
586 
587 	// XXX need to do this in a nicer way.
588 
589 	rv = MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE, clone);
590 	if (rv != B_OK)
591 		return rv;
592 
593 	// We don't do reference counting for timesources, that's why we
594 	// release the node immediately.
595 	ReleaseNode(*clone);
596 
597 	// we need to remember to not use this node with server side reference counting
598 	clone->kind |= NODE_KIND_NO_REFCOUNTING;
599 
600 	return B_OK;
601 }
602 
603 
604 status_t
605 BMediaRoster::ReleaseNode(const media_node & node)
606 {
607 	CALLED();
608 	if (IS_INVALID_NODE(node))
609 		return B_MEDIA_BAD_NODE;
610 
611 	if (node.kind & NODE_KIND_NO_REFCOUNTING) {
612 		printf("BMediaRoster::ReleaseNode, trying to release reference counting disabled timesource, node %ld, port %ld, team %ld\n", node.node, node.port, team);
613 		return B_OK;
614 	}
615 
616 	server_release_node_request request;
617 	server_release_node_reply reply;
618 	status_t rv;
619 
620 	request.node = node;
621 	request.team = team;
622 
623 	TRACE("BMediaRoster::ReleaseNode, node %ld, port %ld, team %ld\n", node.node, node.port, team);
624 
625 	rv = QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply, sizeof(reply));
626 	if (rv != B_OK) {
627 		ERROR("BMediaRoster::ReleaseNode FAILED, node %ld, port %ld, team %ld!\n", node.node, node.port, team);
628 	}
629 	return rv;
630 }
631 
632 BTimeSource *
633 BMediaRoster::MakeTimeSourceFor(const media_node & for_node)
634 {
635 	// MakeTimeSourceFor() returns a BTimeSource object
636 	// corresponding to the specified node's time source.
637 
638 	CALLED();
639 
640 	if (IS_SYSTEM_TIMESOURCE(for_node)) {
641 		// special handling for the system time source
642 		TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time source\n");
643 		return MediaRosterEx(this)->MakeTimeSourceObject(NODE_SYSTEM_TIMESOURCE_ID);
644 	}
645 
646 	if (IS_INVALID_NODE(for_node)) {
647 		ERROR("BMediaRoster::MakeTimeSourceFor: for_node invalid, node %ld, port %ld, kinds 0x%lx\n", for_node.node, for_node.port, for_node.kind);
648 		return NULL;
649 	}
650 
651 	TRACE("BMediaRoster::MakeTimeSourceFor: node %ld enter\n", for_node.node);
652 
653 	node_get_timesource_request request;
654 	node_get_timesource_reply reply;
655 	BTimeSource *source;
656 	status_t rv;
657 
658 	// ask the node to get it's current timesource id
659 	rv = QueryPort(for_node.port, NODE_GET_TIMESOURCE, &request, sizeof(request), &reply, sizeof(reply));
660 	if (rv != B_OK) {
661 		ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n");
662 		return NULL;
663 	}
664 
665 	source = MediaRosterEx(this)->MakeTimeSourceObject(reply.timesource_id);
666 
667 	TRACE("BMediaRoster::MakeTimeSourceFor: node %ld leave\n", for_node.node);
668 
669 	return source;
670 }
671 
672 BTimeSource *
673 BMediaRosterEx::MakeTimeSourceObject(media_node_id timesource_id)
674 {
675 	BTimeSource *source;
676 	media_node clone;
677 	status_t rv;
678 
679 	rv = GetNodeFor(timesource_id, &clone);
680 	if (rv != B_OK) {
681 		ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed\n");
682 		return NULL;
683 	}
684 
685 	source = _TimeSourceObjectManager->GetTimeSource(clone);
686 	if (source == NULL) {
687 		ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n");
688 		return NULL;
689 	}
690 
691 	// XXX release?
692 	ReleaseNode(clone);
693 
694 	return source;
695 }
696 
697 
698 status_t
699 BMediaRoster::Connect(const media_source & from,
700 					  const media_destination & to,
701 					  media_format * io_format,
702 					  media_output * out_output,
703 					  media_input * out_input)
704 {
705 	return BMediaRoster::Connect(from, to, io_format, out_output, out_input, 0);
706 }
707 
708 
709 status_t
710 BMediaRoster::Connect(const media_source & from,
711 					  const media_destination & to,
712 					  media_format * io_format,
713 					  media_output * out_output,
714 					  media_input * out_input,
715 					  uint32 in_flags,
716 					  void * _reserved)
717 {
718 	CALLED();
719 	if (io_format == NULL || out_output == NULL || out_input == NULL)
720 		return B_BAD_VALUE;
721 	if (IS_INVALID_SOURCE(from)) {
722 		ERROR("BMediaRoster::Connect: media_source invalid\n");
723 		return B_MEDIA_BAD_SOURCE;
724 	}
725 	if (IS_INVALID_DESTINATION(to)) {
726 		ERROR("BMediaRoster::Connect: media_destination invalid\n");
727 		return B_MEDIA_BAD_DESTINATION;
728 	}
729 
730 	status_t rv;
731 	producer_format_proposal_request request1;
732 	producer_format_proposal_reply reply1;
733 
734 	PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::FormatProposal with format  ", *io_format);
735 
736 	// BBufferProducer::FormatProposal
737 	request1.output = from;
738 	request1.format = *io_format;
739 	rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1, sizeof(request1), &reply1, sizeof(reply1));
740 	if (rv != B_OK) {
741 		ERROR("BMediaRoster::Connect: aborted after BBufferProducer::FormatProposal, status = %#lx\n",rv);
742 		return rv;
743 	}
744 	// reply1.format now contains the format proposed by the producer
745 
746 	consumer_accept_format_request request2;
747 	consumer_accept_format_reply reply2;
748 
749 	PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::AcceptFormat with format    ", reply1.format);
750 
751 	// BBufferConsumer::AcceptFormat
752 	request2.dest = to;
753 	request2.format = reply1.format;
754 	rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2, sizeof(request2), &reply2, sizeof(reply2));
755 	if (rv != B_OK) {
756 		ERROR("BMediaRoster::Connect: aborted after BBufferConsumer::AcceptFormat, status = %#lx\n",rv);
757 		return rv;
758 	}
759 	// reply2.format now contains the format accepted by the consumer
760 
761 	// BBufferProducer::PrepareToConnect
762 	producer_prepare_to_connect_request request3;
763 	producer_prepare_to_connect_reply reply3;
764 
765 	PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::PrepareToConnect with format", reply2.format);
766 
767 	request3.source = from;
768 	request3.destination = to;
769 	request3.format = reply2.format;
770 	strcpy(request3.name, "XXX some default name"); // XXX fix this
771 	rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3, sizeof(request3), &reply3, sizeof(reply3));
772 	if (rv != B_OK) {
773 		ERROR("BMediaRoster::Connect: aborted after BBufferProducer::PrepareToConnect, status = %#lx\n",rv);
774 		return rv;
775 	}
776 	// reply3.format is still our pretty media format
777 	// reply3.out_source the real source to be used for the connection
778 	// reply3.name the name BBufferConsumer::Connected will see in the outInput->name argument
779 
780 
781 	// find the output and input nodes
782 	// XXX isn't there a easier way?
783 	media_node sourcenode;
784 	media_node destnode;
785 	GetNodeFor(NodeIDFor(from.port), &sourcenode);
786 	GetNodeFor(NodeIDFor(to.port), &destnode);
787 	ReleaseNode(sourcenode);
788 	ReleaseNode(destnode);
789 
790 	// BBufferConsumer::Connected
791 	consumer_connected_request request4;
792 	consumer_connected_reply reply4;
793 	status_t con_status;
794 
795 	PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::Connected with format       ", reply3.format);
796 
797 	request4.input.node = destnode;
798 	request4.input.source = reply3.out_source;
799 	request4.input.destination = to;
800 	request4.input.format = reply3.format;
801 	strcpy(request4.input.name, reply3.name);
802 
803 	con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4, sizeof(request4), &reply4, sizeof(reply4));
804 	if (con_status != B_OK) {
805 		ERROR("BMediaRoster::Connect: aborting after BBufferConsumer::Connected, status = %#lx\n",con_status);
806 		// we do NOT return here!
807 	}
808 	// con_status contains the status code to be supplied to BBufferProducer::Connect's status argument
809 	// reply4.input contains the media_input that describes the connection from the consumer point of view
810 
811 	// BBufferProducer::Connect
812 	producer_connect_request request5;
813 	producer_connect_reply reply5;
814 
815 	PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::Connect with format         ", reply4.input.format);
816 
817 	request5.error = con_status;
818 	request5.source = reply3.out_source;
819 	request5.destination = reply4.input.destination;
820 	request5.format = reply4.input.format;
821 	strcpy(request5.name, reply4.input.name);
822 	rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5, sizeof(request5), &reply5, sizeof(reply5));
823 	if (con_status != B_OK) {
824 		ERROR("BMediaRoster::Connect: aborted\n");
825 		return con_status;
826 	}
827 	if (rv != B_OK) {
828 		ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect, status = %#lx\n",rv);
829 		return rv;
830 	}
831 	// reply5.name contains the name assigned to the connection by the producer
832 
833 	// initilize connection info
834 	*io_format = reply4.input.format;
835 	*out_input = reply4.input;
836 	out_output->node = sourcenode;
837 	out_output->source = reply4.input.source;
838 	out_output->destination = reply4.input.destination;
839 	out_output->format = reply4.input.format;
840 	strcpy(out_output->name, reply5.name);
841 
842 	// the connection is now made
843 	printf("BMediaRoster::Connect connection established!\n");
844 	PRINT_FORMAT("   format", *io_format);
845 	PRINT_INPUT("   input", *out_input);
846 	PRINT_OUTPUT("   output", *out_output);
847 
848 	// XXX register connection with server
849 	// XXX we should just send a notification, instead of republishing all endpoints
850 	List<media_output> outlist;
851 	List<media_input> inlist;
852 	if (B_OK == MediaRosterEx(this)->GetAllOutputs(out_output->node , &outlist))
853 		MediaRosterEx(this)->PublishOutputs(out_output->node , &outlist);
854 	if (B_OK == MediaRosterEx(this)->GetAllInputs(out_input->node , &inlist))
855 		MediaRosterEx(this)->PublishInputs(out_input->node, &inlist);
856 
857 
858 	// XXX if (mute) BBufferProducer::EnableOutput(false)
859 	if (in_flags & B_CONNECT_MUTED) {
860 	}
861 
862 
863 	// send a notification
864 	BPrivate::media::notifications::ConnectionMade(*out_input, *out_output, *io_format);
865 
866 	return B_OK;
867 };
868 
869 
870 status_t
871 BMediaRoster::Disconnect(media_node_id source_nodeid,
872 						 const media_source & source,
873 						 media_node_id destination_nodeid,
874 						 const media_destination & destination)
875 {
876 	CALLED();
877 	if (IS_INVALID_NODEID(source_nodeid)) {
878 		ERROR("BMediaRoster::Disconnect: source media_node_id invalid\n");
879 		return B_MEDIA_BAD_SOURCE;
880 	}
881 	if (IS_INVALID_NODEID(destination_nodeid)) {
882 		ERROR("BMediaRoster::Disconnect: destination media_node_id invalid\n");
883 		return B_MEDIA_BAD_DESTINATION;
884 	}
885 	if (IS_INVALID_SOURCE(source)) {
886 		ERROR("BMediaRoster::Disconnect: media_source invalid\n");
887 		return B_MEDIA_BAD_SOURCE;
888 	}
889 	if (IS_INVALID_DESTINATION(destination)) {
890 		ERROR("BMediaRoster::Disconnect: media_destination invalid\n");
891 		return B_MEDIA_BAD_DESTINATION;
892 	}
893 
894 	producer_disconnect_request request2;
895 	producer_disconnect_reply reply2;
896 	consumer_disconnected_request request1;
897 	consumer_disconnected_reply reply1;
898 	status_t rv1, rv2;
899 
900 	// XXX we should ask the server if this connection really exists
901 
902 	request1.source = source;
903 	request1.destination = destination;
904 	request2.source = source;
905 	request2.destination = destination;
906 
907 	rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1, sizeof(request1), &reply1, sizeof(reply1));
908 	rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2, sizeof(request2), &reply2, sizeof(reply2));
909 
910 	// XXX unregister connection with server
911 	// XXX we should just send a notification, instead of republishing all endpoints
912 	List<media_output> outlist;
913 	List<media_input> inlist;
914 	media_node sourcenode;
915 	media_node destnode;
916 	if (B_OK == GetNodeFor(source_nodeid, &sourcenode)) {
917 		if (B_OK == MediaRosterEx(this)->GetAllOutputs(sourcenode , &outlist))
918 			MediaRosterEx(this)->PublishOutputs(sourcenode , &outlist);
919 		ReleaseNode(sourcenode);
920 	} else {
921 		ERROR("BMediaRoster::Disconnect: source GetNodeFor failed\n");
922 	}
923 	if (B_OK == GetNodeFor(destination_nodeid, &destnode)) {
924 		if (B_OK == MediaRosterEx(this)->GetAllInputs(destnode , &inlist))
925 			MediaRosterEx(this)->PublishInputs(destnode, &inlist);
926 		ReleaseNode(destnode);
927 	} else {
928 		ERROR("BMediaRoster::Disconnect: dest GetNodeFor failed\n");
929 	}
930 
931 
932 	// send a notification
933 	BPrivate::media::notifications::ConnectionBroken(source, destination);
934 
935 	return (rv1 != B_OK || rv2 != B_OK) ? B_ERROR : B_OK;
936 }
937 
938 
939 status_t
940 BMediaRoster::StartNode(const media_node & node,
941 						bigtime_t at_performance_time)
942 {
943 	CALLED();
944 	if (node.node <= 0)
945 		return B_MEDIA_BAD_NODE;
946 
947 	TRACE("BMediaRoster::StartNode, node %ld, at perf %Ld\n", node.node, at_performance_time);
948 
949 	node_start_command command;
950 	command.performance_time = at_performance_time;
951 
952 	return SendToPort(node.port, NODE_START, &command, sizeof(command));
953 }
954 
955 
956 status_t
957 BMediaRoster::StopNode(const media_node & node,
958 					   bigtime_t at_performance_time,
959 					   bool immediate)
960 {
961 	CALLED();
962 	if (IS_INVALID_NODE(node))
963 		return B_MEDIA_BAD_NODE;
964 
965 	TRACE("BMediaRoster::StopNode, node %ld, at perf %Ld %s\n", node.node, at_performance_time, immediate ? "NOW" : "");
966 
967 	node_stop_command command;
968 	command.performance_time = at_performance_time;
969 	command.immediate = immediate;
970 
971 	return SendToPort(node.port, NODE_STOP, &command, sizeof(command));
972 }
973 
974 
975 status_t
976 BMediaRoster::SeekNode(const media_node & node,
977 					   bigtime_t to_media_time,
978 					   bigtime_t at_performance_time)
979 {
980 	CALLED();
981 	if (IS_INVALID_NODE(node))
982 		return B_MEDIA_BAD_NODE;
983 
984 	TRACE("BMediaRoster::SeekNode, node %ld, at perf %Ld, to perf %Ld\n", node.node, at_performance_time, to_media_time);
985 
986 	node_seek_command command;
987 	command.media_time = to_media_time;
988 	command.performance_time = at_performance_time;
989 
990 	return SendToPort(node.port, NODE_SEEK, &command, sizeof(command));
991 }
992 
993 
994 status_t
995 BMediaRoster::StartTimeSource(const media_node & node,
996 							  bigtime_t at_real_time)
997 {
998 	CALLED();
999 	if (IS_SYSTEM_TIMESOURCE(node)) {
1000 		// XXX debug this
1001 		//ERROR("BMediaRoster::StartTimeSource node %ld is system timesource\n", node.node);
1002 		return B_OK;
1003 	}
1004 //	if (IS_SHADOW_TIMESOURCE(node)) {
1005 //		// XXX debug this
1006 //		ERROR("BMediaRoster::StartTimeSource node %ld is shadow timesource\n", node.node);
1007 //		return B_OK;
1008 //	}
1009 	if (IS_INVALID_NODE(node)) {
1010 		ERROR("BMediaRoster::StartTimeSource node %ld invalid\n", node.node);
1011 		return B_MEDIA_BAD_NODE;
1012 	}
1013 	if ((node.kind & B_TIME_SOURCE) == 0) {
1014 		ERROR("BMediaRoster::StartTimeSource node %ld is no timesource\n", node.node);
1015 		return B_MEDIA_BAD_NODE;
1016 	}
1017 
1018 	TRACE("BMediaRoster::StartTimeSource, node %ld, at real %Ld\n", node.node, at_real_time);
1019 
1020 	BTimeSource::time_source_op_info msg;
1021 	msg.op = BTimeSource::B_TIMESOURCE_START;
1022 	msg.real_time = at_real_time;
1023 
1024 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1025 }
1026 
1027 
1028 status_t
1029 BMediaRoster::StopTimeSource(const media_node & node,
1030 							 bigtime_t at_real_time,
1031 							 bool immediate)
1032 {
1033 	CALLED();
1034 	if (IS_SYSTEM_TIMESOURCE(node)) {
1035 		// XXX debug this
1036 		//ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node);
1037 		return B_OK;
1038 	}
1039 //	if (IS_SHADOW_TIMESOURCE(node)) {
1040 //		// XXX debug this
1041 //		ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node);
1042 //		return B_OK;
1043 //	}
1044 	if (IS_INVALID_NODE(node)) {
1045 		ERROR("BMediaRoster::StopTimeSource node %ld invalid\n", node.node);
1046 		return B_MEDIA_BAD_NODE;
1047 	}
1048 	if ((node.kind & B_TIME_SOURCE) == 0) {
1049 		ERROR("BMediaRoster::StopTimeSource node %ld is no timesource\n", node.node);
1050 		return B_MEDIA_BAD_NODE;
1051 	}
1052 
1053 	TRACE("BMediaRoster::StopTimeSource, node %ld, at real %Ld %s\n", node.node, at_real_time, immediate ? "NOW" : "");
1054 
1055 	BTimeSource::time_source_op_info msg;
1056 	msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY : BTimeSource::B_TIMESOURCE_STOP;
1057 	msg.real_time = at_real_time;
1058 
1059 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1060 }
1061 
1062 
1063 status_t
1064 BMediaRoster::SeekTimeSource(const media_node & node,
1065 							 bigtime_t to_performance_time,
1066 							 bigtime_t at_real_time)
1067 {
1068 	CALLED();
1069 	if (IS_SYSTEM_TIMESOURCE(node)) {
1070 		// XXX debug this
1071 		// ERROR("BMediaRoster::SeekTimeSource node %ld is system timesource\n", node.node);
1072 		// you can't seek the system time source, but
1073 		// returning B_ERROR would break StampTV
1074 		return B_OK;
1075 	}
1076 //	if (IS_SHADOW_TIMESOURCE(node)) {
1077 //		// XXX debug this
1078 //		ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node);
1079 //		return B_OK;
1080 //	}
1081 	if (IS_INVALID_NODE(node)) {
1082 		ERROR("BMediaRoster::SeekTimeSource node %ld invalid\n", node.node);
1083 		return B_MEDIA_BAD_NODE;
1084 	}
1085 	if ((node.kind & B_TIME_SOURCE) == 0) {
1086 		ERROR("BMediaRoster::SeekTimeSource node %ld is no timesource\n", node.node);
1087 		return B_MEDIA_BAD_NODE;
1088 	}
1089 
1090 	TRACE("BMediaRoster::SeekTimeSource, node %ld, at real %Ld, to perf %Ld\n", node.node, at_real_time, to_performance_time);
1091 
1092 	BTimeSource::time_source_op_info msg;
1093 	msg.op = BTimeSource::B_TIMESOURCE_SEEK;
1094 	msg.real_time = at_real_time;
1095 	msg.performance_time = to_performance_time;
1096 
1097 	return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1098 }
1099 
1100 
1101 status_t
1102 BMediaRoster::SyncToNode(const media_node & node,
1103 						 bigtime_t at_time,
1104 						 bigtime_t timeout)
1105 {
1106 	UNIMPLEMENTED();
1107 	return B_OK;
1108 }
1109 
1110 
1111 status_t
1112 BMediaRoster::SetRunModeNode(const media_node & node,
1113 							 BMediaNode::run_mode mode)
1114 {
1115 	CALLED();
1116 	if (IS_INVALID_NODE(node))
1117 		return B_MEDIA_BAD_NODE;
1118 
1119 	node_set_run_mode_command msg;
1120 	msg.mode = mode;
1121 
1122 	return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg));
1123 }
1124 
1125 
1126 status_t
1127 BMediaRoster::PrerollNode(const media_node & node)
1128 {
1129 	CALLED();
1130 	if (IS_INVALID_NODE(node))
1131 		return B_MEDIA_BAD_NODE;
1132 
1133 	char dummy;
1134 	return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy));
1135 }
1136 
1137 
1138 status_t
1139 BMediaRoster::RollNode(const media_node & node,
1140 					   bigtime_t startPerformance,
1141 					   bigtime_t stopPerformance,
1142 					   bigtime_t atMediaTime)
1143 {
1144 	UNIMPLEMENTED();
1145 	return B_ERROR;
1146 }
1147 
1148 
1149 status_t
1150 BMediaRoster::SetProducerRunModeDelay(const media_node & node,
1151 									  bigtime_t delay,
1152 									  BMediaNode::run_mode mode)
1153 {
1154 	CALLED();
1155 	if (IS_INVALID_NODE(node))
1156 		return B_MEDIA_BAD_NODE;
1157 	if ((node.kind & B_BUFFER_PRODUCER) == 0)
1158 		return B_MEDIA_BAD_NODE;
1159 
1160 	producer_set_run_mode_delay_command command;
1161 	command.mode = mode;
1162 	command.delay = delay;
1163 
1164 	return SendToPort(node.port, PRODUCER_SET_RUN_MODE_DELAY, &command, sizeof(command));
1165 }
1166 
1167 
1168 status_t
1169 BMediaRoster::SetProducerRate(const media_node & producer,
1170 							  int32 numer,
1171 							  int32 denom)
1172 {
1173 	CALLED();
1174 	if (IS_INVALID_NODE(producer))
1175 		return B_MEDIA_BAD_NODE;
1176 	if ((producer.kind & B_BUFFER_PRODUCER) == 0)
1177 		return B_MEDIA_BAD_NODE;
1178 
1179 	producer_set_play_rate_request msg;
1180 	producer_set_play_rate_reply reply;
1181 	status_t rv;
1182 	int32 code;
1183 
1184 	msg.numer = numer;
1185 	msg.denom = denom;
1186 	msg.reply_port = _PortPool->GetPort();
1187 	rv = write_port(producer.node, PRODUCER_SET_PLAY_RATE, &msg, sizeof(msg));
1188 	if (rv != B_OK) {
1189 		_PortPool->PutPort(msg.reply_port);
1190 		return rv;
1191 	}
1192 	rv = read_port(msg.reply_port, &code, &reply, sizeof(reply));
1193 	_PortPool->PutPort(msg.reply_port);
1194 	return (rv < B_OK) ? rv : reply.result;
1195 }
1196 
1197 
1198 /* Nodes will have available inputs/outputs as long as they are capable */
1199 /* of accepting more connections. The node may create an additional */
1200 /* output or input as the currently available is taken into usage. */
1201 status_t
1202 BMediaRoster::GetLiveNodeInfo(const media_node & node,
1203 							  live_node_info * out_live_info)
1204 {
1205 	CALLED();
1206 	if (out_live_info == NULL)
1207 		return B_BAD_VALUE;
1208 	if (IS_INVALID_NODE(node))
1209 		return B_MEDIA_BAD_NODE;
1210 
1211 	server_get_live_node_info_request request;
1212 	server_get_live_node_info_reply reply;
1213 	status_t rv;
1214 
1215 	request.node = node;
1216 
1217 	rv = QueryServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request), &reply, sizeof(reply));
1218 	if (rv != B_OK)
1219 		return rv;
1220 
1221 	*out_live_info = reply.live_info;
1222 	return B_OK;
1223 }
1224 
1225 
1226 status_t
1227 BMediaRoster::GetLiveNodes(live_node_info * out_live_nodes,
1228 						   int32 * io_total_count,
1229 						   const media_format * has_input,
1230 						   const media_format * has_output,
1231 						   const char * name,
1232 						   uint64 node_kinds)
1233 {
1234 	CALLED();
1235 	if (out_live_nodes == NULL || io_total_count == NULL)
1236 		return B_BAD_VALUE;
1237 	if (*io_total_count <= 0)
1238 		return B_BAD_VALUE;
1239 
1240 	// XXX we also support the wildcard search as GetDormantNodes does. This needs to be documented
1241 
1242 	server_get_live_nodes_request request;
1243 	server_get_live_nodes_reply reply;
1244 	status_t rv;
1245 
1246 	request.maxcount = *io_total_count;
1247 	request.has_input = (bool) has_input;
1248 	if (has_input)
1249 		request.inputformat = *has_input; // XXX we should not make a flat copy of media_format
1250 	request.has_output = (bool) has_output;
1251 	if (has_output)
1252 		request.outputformat = *has_output; // XXX we should not make a flat copy of media_format
1253 	request.has_name = (bool) name;
1254 	if (name) {
1255 		int len = strlen(name);
1256 		len = min_c(len, (int)sizeof(request.name) - 1);
1257 		memcpy(request.name, name, len);
1258 		request.name[len] = 0;
1259 	}
1260 	request.require_kinds = node_kinds;
1261 
1262 	rv = QueryServer(SERVER_GET_LIVE_NODES, &request, sizeof(request), &reply, sizeof(reply));
1263 	if (rv != B_OK) {
1264 		ERROR("BMediaRoster::GetLiveNodes failed querying server\n");
1265 		*io_total_count = 0;
1266 		return rv;
1267 	}
1268 
1269 	if (reply.count > MAX_LIVE_INFO) {
1270 		live_node_info *live_info;
1271 		area_id clone;
1272 
1273 		clone = clone_area("live_node_info clone", reinterpret_cast<void **>(&live_info), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, reply.area);
1274 		if (clone < B_OK) {
1275 			ERROR("BMediaRoster::GetLiveNodes failed to clone area, %#lx\n", clone);
1276 			delete_area(reply.area);
1277 			*io_total_count = 0;
1278 			return B_ERROR;
1279 		}
1280 
1281 		for (int32 i = 0; i < reply.count; i++) {
1282 			out_live_nodes[i] = live_info[i];
1283 		}
1284 
1285 		delete_area(clone);
1286 		delete_area(reply.area);
1287 	} else {
1288 		for (int32 i = 0; i < reply.count; i++) {
1289 			out_live_nodes[i] = reply.live_info[i];
1290 		}
1291 	}
1292 	*io_total_count = reply.count;
1293 
1294 	return B_OK;
1295 }
1296 
1297 
1298 status_t
1299 BMediaRoster::GetFreeInputsFor(const media_node & node,
1300 							   media_input * out_free_inputs,
1301 							   int32 buf_num_inputs,
1302 							   int32 * out_total_count,
1303 							   media_type filter_type)
1304 {
1305 	CALLED();
1306 	if (IS_INVALID_NODE(node)) {
1307 		ERROR("BMediaRoster::GetFreeInputsFor: node %ld, port %ld invalid\n", node.node, node.port);
1308 		return B_MEDIA_BAD_NODE;
1309 	}
1310 	if ((node.kind & B_BUFFER_CONSUMER) == 0) {
1311 		ERROR("BMediaRoster::GetFreeInputsFor: node %ld, port %ld is not a consumer\n", node.node, node.port);
1312 		return B_MEDIA_BAD_NODE;
1313 	}
1314 	if (out_free_inputs == NULL || out_total_count == NULL)
1315 		return B_BAD_VALUE;
1316 
1317 	List<media_input> list;
1318 	media_input *input;
1319 	status_t rv;
1320 
1321 	*out_total_count = 0;
1322 
1323 	rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1324 	if (B_OK != rv)
1325 		return rv;
1326 
1327 	PRINT(4, "BMediaRoster::GetFreeInputsFor node %ld, max %ld, filter-type %ld\n", node.node, buf_num_inputs, filter_type);
1328 
1329 	int32 i;
1330 	for (i = 0, list.Rewind(); list.GetNext(&input);) {
1331 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != input->format.type)
1332 			continue; // media_type used, but doesn't match
1333 		if (input->source != media_source::null)
1334 			continue; // consumer source already connected
1335 		out_free_inputs[i] = *input;
1336 		*out_total_count += 1;
1337 		buf_num_inputs -= 1;
1338 		#if DEBUG >= 3
1339 			PRINT_OUTPUT("  input", out_free_inputs[i]);
1340 		#endif
1341 		if (buf_num_inputs == 0)
1342 			break;
1343 		i++;
1344 	}
1345 
1346 	MediaRosterEx(this)->PublishInputs(node, &list);
1347 	return B_OK;
1348 }
1349 
1350 
1351 status_t
1352 BMediaRoster::GetConnectedInputsFor(const media_node & node,
1353 									media_input * out_active_inputs,
1354 									int32 buf_num_inputs,
1355 									int32 * out_total_count)
1356 {
1357 	CALLED();
1358 	if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1359 		return B_MEDIA_BAD_NODE;
1360 	if (out_active_inputs == NULL || out_total_count == NULL)
1361 		return B_BAD_VALUE;
1362 
1363 	List<media_input> list;
1364 	media_input *input;
1365 	status_t rv;
1366 
1367 	*out_total_count = 0;
1368 
1369 	rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1370 	if (B_OK != rv)
1371 		return rv;
1372 
1373 	PRINT(4, "BMediaRoster::GetConnectedInputsFor node %ld, max %ld\n", node.node, buf_num_inputs);
1374 
1375 	int32 i;
1376 	for (i = 0, list.Rewind(); list.GetNext(&input);) {
1377 		if (input->source == media_source::null)
1378 			continue; // consumer source not connected
1379 		out_active_inputs[i] = *input;
1380 		*out_total_count += 1;
1381 		buf_num_inputs -= 1;
1382 		#if DEBUG >= 3
1383 			PRINT_OUTPUT("  input ", out_active_inputs[i]);
1384 		#endif
1385 		if (buf_num_inputs == 0)
1386 			break;
1387 		i++;
1388 	}
1389 
1390 	MediaRosterEx(this)->PublishInputs(node, &list);
1391 	return B_OK;
1392 }
1393 
1394 
1395 status_t
1396 BMediaRoster::GetAllInputsFor(const media_node & node,
1397 							  media_input * out_inputs,
1398 							  int32 buf_num_inputs,
1399 							  int32 * out_total_count)
1400 {
1401 	CALLED();
1402 	if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1403 		return B_MEDIA_BAD_NODE;
1404 	if (out_inputs == NULL || out_total_count == NULL)
1405 		return B_BAD_VALUE;
1406 
1407 	List<media_input> list;
1408 	media_input *input;
1409 	status_t rv;
1410 
1411 	*out_total_count = 0;
1412 
1413 	rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1414 	if (B_OK != rv)
1415 		return rv;
1416 
1417 	PRINT(4, "BMediaRoster::GetAllInputsFor node %ld, max %ld\n", node.node, buf_num_inputs);
1418 
1419 	int32 i;
1420 	for (i = 0, list.Rewind(); list.GetNext(&input); i++) {
1421 		out_inputs[i] = *input;
1422 		*out_total_count += 1;
1423 		buf_num_inputs -= 1;
1424 		#if DEBUG >= 3
1425 			PRINT_OUTPUT("  input ", out_inputs[i]);
1426 		#endif
1427 		if (buf_num_inputs == 0)
1428 			break;
1429 	}
1430 
1431 	MediaRosterEx(this)->PublishInputs(node, &list);
1432 	return B_OK;
1433 }
1434 
1435 
1436 status_t
1437 BMediaRoster::GetFreeOutputsFor(const media_node & node,
1438 								media_output * out_free_outputs,
1439 								int32 buf_num_outputs,
1440 								int32 * out_total_count,
1441 								media_type filter_type)
1442 {
1443 	CALLED();
1444 	if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1445 		return B_MEDIA_BAD_NODE;
1446 	if (out_free_outputs == NULL || out_total_count == NULL)
1447 		return B_BAD_VALUE;
1448 
1449 	List<media_output> list;
1450 	media_output *output;
1451 	status_t rv;
1452 
1453 	*out_total_count = 0;
1454 
1455 	rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1456 	if (B_OK != rv)
1457 		return rv;
1458 
1459 	PRINT(4, "BMediaRoster::GetFreeOutputsFor node %ld, max %ld, filter-type %ld\n", node.node, buf_num_outputs, filter_type);
1460 
1461 	int32 i;
1462 	for (i = 0, list.Rewind(); list.GetNext(&output);) {
1463 		if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != output->format.type)
1464 			continue; // media_type used, but doesn't match
1465 		if (output->destination != media_destination::null)
1466 			continue; // producer destination already connected
1467 		out_free_outputs[i] = *output;
1468 		*out_total_count += 1;
1469 		buf_num_outputs -= 1;
1470 		#if DEBUG >= 3
1471 			PRINT_OUTPUT("  output ", out_free_outputs[i]);
1472 		#endif
1473 		if (buf_num_outputs == 0)
1474 			break;
1475 		i++;
1476 	}
1477 
1478 	MediaRosterEx(this)->PublishOutputs(node, &list);
1479 	return B_OK;
1480 }
1481 
1482 
1483 status_t
1484 BMediaRoster::GetConnectedOutputsFor(const media_node & node,
1485 									 media_output * out_active_outputs,
1486 									 int32 buf_num_outputs,
1487 									 int32 * out_total_count)
1488 {
1489 	CALLED();
1490 	if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1491 		return B_MEDIA_BAD_NODE;
1492 	if (out_active_outputs == NULL || out_total_count == NULL)
1493 		return B_BAD_VALUE;
1494 
1495 	List<media_output> list;
1496 	media_output *output;
1497 	status_t rv;
1498 
1499 	*out_total_count = 0;
1500 
1501 	rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1502 	if (B_OK != rv)
1503 		return rv;
1504 
1505 	PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %ld, max %ld\n", node.node, buf_num_outputs);
1506 
1507 	int32 i;
1508 	for (i = 0, list.Rewind(); list.GetNext(&output);) {
1509 		if (output->destination == media_destination::null)
1510 			continue; // producer destination not connected
1511 		out_active_outputs[i] = *output;
1512 		*out_total_count += 1;
1513 		buf_num_outputs -= 1;
1514 		#if DEBUG >= 3
1515 			PRINT_OUTPUT("  output ", out_active_outputs[i]);
1516 		#endif
1517 		if (buf_num_outputs == 0)
1518 			break;
1519 		i++;
1520 	}
1521 
1522 	MediaRosterEx(this)->PublishOutputs(node, &list);
1523 	return B_OK;
1524 }
1525 
1526 
1527 status_t
1528 BMediaRoster::GetAllOutputsFor(const media_node & node,
1529 							   media_output * out_outputs,
1530 							   int32 buf_num_outputs,
1531 							   int32 * out_total_count)
1532 {
1533 	CALLED();
1534 	if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1535 		return B_MEDIA_BAD_NODE;
1536 	if (out_outputs == NULL || out_total_count == NULL)
1537 		return B_BAD_VALUE;
1538 
1539 	List<media_output> list;
1540 	media_output *output;
1541 	status_t rv;
1542 
1543 	*out_total_count = 0;
1544 
1545 	rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1546 	if (B_OK != rv)
1547 		return rv;
1548 
1549 	PRINT(4, "BMediaRoster::GetAllOutputsFor node %ld, max %ld\n", node.node, buf_num_outputs);
1550 
1551 	int32 i;
1552 	for (i = 0, list.Rewind(); list.GetNext(&output); i++) {
1553 		out_outputs[i] = *output;
1554 		*out_total_count += 1;
1555 		buf_num_outputs -= 1;
1556 		#if DEBUG >= 3
1557 			PRINT_OUTPUT("  output ", out_outputs[i]);
1558 		#endif
1559 		if (buf_num_outputs == 0)
1560 			break;
1561 	}
1562 
1563 	MediaRosterEx(this)->PublishOutputs(node, &list);
1564 	return B_OK;
1565 }
1566 
1567 
1568 status_t
1569 BMediaRoster::StartWatching(const BMessenger & where)
1570 {
1571 	CALLED();
1572 	if (!where.IsValid()) {
1573 		ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1574 		return B_BAD_VALUE;
1575 	}
1576 	return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD);
1577 }
1578 
1579 
1580 status_t
1581 BMediaRoster::StartWatching(const BMessenger & where,
1582 							int32 notificationType)
1583 {
1584 	CALLED();
1585 	if (!where.IsValid()) {
1586 		ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1587 		return B_BAD_VALUE;
1588 	}
1589 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1590 		ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1591 		return B_BAD_VALUE;
1592 	}
1593 	return BPrivate::media::notifications::Register(where, media_node::null, notificationType);
1594 }
1595 
1596 
1597 status_t
1598 BMediaRoster::StartWatching(const BMessenger & where,
1599 							const media_node & node,
1600 							int32 notificationType)
1601 {
1602 	CALLED();
1603 	if (!where.IsValid()) {
1604 		ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1605 		return B_BAD_VALUE;
1606 	}
1607 	if (IS_INVALID_NODE(node)) {
1608 		ERROR("BMediaRoster::StartWatching: node invalid!\n");
1609 		return B_MEDIA_BAD_NODE;
1610 	}
1611 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1612 		ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1613 		return B_BAD_VALUE;
1614 	}
1615 	return BPrivate::media::notifications::Register(where, node, notificationType);
1616 }
1617 
1618 
1619 status_t
1620 BMediaRoster::StopWatching(const BMessenger & where)
1621 {
1622 	CALLED();
1623 	// messenger may already be invalid, so we don't check this
1624 	return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD);
1625 }
1626 
1627 
1628 status_t
1629 BMediaRoster::StopWatching(const BMessenger & where,
1630 						   int32 notificationType)
1631 {
1632 	CALLED();
1633 	// messenger may already be invalid, so we don't check this
1634 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) {
1635 		ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1636 		return B_BAD_VALUE;
1637 	}
1638 	return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType);
1639 }
1640 
1641 
1642 status_t
1643 BMediaRoster::StopWatching(const BMessenger & where,
1644 						   const media_node & node,
1645 						   int32 notificationType)
1646 {
1647 	CALLED();
1648 	// messenger may already be invalid, so we don't check this
1649 	if (IS_INVALID_NODE(node)) {
1650 		ERROR("BMediaRoster::StopWatching: node invalid!\n");
1651 		return B_MEDIA_BAD_NODE;
1652 	}
1653 	if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) {
1654 		ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1655 		return B_BAD_VALUE;
1656 	}
1657 	return BPrivate::media::notifications::Unregister(where, node, notificationType);
1658 }
1659 
1660 
1661 status_t
1662 BMediaRoster::RegisterNode(BMediaNode * node)
1663 {
1664 	CALLED();
1665 	// addon-id = -1 (unused), addon-flavor-id = 0 (unused, too)
1666 	return MediaRosterEx(this)->RegisterNode(node, -1, 0);
1667 }
1668 
1669 
1670 status_t
1671 BMediaRosterEx::RegisterNode(BMediaNode * node, media_addon_id addonid, int32 flavorid)
1672 {
1673 	CALLED();
1674 	if (node == NULL)
1675 		return B_BAD_VALUE;
1676 
1677 	// some sanity check
1678 	// I'm not sure if the media kit warrants to call BMediaNode::AddOn() here.
1679 	// Perhaps we don't need it.
1680 	{
1681 		BMediaAddOn *addon;
1682 		int32 addon_flavor_id;
1683 		media_addon_id addon_id;
1684 		addon_flavor_id = 0;
1685 		addon = node->AddOn(&addon_flavor_id);
1686 		addon_id = addon ? addon->AddonID() : -1;
1687 		ASSERT(addonid == addon_id);
1688 		ASSERT(flavorid == addon_flavor_id);
1689 	}
1690 
1691 	status_t rv;
1692 	server_register_node_request request;
1693 	server_register_node_reply reply;
1694 
1695 	request.addon_id = addonid;
1696 	request.addon_flavor_id = flavorid;
1697 	strcpy(request.name, node->Name());
1698 	request.kinds = node->Kinds();
1699 	request.port = node->ControlPort();
1700 	request.team = team;
1701 
1702 	TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port %ld, kinds 0x%Lx, team %ld, name '%s'\n", request.port, request.kinds, request.team, request.name);
1703 
1704 	rv = QueryServer(SERVER_REGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1705 	if (rv != B_OK) {
1706 		ERROR("BMediaRoster::RegisterNode: failed to register node %s (error %#lx)\n", node->Name(), rv);
1707 		return rv;
1708 	}
1709 
1710 	TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE finished\n");
1711 
1712 	// we are a friend class of BMediaNode and initialize this member variable
1713 	node->fNodeID = reply.nodeid;
1714 	ASSERT(reply.nodeid == node->Node().node);
1715 	ASSERT(reply.nodeid == node->ID());
1716 
1717 	// call the callback
1718 	node->NodeRegistered();
1719 
1720 	TRACE("BMediaRoster::RegisterNode: NodeRegistered callback finished\n");
1721 
1722 	// if the BMediaNode also inherits from BTimeSource, we need to call BTimeSource::FinishCreate()
1723 	if (node->Kinds() & B_TIME_SOURCE) {
1724 		BTimeSource *ts;
1725 		ts = dynamic_cast<BTimeSource *>(node);
1726 		if (ts)
1727 			ts->FinishCreate();
1728 	}
1729 
1730 	TRACE("BMediaRoster::RegisterNode: publishing inputs/outputs\n");
1731 
1732 	// register existing inputs and outputs with the
1733 	// media_server, this allows GetLiveNodes() to work
1734 	// with created, but unconnected nodes.
1735 	// The node control loop might not be running, or might deadlock
1736 	// if we send a message and wait for a reply here.
1737 	// We have a pointer to the node, and thus call the functions directly
1738 
1739 	if (node->Kinds() & B_BUFFER_PRODUCER) {
1740 		BBufferProducer *bp;
1741 		bp = dynamic_cast<BBufferProducer *>(node);
1742 		if (bp) {
1743 			List<media_output> list;
1744 			if (B_OK == GetAllOutputs(bp, &list))
1745 				PublishOutputs(node->Node(), &list);
1746 		}
1747 	}
1748 	if (node->Kinds() & B_BUFFER_CONSUMER) {
1749 		BBufferConsumer *bc;
1750 		bc = dynamic_cast<BBufferConsumer *>(node);
1751 		if (bc) {
1752 			List<media_input> list;
1753 			if (B_OK == GetAllInputs(bc, &list))
1754 				PublishInputs(node->Node(), &list);
1755 		}
1756 	}
1757 
1758 	TRACE("BMediaRoster::RegisterNode: sending NodesCreated\n");
1759 
1760 	BPrivate::media::notifications::NodesCreated(&reply.nodeid, 1);
1761 
1762 	TRACE("BMediaRoster::RegisterNode: finished\n");
1763 
1764 /*
1765 	TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id);
1766 	TRACE("BMediaRoster::RegisterNode: node this               %p\n", node);
1767 	TRACE("BMediaRoster::RegisterNode: node fConsumerThis      %p\n", node->fConsumerThis);
1768 	TRACE("BMediaRoster::RegisterNode: node fProducerThis      %p\n", node->fProducerThis);
1769 	TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n", node->fFileInterfaceThis);
1770 	TRACE("BMediaRoster::RegisterNode: node fControllableThis  %p\n", node->fControllableThis);
1771 	TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis    %p\n", node->fTimeSourceThis);
1772 */
1773 	return B_OK;
1774 }
1775 
1776 
1777 status_t
1778 BMediaRoster::UnregisterNode(BMediaNode * node)
1779 {
1780 	CALLED();
1781 	if (node == NULL)
1782 		return B_BAD_VALUE;
1783 
1784 	TRACE("BMediaRoster::UnregisterNode %ld (%p)\n", node->ID(), node);
1785 
1786 	if (node->fKinds & NODE_KIND_NO_REFCOUNTING) {
1787 		printf("BMediaRoster::UnregisterNode, trying to unregister reference counting disabled timesource, node %ld, port %ld, team %ld\n", node->ID(), node->ControlPort(), team);
1788 		return B_OK;
1789 	}
1790 	if (node->ID() == NODE_UNREGISTERED_ID) {
1791 		PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name '%s' already unregistered\n", node->ID(), node->Name());
1792 		return B_OK;
1793 	}
1794 	if (node->fRefCount != 0) {
1795 		PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name '%s' has local reference count of %ld\n", node->ID(), node->Name(), node->fRefCount);
1796 		// no return here, we continue and unregister!
1797 	}
1798 
1799 	// Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node, BMessage *config)
1800 	// if this node was instanciated by an add-on needs to be done *somewhere*
1801 	// We can't do it here because it is already to late (destructor of the node
1802 	// might have been called).
1803 
1804 	server_unregister_node_request request;
1805 	server_unregister_node_reply reply;
1806 	status_t rv;
1807 
1808 	request.nodeid = node->ID();
1809 	request.team = team;
1810 
1811 	// send a notification
1812 	BPrivate::media::notifications::NodesDeleted(&request.nodeid, 1);
1813 
1814 	rv = QueryServer(SERVER_UNREGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply));
1815 	if (rv != B_OK) {
1816 		ERROR("BMediaRoster::UnregisterNode: failed to unregister node id %ld, name '%s' (error %#lx)\n", node->ID(), node->Name(), rv);
1817 		return rv;
1818 	}
1819 
1820 	if (reply.addonid != -1) {
1821 		// Small problem here, we can't use DormantNodeManager::PutAddon(), as
1822 		// UnregisterNode() is called by a dormant node itself (by the destructor).
1823 		// The add-on that contains the node needs to remain in memory until the
1824 		// destructor execution is finished.
1825 		// DormantNodeManager::PutAddonDelayed() will delay unloading.
1826 		_DormantNodeManager->PutAddonDelayed(reply.addonid);
1827 
1828 		rv = MediaRosterEx(this)->DecrementAddonFlavorInstancesCount(reply.addonid, reply.flavorid);
1829 		if (rv != B_OK) {
1830 			ERROR("BMediaRoster::UnregisterNode: DecrementAddonFlavorInstancesCount failed\n");
1831 			// this is really a problem, but we can't fail now
1832 		}
1833 	}
1834 
1835 	// we are a friend class of BMediaNode and invalidate this member variable
1836 	node->fNodeID = NODE_UNREGISTERED_ID;
1837 
1838 	return B_OK;
1839 }
1840 
1841 
1842 //	thread safe for multiple calls to Roster()
1843 /* static */ BMediaRoster *
1844 BMediaRoster::Roster(status_t* out_error)
1845 {
1846 	static BLocker locker("BMediaRoster::Roster locker");
1847 	locker.Lock();
1848 	if (_sDefault == NULL) {
1849 		_sDefault = new BMediaRosterEx();
1850 		if (out_error != NULL)
1851 			*out_error = B_OK;
1852 	} else {
1853 		if (out_error != NULL)
1854 			*out_error = B_OK;
1855 	}
1856 	locker.Unlock();
1857 	return _sDefault;
1858 }
1859 
1860 
1861 //	won't create it if there isn't one
1862 //	not thread safe if you call Roster() at the same time
1863 /* static */ BMediaRoster *
1864 BMediaRoster::CurrentRoster()
1865 {
1866 	return _sDefault;
1867 }
1868 
1869 
1870 status_t
1871 BMediaRoster::SetTimeSourceFor(media_node_id node,
1872 							   media_node_id time_source)
1873 {
1874 	CALLED();
1875 	if (IS_INVALID_NODEID(node) || IS_INVALID_NODEID(time_source))
1876 		return B_BAD_VALUE;
1877 
1878 	media_node clone;
1879 	status_t rv, result;
1880 
1881 	TRACE("BMediaRoster::SetTimeSourceFor: node %ld will be assigned time source %ld\n", node, time_source);
1882 
1883 	printf("BMediaRoster::SetTimeSourceFor: node %ld time source %ld enter\n", node, time_source);
1884 
1885 	// we need to get a clone of the node to have a port id
1886 	rv = GetNodeFor(node, &clone);
1887 	if (rv != B_OK) {
1888 		ERROR("BMediaRoster::SetTimeSourceFor, GetNodeFor failed, node id %ld\n", node);
1889 		return B_ERROR;
1890 	}
1891 
1892 	// we just send the request to set time_source-id as timesource to the node,
1893 	// the NODE_SET_TIMESOURCE handler code will do the real assignment
1894 	result = B_OK;
1895 	node_set_timesource_command cmd;
1896 	cmd.timesource_id = time_source;
1897 	rv = SendToPort(clone.port, NODE_SET_TIMESOURCE, &cmd, sizeof(cmd));
1898 	if (rv != B_OK) {
1899 		ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE failed, node id %ld\n", node);
1900 		result = B_ERROR;
1901 	}
1902 
1903 	// we release the clone
1904 	rv = ReleaseNode(clone);
1905 	if (rv != B_OK) {
1906 		ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed, node id %ld\n", node);
1907 		result = B_ERROR;
1908 	}
1909 
1910 	printf("BMediaRoster::SetTimeSourceFor: node %ld time source %ld leave\n", node, time_source);
1911 
1912 	return result;
1913 }
1914 
1915 
1916 status_t
1917 BMediaRoster::GetParameterWebFor(const media_node & node,
1918 								 BParameterWeb ** out_web)
1919 {
1920 	CALLED();
1921 	if (out_web == NULL)
1922 		return B_BAD_VALUE;
1923 	if (IS_INVALID_NODE(node))
1924 		return B_MEDIA_BAD_NODE;
1925 	if ((node.kind & B_CONTROLLABLE) == 0)
1926 		return B_MEDIA_BAD_NODE;
1927 
1928 	controllable_get_parameter_web_request request;
1929 	controllable_get_parameter_web_reply reply;
1930 	int32 requestsize[] = {B_PAGE_SIZE, 4*B_PAGE_SIZE, 16*B_PAGE_SIZE, 64*B_PAGE_SIZE, 128*B_PAGE_SIZE, 256*B_PAGE_SIZE, 0};
1931 	int32 size;
1932 
1933 	// XXX it might be better to query the node for the (current) parameter size first
1934 	for (int i = 0; (size = requestsize[i]) != 0; i++) {
1935 		status_t rv;
1936 		area_id area;
1937 		void *data;
1938 		area = create_area("parameter web data", &data, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1939 		if (area < B_OK) {
1940 			ERROR("BMediaRoster::GetParameterWebFor couldn't create area of size %ld\n", size);
1941 			return B_ERROR;
1942 		}
1943 		request.maxsize = size;
1944 		request.area = area;
1945 		rv = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_WEB, &request, sizeof(request), &reply, sizeof(reply));
1946 		if (rv != B_OK) {
1947 			ERROR("BMediaRoster::GetParameterWebFor CONTROLLABLE_GET_PARAMETER_WEB failed\n");
1948 			delete_area(area);
1949 			return B_ERROR;
1950 		}
1951 		if (reply.size == 0) {
1952 			// no parameter web available
1953 			// XXX should we return an error?
1954 			ERROR("BMediaRoster::GetParameterWebFor node %ld has no parameter web\n", node.node);
1955 			*out_web = new BParameterWeb();
1956 			delete_area(area);
1957 			return B_OK;
1958 		}
1959 		if (reply.size > 0) {
1960 			// we got a flattened parameter web!
1961 			*out_web = new BParameterWeb();
1962 
1963 			printf("BMediaRoster::GetParameterWebFor Unflattening %ld bytes, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
1964 				reply.size, ((uint32*)data)[0], ((uint32*)data)[1], ((uint32*)data)[2], ((uint32*)data)[3]);
1965 
1966 			rv = (*out_web)->Unflatten(reply.code, data, reply.size);
1967 			if (rv != B_OK) {
1968 				ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, %s\n", strerror(rv));
1969 				delete_area(area);
1970 				delete *out_web;
1971 				return B_ERROR;
1972 			}
1973 			delete_area(area);
1974 			return B_OK;
1975 		}
1976 		delete_area(area);
1977 		ASSERT(reply.size == -1);
1978 		// parameter web data was too large
1979 		// loop and try a larger size
1980 	}
1981 	ERROR("BMediaRoster::GetParameterWebFor node %ld has no parameter web larger than %ld\n", node.node, size);
1982 	return B_ERROR;
1983 }
1984 
1985 
1986 status_t
1987 BMediaRoster::StartControlPanel(const media_node & node,
1988 								BMessenger * out_messenger)
1989 {
1990 	UNIMPLEMENTED();
1991 	return B_ERROR;
1992 }
1993 
1994 
1995 status_t
1996 BMediaRoster::GetDormantNodes(dormant_node_info * out_info,
1997 							  int32 * io_count,
1998 							  const media_format * has_input /* = NULL */,
1999 							  const media_format * has_output /* = NULL */,
2000 							  const char * name /* = NULL */,
2001 							  uint64 require_kinds /* = NULL */,
2002 							  uint64 deny_kinds /* = NULL */)
2003 {
2004 	CALLED();
2005 	if (out_info == NULL)
2006 		return B_BAD_VALUE;
2007 	if (io_count == NULL)
2008 		return B_BAD_VALUE;
2009 	if (*io_count <= 0)
2010 		return B_BAD_VALUE;
2011 
2012 	xfer_server_get_dormant_nodes msg;
2013 	port_id port;
2014 	status_t rv;
2015 
2016 	port = find_port(MEDIA_SERVER_PORT_NAME);
2017 	if (port <= B_OK)
2018 		return B_ERROR;
2019 
2020 	msg.maxcount = *io_count;
2021 	msg.has_input = (bool) has_input;
2022 	if (has_input)
2023 		msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format
2024 	msg.has_output = (bool) has_output;
2025 	if (has_output)
2026 		msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format
2027 	msg.has_name = (bool) name;
2028 	if (name) {
2029 		int len = strlen(name);
2030 		len = min_c(len, (int)sizeof(msg.name) - 1);
2031 		memcpy(msg.name, name, len);
2032 		msg.name[len] = 0;
2033 	}
2034 	msg.require_kinds = require_kinds;
2035 	msg.deny_kinds = deny_kinds;
2036 	msg.reply_port = _PortPool->GetPort();
2037 
2038 	rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg));
2039 	if (rv != B_OK) {
2040 		_PortPool->PutPort(msg.reply_port);
2041 		return rv;
2042 	}
2043 
2044 	xfer_server_get_dormant_nodes_reply reply;
2045 	int32 code;
2046 
2047 	rv = read_port(msg.reply_port, &code, &reply, sizeof(reply));
2048 	if (rv < B_OK) {
2049 		_PortPool->PutPort(msg.reply_port);
2050 		return rv;
2051 	}
2052 
2053 	*io_count = reply.count;
2054 
2055 	if (*io_count > 0) {
2056 		rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info));
2057 		if (rv < B_OK)
2058 			reply.result = rv;
2059 	}
2060 	_PortPool->PutPort(msg.reply_port);
2061 
2062 	return reply.result;
2063 }
2064 
2065 /* This function is used to do the real work of instantiating a dormant node. It is either
2066  * called by the media_addon_server to instantiate a global node, or it gets called from
2067  * BMediaRoster::InstantiateDormantNode() to create a local one.
2068  *
2069  * Checks concerning global/local are not done here.
2070  */
2071 status_t
2072 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonid, int32 flavorid, team_id creator, media_node *out_node)
2073 {
2074 	// This function is always called from the correct context, if the node
2075 	// is supposed to be global, it is called from the media_addon_server.
2076 
2077 	// if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
2078 	// resides in the media_addon_server
2079 
2080 	// RegisterNode() must be called for nodes instantiated from add-ons,
2081 	// since the media kit warrants that it's done automatically.
2082 
2083 	// addonid		Indicates the ID number of the media add-on in which the node resides.
2084 	// flavorid		Indicates the internal ID number that the add-on uses to identify the flavor,
2085 	//				this is the number that was published by BMediaAddOn::GetFlavorAt() in the
2086 	//				flavor_info::internal_id field.
2087 	// creator		The creator team is -1 if nodes are created locally. If created globally,
2088 	//				it will contain (while called in media_addon_server context) the team-id of
2089 	// 				the team that requested the instantiation.
2090 
2091 	TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %ld, flavor_id %ld\n", addonid, flavorid);
2092 
2093 	// Get flavor_info from the server
2094 	dormant_flavor_info node_info;
2095 	status_t rv;
2096 	rv = GetDormantFlavorInfo(addonid, flavorid, &node_info);
2097 	if (rv != B_OK) {
2098 		ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get dormant_flavor_info for addon-id %ld, flavor-id %ld\n", addonid, flavorid);
2099 		return B_ERROR;
2100 	}
2101 
2102 	//ASSERT(node_info.internal_id == flavorid);
2103 	if (node_info.internal_id != flavorid) {
2104 		ERROR("############# BMediaRosterEx::InstantiateDormantNode failed: ID mismatch for addon-id %ld, flavor-id %ld, node_info.internal_id %ld, node_info.name %s\n", addonid, flavorid, node_info.internal_id, node_info.name);
2105 		return B_ERROR;
2106 	}
2107 
2108 	// load the BMediaAddOn object
2109 	BMediaAddOn *addon;
2110 	addon = _DormantNodeManager->GetAddon(addonid);
2111 	if (!addon) {
2112 		ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n");
2113 		return B_ERROR;
2114 	}
2115 
2116 	// Now we need to try to increment the use count of this addon flavor
2117 	// in the server. This can fail if the total number instances of this
2118 	// flavor is limited.
2119 	rv = IncrementAddonFlavorInstancesCount(addonid, flavorid);
2120 	if (rv != B_OK) {
2121 		ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create more nodes for addon-id %ld, flavor-id %ld\n", addonid, flavorid);
2122 		// Put the addon back into the pool
2123 		_DormantNodeManager->PutAddon(addonid);
2124 		return B_ERROR;
2125 	}
2126 
2127 	BMessage config;
2128 	rv = LoadNodeConfiguration(addonid, flavorid, &config);
2129 	if (rv != B_OK) {
2130 		ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load configuration for addon-id %ld, flavor-id %ld\n", addonid, flavorid);
2131 		// do not return, this is a minor problem, not a reason to fail
2132 	}
2133 
2134 	BMediaNode *node;
2135 	status_t out_error;
2136 
2137 	out_error = B_OK;
2138 	node = addon->InstantiateNodeFor(&node_info, &config, &out_error);
2139 	if (!node) {
2140 		ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor failed\n");
2141 		// Put the addon back into the pool
2142 		_DormantNodeManager->PutAddon(addonid);
2143 		// We must decrement the use count of this addon flavor in the
2144 		// server to compensate the increment done in the beginning.
2145 		rv = DecrementAddonFlavorInstancesCount(addonid, flavorid);
2146 		if (rv != B_OK) {
2147 			ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddonFlavorInstancesCount failed\n");
2148 		}
2149 		return (out_error != B_OK) ? out_error : B_ERROR;
2150 	}
2151 
2152 	rv = RegisterNode(node, addonid, flavorid);
2153 	if (rv != B_OK) {
2154 		ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
2155 		delete node;
2156 		// Put the addon back into the pool
2157 		_DormantNodeManager->PutAddon(addonid);
2158 		// We must decrement the use count of this addon flavor in the
2159 		// server to compensate the increment done in the beginning.
2160 		rv = DecrementAddonFlavorInstancesCount(addonid, flavorid);
2161 		if (rv != B_OK) {
2162 			ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddonFlavorInstancesCount failed\n");
2163 		}
2164 		return B_ERROR;
2165 	}
2166 
2167 	if (creator != -1) {
2168 		// send a message to the server to assign team "creator" as creator of node "node->ID()"
2169 		printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %ld as creator of node %ld\n", creator, node->ID());
2170 		rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator);
2171 		if (rv != B_OK) {
2172 			ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign team %ld as creator of node %ld\n", creator, node->ID());
2173 			// do not return, this is a minor problem, not a reason to fail
2174 		}
2175 	}
2176 
2177 	// RegisterNode() does remember the add-on id in the server
2178 	// and UnregisterNode() will call DormantNodeManager::PutAddon()
2179 	// when the node is unregistered.
2180 
2181 	*out_node = node->Node();
2182 
2183 	TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %ld, flavor_id %ld instanciated as node %ld, port %ld in team %ld\n", addonid, flavorid, out_node->node, out_node->port, team);
2184 
2185 	return B_OK;
2186 }
2187 
2188 
2189 status_t
2190 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
2191 									 media_node * out_node,
2192 									 uint32 flags /* currently 0 or B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ )
2193 {
2194 	CALLED();
2195 	if (out_node == 0)
2196 		return B_BAD_VALUE;
2197 	if (in_info.addon <= 0) {
2198 		ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %ld invalid.\n", in_info.addon);
2199 		return B_BAD_VALUE;
2200 	}
2201 
2202 	printf("BMediaRoster::InstantiateDormantNode: addon-id %ld, flavor_id %ld, flags 0x%lX\n", in_info.addon, in_info.flavor_id, flags);
2203 
2204 	// Get flavor_info from the server
2205 	// XXX this is a little overhead, as we get the full blown dormant_flavor_info,
2206 	// XXX but only need the flags.
2207 	dormant_flavor_info node_info;
2208 	status_t rv;
2209 	rv = MediaRosterEx(this)->GetDormantFlavorInfo(in_info.addon, in_info.flavor_id, &node_info);
2210 	if (rv != B_OK) {
2211 		ERROR("BMediaRoster::InstantiateDormantNode: failed to get dormant_flavor_info for addon-id %ld, flavor-id %ld\n", in_info.addon, in_info.flavor_id);
2212 		return B_NAME_NOT_FOUND;
2213 	}
2214 
2215 	ASSERT(node_info.internal_id == in_info.flavor_id);
2216 
2217 	printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", flavor_flags 0x%lX, internal_id %ld, possible_count %ld\n",
2218 		node_info.name, node_info.info, node_info.flavor_flags, node_info.internal_id, node_info.possible_count);
2219 
2220 	#if DEBUG
2221 		if (flags & B_FLAVOR_IS_LOCAL)
2222 			printf("BMediaRoster::InstantiateDormantNode: caller requested B_FLAVOR_IS_LOCAL\n");
2223 		if (flags & B_FLAVOR_IS_GLOBAL)
2224 			printf("BMediaRoster::InstantiateDormantNode: caller requested B_FLAVOR_IS_GLOBAL\n");
2225 		if (node_info.flavor_flags & B_FLAVOR_IS_LOCAL)
2226 			printf("BMediaRoster::InstantiateDormantNode: node requires B_FLAVOR_IS_LOCAL\n");
2227 		if (node_info.flavor_flags & B_FLAVOR_IS_GLOBAL)
2228 			printf("BMediaRoster::InstantiateDormantNode: node requires B_FLAVOR_IS_GLOBAL\n");
2229 	#endif
2230 
2231 	// Make sure that flags demanded by the dormant node and those requested
2232 	// by the caller are not incompatible.
2233 	if ((node_info.flavor_flags & B_FLAVOR_IS_GLOBAL) && (flags & B_FLAVOR_IS_LOCAL)) {
2234 		ERROR("BMediaRoster::InstantiateDormantNode: requested B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n");
2235 		return B_NAME_NOT_FOUND;
2236 	}
2237 	if ((node_info.flavor_flags & B_FLAVOR_IS_LOCAL) && (flags & B_FLAVOR_IS_GLOBAL)) {
2238 		ERROR("BMediaRoster::InstantiateDormantNode: requested B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
2239 		return B_NAME_NOT_FOUND;
2240 	}
2241 
2242 	// If either the node, or the caller requested to make the instance global
2243 	// we will do it by forwarding this request into the media_addon_server, which
2244 	// in turn will call BMediaRosterEx::InstantiateDormantNode to create the node
2245 	// there and make it globally available.
2246 	if ((node_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) {
2247 
2248 		printf("BMediaRoster::InstantiateDormantNode: creating global object in media_addon_server\n");
2249 
2250 		addonserver_instantiate_dormant_node_request request;
2251 		addonserver_instantiate_dormant_node_reply reply;
2252 		request.addonid = in_info.addon;
2253 		request.flavorid = in_info.flavor_id;
2254 		request.creator_team = team; // creator team is allowed to also release global nodes
2255 		rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply));
2256 		if (rv == B_OK) {
2257 			*out_node = reply.node;
2258 		}
2259 
2260 	} else {
2261 
2262 		// creator team = -1, as this is a local node
2263 		rv = MediaRosterEx(this)->InstantiateDormantNode(in_info.addon, in_info.flavor_id, -1, out_node);
2264 
2265 	}
2266 	if (rv != B_OK) {
2267 		*out_node = media_node::null;
2268 		return B_NAME_NOT_FOUND;
2269 	}
2270 	return B_OK;
2271 }
2272 
2273 
2274 status_t
2275 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
2276 									 media_node * out_node)
2277 {
2278 	return InstantiateDormantNode(in_info, out_node, 0);
2279 }
2280 
2281 
2282 status_t
2283 BMediaRoster::GetDormantNodeFor(const media_node & node,
2284 								dormant_node_info * out_info)
2285 {
2286 	CALLED();
2287 	if (out_info == NULL)
2288 		return B_BAD_VALUE;
2289 	if (IS_INVALID_NODE(node))
2290 		return B_MEDIA_BAD_NODE;
2291 
2292 	server_get_dormant_node_for_request request;
2293 	server_get_dormant_node_for_reply reply;
2294 	status_t rv;
2295 
2296 	request.node = node;
2297 
2298 	rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply));
2299 	if (rv != B_OK)
2300 		return rv;
2301 
2302 	*out_info = reply.node_info;
2303 	return B_OK;
2304 }
2305 
2306 status_t
2307 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonid,
2308 									  int32 flavorid,
2309 									  dormant_flavor_info * out_flavor)
2310 {
2311 	CALLED();
2312 	if (out_flavor == NULL)
2313 		return B_BAD_VALUE;
2314 
2315 	xfer_server_get_dormant_flavor_info msg;
2316 	xfer_server_get_dormant_flavor_info_reply *reply;
2317 	port_id port;
2318 	status_t rv;
2319 	int32 code;
2320 
2321 	port = find_port(MEDIA_SERVER_PORT_NAME);
2322 	if (port <= B_OK)
2323 		return B_ERROR;
2324 
2325 	reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000);
2326 	if (reply == 0)
2327 		return B_ERROR;
2328 
2329 	msg.addon 		= addonid;
2330 	msg.flavor_id 	= flavorid;
2331 	msg.reply_port 	= _PortPool->GetPort();
2332 	rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg));
2333 	if (rv != B_OK) {
2334 		free(reply);
2335 		_PortPool->PutPort(msg.reply_port);
2336 		return rv;
2337 	}
2338 	rv = read_port(msg.reply_port, &code, reply, 16000);
2339 	_PortPool->PutPort(msg.reply_port);
2340 
2341 	if (rv < B_OK) {
2342 		free(reply);
2343 		return rv;
2344 	}
2345 
2346 	if (reply->result == B_OK)
2347 		rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size);
2348 	else
2349 		rv = reply->result;
2350 
2351 	free(reply);
2352 	return rv;
2353 }
2354 
2355 status_t
2356 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant,
2357 									  dormant_flavor_info * out_flavor)
2358 {
2359 	return MediaRosterEx(this)->GetDormantFlavorInfo(in_dormant.addon, in_dormant.flavor_id, out_flavor);
2360 }
2361 
2362 // Reports in outLatency the maximum latency found downstream from
2363 // the specified BBufferProducer, producer, given the current connections.
2364 status_t
2365 BMediaRoster::GetLatencyFor(const media_node & producer,
2366 							bigtime_t * out_latency)
2367 {
2368 	CALLED();
2369 	if (out_latency == NULL)
2370 		return B_BAD_VALUE;
2371 	if (IS_INVALID_NODE(producer))
2372 		return B_MEDIA_BAD_NODE;
2373 	if ((producer.kind & B_BUFFER_PRODUCER) == 0)
2374 		return B_MEDIA_BAD_NODE;
2375 
2376 	producer_get_latency_request request;
2377 	producer_get_latency_reply reply;
2378 	status_t rv;
2379 
2380 	rv = QueryPort(producer.port, PRODUCER_GET_LATENCY, &request, sizeof(request), &reply, sizeof(reply));
2381 	if (rv != B_OK)
2382 		return rv;
2383 
2384 	*out_latency = reply.latency;
2385 
2386 	printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2387 	return B_OK;
2388 }
2389 
2390 
2391 status_t
2392 BMediaRoster::GetInitialLatencyFor(const media_node & producer,
2393 								   bigtime_t * out_latency,
2394 								   uint32 * out_flags /* = NULL */)
2395 {
2396 	CALLED();
2397 	if (out_latency == NULL)
2398 		return B_BAD_VALUE;
2399 	if (IS_INVALID_NODE(producer))
2400 		return B_MEDIA_BAD_NODE;
2401 	if ((producer.kind & B_BUFFER_PRODUCER) == 0)
2402 		return B_MEDIA_BAD_NODE;
2403 
2404 	producer_get_initial_latency_request request;
2405 	producer_get_initial_latency_reply reply;
2406 	status_t rv;
2407 
2408 	rv = QueryPort(producer.port, PRODUCER_GET_INITIAL_LATENCY, &request, sizeof(request), &reply, sizeof(reply));
2409 	if (rv != B_OK)
2410 		return rv;
2411 
2412 	*out_latency = reply.initial_latency;
2413 	if (out_flags)
2414 		*out_flags = reply.flags;
2415 
2416 	printf("BMediaRoster::GetInitialLatencyFor producer %ld has maximum initial latency %Ld\n", producer.node, *out_latency);
2417 	return B_OK;
2418 }
2419 
2420 
2421 status_t
2422 BMediaRoster::GetStartLatencyFor(const media_node & time_source,
2423 								 bigtime_t * out_latency)
2424 {
2425 	CALLED();
2426 	if (out_latency == NULL)
2427 		return B_BAD_VALUE;
2428 	if (IS_INVALID_NODE(time_source))
2429 		return B_MEDIA_BAD_NODE;
2430 	if ((time_source.kind & B_TIME_SOURCE) == 0)
2431 		return B_MEDIA_BAD_NODE;
2432 
2433 	timesource_get_start_latency_request request;
2434 	timesource_get_start_latency_reply reply;
2435 	status_t rv;
2436 
2437 	rv = QueryPort(time_source.port, TIMESOURCE_GET_START_LATENCY, &request, sizeof(request), &reply, sizeof(reply));
2438 	if (rv != B_OK)
2439 		return rv;
2440 
2441 	*out_latency = reply.start_latency;
2442 
2443 	printf("BMediaRoster::GetStartLatencyFor timesource %ld has maximum initial latency %Ld\n", time_source.node, *out_latency);
2444 	return B_OK;
2445 }
2446 
2447 
2448 status_t
2449 BMediaRoster::GetFileFormatsFor(const media_node & file_interface,
2450 								media_file_format * out_formats,
2451 								int32 * io_num_infos)
2452 {
2453 	UNIMPLEMENTED();
2454 	return B_ERROR;
2455 }
2456 
2457 
2458 status_t
2459 BMediaRoster::SetRefFor(const media_node & file_interface,
2460 						const entry_ref & file,
2461 						bool create_and_truncate,
2462 						bigtime_t * out_length)	/* if create is false */
2463 {
2464 	UNIMPLEMENTED();
2465 	return B_ERROR;
2466 }
2467 
2468 
2469 status_t
2470 BMediaRoster::GetRefFor(const media_node & node,
2471 						entry_ref * out_file,
2472 						BMimeType * mime_type)
2473 {
2474 	UNIMPLEMENTED();
2475 	return B_ERROR;
2476 }
2477 
2478 
2479 status_t
2480 BMediaRoster::SniffRefFor(const media_node & file_interface,
2481 						  const entry_ref & file,
2482 						  BMimeType * mime_type,
2483 						  float * out_capability)
2484 {
2485 	UNIMPLEMENTED();
2486 	return B_ERROR;
2487 }
2488 
2489 
2490 /* This is the generic "here's a file, now can someone please play it" interface */
2491 status_t
2492 BMediaRoster::SniffRef(const entry_ref & file,
2493 					   uint64 require_node_kinds,		/* if you need an EntityInterface or BufferConsumer or something */
2494 					   dormant_node_info * out_node,
2495 					   BMimeType * mime_type)
2496 {
2497 	UNIMPLEMENTED();
2498 	return B_ERROR;
2499 }
2500 
2501 
2502 status_t
2503 BMediaRoster::GetDormantNodeForType(const BMimeType & type,
2504 									uint64 require_node_kinds,
2505 									dormant_node_info * out_node)
2506 {
2507 	UNIMPLEMENTED();
2508 	return B_ERROR;
2509 }
2510 
2511 
2512 status_t
2513 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node,
2514 									media_file_format * out_read_formats,
2515 									int32 in_read_count,
2516 									int32 * out_read_count)
2517 {
2518 	UNIMPLEMENTED();
2519 	return B_ERROR;
2520 }
2521 
2522 
2523 status_t
2524 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node,
2525 									 media_file_format * out_write_formats,
2526 									 int32 in_write_count,
2527 									 int32 * out_write_count)
2528 {
2529 	UNIMPLEMENTED();
2530 	return B_ERROR;
2531 }
2532 
2533 
2534 status_t
2535 BMediaRoster::GetFormatFor(const media_output & output,
2536 						   media_format * io_format,
2537 						   uint32 flags)
2538 {
2539 	CALLED();
2540 	if (io_format == NULL)
2541 		return B_BAD_VALUE;
2542 	if ((output.node.kind & B_BUFFER_PRODUCER) == 0)
2543 		return B_MEDIA_BAD_NODE;
2544 	if (IS_INVALID_SOURCE(output.source))
2545 		return B_MEDIA_BAD_SOURCE;
2546 
2547 	producer_format_suggestion_requested_request request;
2548 	producer_format_suggestion_requested_reply reply;
2549 	status_t rv;
2550 
2551 	request.type = B_MEDIA_UNKNOWN_TYPE;
2552 	request.quality = 0; // XXX what should this be?
2553 
2554 	rv = QueryPort(output.source.port, PRODUCER_FORMAT_SUGGESTION_REQUESTED, &request, sizeof(request), &reply, sizeof(reply));
2555 	if (rv != B_OK)
2556 		return rv;
2557 
2558 	*io_format = reply.format;
2559 	return B_OK;
2560 }
2561 
2562 
2563 status_t
2564 BMediaRoster::GetFormatFor(const media_input & input,
2565 						   media_format * io_format,
2566 						   uint32 flags)
2567 {
2568 	CALLED();
2569 	if (io_format == NULL)
2570 		return B_BAD_VALUE;
2571 	if ((input.node.kind & B_BUFFER_CONSUMER) == 0)
2572 		return B_MEDIA_BAD_NODE;
2573 	if (IS_INVALID_DESTINATION(input.destination))
2574 		return B_MEDIA_BAD_DESTINATION;
2575 
2576 	consumer_accept_format_request request;
2577 	consumer_accept_format_reply reply;
2578 	status_t rv;
2579 
2580 	request.dest = input.destination;
2581 	memset(&request.format, 0, sizeof(request.format)); // wildcard
2582 
2583 	rv = QueryPort(input.destination.port, CONSUMER_ACCEPT_FORMAT, &request, sizeof(request), &reply, sizeof(reply));
2584 	if (rv != B_OK)
2585 		return rv;
2586 
2587 	*io_format = reply.format;
2588 	return B_OK;
2589 }
2590 
2591 
2592 status_t
2593 BMediaRoster::GetFormatFor(const media_node & node,
2594 						   media_format * io_format,
2595 						   float quality)
2596 {
2597 	UNIMPLEMENTED();
2598 	if (io_format == NULL)
2599 		return B_BAD_VALUE;
2600 	if (IS_INVALID_NODE(node))
2601 		return B_MEDIA_BAD_NODE;
2602 	if ((node.kind & (B_BUFFER_CONSUMER | B_BUFFER_PRODUCER)) == 0)
2603 		return B_MEDIA_BAD_NODE;
2604 
2605 
2606 	return B_ERROR;
2607 }
2608 
2609 
2610 ssize_t
2611 BMediaRoster::GetNodeAttributesFor(const media_node & node,
2612 								   media_node_attribute * outArray,
2613 								   size_t inMaxCount)
2614 {
2615 	UNIMPLEMENTED();
2616 	return B_ERROR;
2617 }
2618 
2619 
2620 media_node_id
2621 BMediaRoster::NodeIDFor(port_id source_or_destination_port)
2622 {
2623 	CALLED();
2624 
2625 	server_node_id_for_request request;
2626 	server_node_id_for_reply reply;
2627 	status_t rv;
2628 
2629 	request.port = source_or_destination_port;
2630 
2631 	rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, sizeof(reply));
2632 	if (rv != B_OK) {
2633 		ERROR("BMediaRoster::NodeIDFor: failed (error %#lx)\n", rv);
2634 		return -1;
2635 	}
2636 
2637 	return reply.nodeid;
2638 }
2639 
2640 
2641 status_t
2642 BMediaRoster::GetInstancesFor(media_addon_id addon,
2643 							  int32 flavor,
2644 							  media_node_id * out_id,
2645 							  int32 * io_count)
2646 {
2647 	CALLED();
2648 	if (out_id == NULL)
2649 		return B_BAD_VALUE;
2650 	if (io_count && *io_count <= 0)
2651 		return B_BAD_VALUE;
2652 
2653 	server_get_instances_for_request request;
2654 	server_get_instances_for_reply reply;
2655 	status_t rv;
2656 
2657 	request.maxcount = (io_count ? *io_count : 1);
2658 	request.addon_id = addon;
2659 	request.addon_flavor_id = flavor;
2660 
2661 	rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), &reply, sizeof(reply));
2662 	if (rv != B_OK) {
2663 		ERROR("BMediaRoster::GetLiveNodes failed\n");
2664 		return rv;
2665 	}
2666 
2667 	if(io_count)
2668 		*io_count = reply.count;
2669 	if (reply.count > 0)
2670 		memcpy(out_id, reply.node_id, sizeof(media_node_id) * reply.count);
2671 
2672 	return B_OK;
2673 }
2674 
2675 
2676 status_t
2677 BMediaRoster::SetRealtimeFlags(uint32 in_enabled)
2678 {
2679 	UNIMPLEMENTED();
2680 	return B_ERROR;
2681 }
2682 
2683 
2684 status_t
2685 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled)
2686 {
2687 	UNIMPLEMENTED();
2688 	return B_ERROR;
2689 }
2690 
2691 
2692 ssize_t
2693 BMediaRoster::AudioBufferSizeFor(int32 channel_count,
2694 								 uint32 sample_format,
2695 								 float frame_rate,
2696 								 bus_type bus_kind)
2697 {
2698 	bigtime_t buffer_duration;
2699 	ssize_t buffer_size;
2700 
2701 	system_info info;
2702 	get_system_info(&info);
2703 
2704 	if (info.cpu_clock_speed > 2000000000)
2705 		buffer_duration = 2500;
2706 	else if (info.cpu_clock_speed > 1000000000)
2707 		buffer_duration = 5000;
2708 	else if (info.cpu_clock_speed > 600000000)
2709 		buffer_duration = 10000;
2710 	else if (info.cpu_clock_speed > 200000000)
2711 		buffer_duration = 20000;
2712 	else if (info.cpu_clock_speed > 100000000)
2713 		buffer_duration = 30000;
2714 	else
2715 		buffer_duration = 50000;
2716 
2717 	if ((bus_kind == B_ISA_BUS || bus_kind == B_PCMCIA_BUS) && buffer_duration < 25000)
2718 		buffer_duration = 25000;
2719 
2720 	buffer_size = (sample_format & 0xf) * channel_count * (ssize_t)((frame_rate * buffer_duration) / 1000000.0);
2721 
2722 	printf("Suggested buffer duration %Ld, size %ld\n", buffer_duration, buffer_size);
2723 
2724 	return buffer_size;
2725 }
2726 
2727 
2728 /* Use MediaFlags to inquire about specific features of the Media Kit. */
2729 /* Returns < 0 for "not present", positive size for output data size. */
2730 /* 0 means that the capability is present, but no data about it. */
2731 /* static */ ssize_t
2732 BMediaRoster::MediaFlags(media_flags cap,
2733 						 void * buf,
2734 						 size_t maxSize)
2735 {
2736 	UNIMPLEMENTED();
2737 	return 0;
2738 }
2739 
2740 
2741 /* BLooper overrides */
2742 /* virtual */ void
2743 BMediaRoster::MessageReceived(BMessage * message)
2744 {
2745 	switch (message->what) {
2746 		case 'PING':
2747 		{
2748 			// media_server plays ping-pong with the BMediaRosters
2749 			// to detect dead teams. Normal communication uses ports.
2750 			static BMessage pong('PONG');
2751 			message->SendReply(&pong, static_cast<BHandler *>(NULL), 2000000);
2752 			return;
2753 		}
2754 
2755 		case NODE_FINAL_RELEASE:
2756 		{
2757 			// this function is called by a BMediaNode to delete
2758 			// itself, as this needs to be done from another thread
2759 			// context, it is done here.
2760 			// XXX If a node is released using BMediaRoster::ReleaseNode()
2761 			// XXX instead of using BMediaNode::Release() / BMediaNode::Acquire()
2762 			// XXX fRefCount of the BMediaNode will not be correct.
2763 
2764 			BMediaNode *node;
2765 			message->FindPointer("node", reinterpret_cast<void **>(&node));
2766 
2767 			TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE saving node %ld configuration\n", node->ID());
2768 			MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(node);
2769 
2770 			TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing node %ld\n", node->ID());
2771 			node->DeleteHook(node); // we don't call Release(), see above!
2772 			return;
2773 		}
2774 	}
2775 	printf("BMediaRoster::MessageReceived: unknown message!\n");
2776 	message->PrintToStream();
2777 }
2778 
2779 /* virtual */ bool
2780 BMediaRoster::QuitRequested()
2781 {
2782 	UNIMPLEMENTED();
2783 	return true;
2784 }
2785 
2786 /* virtual */ BHandler *
2787 BMediaRoster::ResolveSpecifier(BMessage *msg,
2788 				 int32 index,
2789 				 BMessage *specifier,
2790 				 int32 form,
2791 				 const char *property)
2792 {
2793 	UNIMPLEMENTED();
2794 	return 0;
2795 }
2796 
2797 
2798 /* virtual */ status_t
2799 BMediaRoster::GetSupportedSuites(BMessage *data)
2800 {
2801 	UNIMPLEMENTED();
2802 	return B_ERROR;
2803 }
2804 
2805 
2806 BMediaRoster::~BMediaRoster()
2807 {
2808 	CALLED();
2809 
2810 	// unregister this application with the media server
2811 	server_unregister_app_request request;
2812 	server_unregister_app_reply reply;
2813 	request.team = team;
2814 	QueryServer(SERVER_UNREGISTER_APP, &request, sizeof(request), &reply, sizeof(reply));
2815 }
2816 
2817 
2818 /*************************************************************
2819  * private BMediaRoster
2820  *************************************************************/
2821 
2822 // deprecated call
2823 status_t
2824 BMediaRoster::SetOutputBuffersFor(const media_source & output,
2825 								  BBufferGroup * group,
2826 								  bool will_reclaim )
2827 {
2828 	UNIMPLEMENTED();
2829 	debugger("BMediaRoster::SetOutputBuffersFor missing\n");
2830 	return B_ERROR;
2831 }
2832 
2833 
2834 /* FBC stuffing (Mmmh, Stuffing!) */
2835 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; }
2836 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; }
2837 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; }
2838 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; }
2839 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; }
2840 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; }
2841 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; }
2842 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; }
2843 
2844 
2845 BMediaRoster::BMediaRoster() :
2846 	BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY, B_LOOPER_PORT_DEFAULT_CAPACITY)
2847 {
2848 	CALLED();
2849 
2850 	// start the looper
2851 	Run();
2852 
2853 	// register this application with the media server
2854 	server_register_app_request request;
2855 	server_register_app_reply reply;
2856 	request.team = team;
2857 	request.messenger = BMessenger(NULL, this);
2858 	QueryServer(SERVER_REGISTER_APP, &request, sizeof(request), &reply, sizeof(reply));
2859 }
2860 
2861 
2862 /* static */ status_t
2863 BMediaRoster::ParseCommand(BMessage & reply)
2864 {
2865 	UNIMPLEMENTED();
2866 	return B_ERROR;
2867 }
2868 
2869 
2870 status_t
2871 BMediaRoster::GetDefaultInfo(media_node_id for_default,
2872 							 BMessage & out_config)
2873 {
2874 	UNIMPLEMENTED();
2875 	return B_ERROR;
2876 }
2877 
2878 
2879 
2880 status_t
2881 BMediaRoster::SetRunningDefault(media_node_id for_default,
2882 								const media_node & node)
2883 {
2884 	UNIMPLEMENTED();
2885 	return B_ERROR;
2886 }
2887 
2888 
2889 /*************************************************************
2890  * static BMediaRoster variables
2891  *************************************************************/
2892 
2893 bool BMediaRoster::_isMediaServer;
2894 port_id BMediaRoster::_mReplyPort;
2895 int32 BMediaRoster::_mReplyPortRes;
2896 int32 BMediaRoster::_mReplyPortUnavailCount;
2897 BMediaRoster * BMediaRoster::_sDefault = NULL;
2898 
2899