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