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