xref: /haiku/src/kits/media/MediaRoster.cpp (revision 04a0e9c7b68cbe3a43d38e2bca8e860fd80936fb)
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 			BParameterWeb* 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 				if (rv != B_OK) {
2277 					ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, "
2278 						"%s\n", strerror(rv));
2279 					delete web;
2280 				} else
2281 					*_web = web;
2282 			}
2283 
2284 			delete_area(area);
2285 			return rv;
2286 		}
2287 		delete_area(area);
2288 		ASSERT(reply.size == -1);
2289 		// parameter web data was too large
2290 		// loop and try a larger size
2291 	}
2292 	ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32 " has no "
2293 		"parameter web larger than %" B_PRId32 "\n", node.node, size);
2294 	return B_ERROR;
2295 }
2296 
2297 
2298 status_t
2299 BMediaRoster::StartControlPanel(const media_node& node, BMessenger* _messenger)
2300 {
2301 	CALLED();
2302 
2303 	controllable_start_control_panel_request request;
2304 	controllable_start_control_panel_reply reply;
2305 
2306 	request.node = node;
2307 
2308 	status_t rv;
2309 	rv = QueryPort(node.port, CONTROLLABLE_START_CONTROL_PANEL, &request,
2310 		sizeof(request), &reply, sizeof(reply));
2311 	if (rv != B_OK)
2312 		return rv;
2313 
2314 	if (reply.team != -1 && _messenger != NULL)
2315 		*_messenger = BMessenger(NULL, reply.team);
2316 
2317 	return B_OK;
2318 }
2319 
2320 
2321 status_t
2322 BMediaRoster::GetDormantNodes(dormant_node_info* _info, int32* _count,
2323 	const media_format* hasInput, const media_format* hasOutput,
2324 	const char* name, uint64 requireKinds, uint64 denyKinds)
2325 {
2326 	CALLED();
2327 	if (_info == NULL || _count == NULL || *_count <= 0)
2328 		return B_BAD_VALUE;
2329 
2330 	server_get_dormant_nodes_request request;
2331 	request.max_count = *_count;
2332 	request.has_input = hasInput != NULL;
2333 	if (hasInput != NULL) {
2334 		// TODO: we should not make a flat copy of media_format
2335 		request.input_format = *hasInput;
2336 	}
2337 	request.has_output = hasOutput != NULL;
2338 	if (hasOutput != NULL) {
2339 		// TODO: we should not make a flat copy of media_format
2340 		request.output_format = *hasOutput;
2341 	}
2342 
2343 	request.has_name = name != NULL;
2344 	if (name != NULL)
2345 		strlcpy(request.name, name, sizeof(request.name));
2346 
2347 	request.require_kinds = requireKinds;
2348 	request.deny_kinds = denyKinds;
2349 
2350 	server_get_dormant_nodes_reply reply;
2351 	status_t status = QueryServer(SERVER_GET_DORMANT_NODES, &request,
2352 		sizeof(request), &reply, sizeof(reply));
2353 	if (status != B_OK)
2354 		return status;
2355 
2356 	*_count = reply.count;
2357 
2358 	if (reply.count > 0) {
2359 		int32 code;
2360 		status = read_port(request.reply_port, &code, _info,
2361 			reply.count * sizeof(dormant_node_info));
2362 		if (status < B_OK)
2363 			reply.result = status;
2364 	}
2365 
2366 	return reply.result;
2367 }
2368 
2369 
2370 /*!	This function is used to do the real work of instantiating a dormant node.
2371 	It is either called by the media_addon_server to instantiate a global node,
2372 	or it gets called from BMediaRoster::InstantiateDormantNode() to create a
2373 	local one.
2374 
2375 	Checks concerning global/local are not done here.
2376 */
2377 status_t
2378 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonID, int32 flavorID,
2379 	team_id creator, media_node *_node)
2380 {
2381 	// This function is always called from the correct context, if the node
2382 	// is supposed to be global, it is called from the media_addon_server.
2383 
2384 	// if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
2385 	// resides in the media_addon_server
2386 
2387 	// RegisterNode() must be called for nodes instantiated from add-ons,
2388 	// since the media kit warrants that it's done automatically.
2389 
2390 	// addonID		Indicates the ID number of the media add-on in which the
2391 	//				node resides.
2392 	// flavorID		Indicates the internal ID number that the add-on uses to
2393 	//				identify the flavor, this is the number that was published
2394 	//				by BMediaAddOn::GetFlavorAt() in the
2395 	//				flavor_info::internal_id field.
2396 	// creator		The creator team is -1 if nodes are created locally. If
2397 	//				created globally, it will contain (while called in
2398 	//				media_addon_server context) the team-id of the team that
2399 	//				requested the instantiation.
2400 
2401 	TRACE("BMediaRosterEx::InstantiateDormantNode: addonID %" B_PRId32
2402 		", flavorID %" B_PRId32 "\n", addonID, flavorID);
2403 
2404 	// Get flavor_info from the server
2405 	dormant_flavor_info info;
2406 	status_t rv;
2407 	rv = GetDormantFlavorInfo(addonID, flavorID, &info);
2408 	if (rv != B_OK) {
2409 		ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get "
2410 			"dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2411 			B_PRId32 "\n", addonID, flavorID);
2412 		return B_ERROR;
2413 	}
2414 
2415 	ASSERT(info.internal_id == flavorID);
2416 
2417 	// load the BMediaAddOn object
2418 	BMediaAddOn* addon = gDormantNodeManager->GetAddOn(addonID);
2419 	if (addon == NULL) {
2420 		ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n");
2421 		return B_ERROR;
2422 	}
2423 
2424 	// Now we need to try to increment the use count of this addon flavor
2425 	// in the server. This can fail if the total number instances of this
2426 	// flavor is limited.
2427 	rv = IncrementAddonFlavorInstancesCount(addonID, flavorID);
2428 	if (rv != B_OK) {
2429 		ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create "
2430 			"more nodes for addon-id %" B_PRId32 ", flavor-id %" B_PRId32 "\n",
2431 			addonID, flavorID);
2432 		// Put the addon back into the pool
2433 		gDormantNodeManager->PutAddOn(addonID);
2434 		return B_ERROR;
2435 	}
2436 
2437 	BMessage config;
2438 	rv = LoadNodeConfiguration(addonID, flavorID, &config);
2439 	if (rv != B_OK) {
2440 		ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load "
2441 			"configuration for addon-id %" B_PRId32 ", flavor-id %" B_PRId32
2442 			"\n", addonID, flavorID);
2443 		// do not return, this is a minor problem, not a reason to fail
2444 	}
2445 
2446 	status_t status = B_OK;
2447 	BMediaNode* node = addon->InstantiateNodeFor(&info, &config, &status);
2448 	if (node == NULL) {
2449 		ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor "
2450 			"failed\n");
2451 
2452 		// Put the addon back into the pool
2453 		gDormantNodeManager->PutAddOn(addonID);
2454 
2455 		// We must decrement the use count of this addon flavor in the
2456 		// server to compensate the increment done in the beginning.
2457 		rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2458 		if (rv != B_OK) {
2459 			ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2460 				"FlavorInstancesCount failed\n");
2461 		}
2462 		return status != B_OK ? status : B_ERROR;
2463 	}
2464 
2465 	rv = RegisterNode(node, addonID, flavorID);
2466 	if (rv != B_OK) {
2467 		ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
2468 		delete node;
2469 		// Put the addon back into the pool
2470 		gDormantNodeManager->PutAddOn(addonID);
2471 		// We must decrement the use count of this addon flavor in the
2472 		// server to compensate the increment done in the beginning.
2473 		rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2474 		if (rv != B_OK) {
2475 			ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2476 				"FlavorInstancesCount failed\n");
2477 		}
2478 		return B_ERROR;
2479 	}
2480 
2481 	if (creator != -1) {
2482 		// send a message to the server to assign team "creator" as creator
2483 		// of node "node->ID()"
2484 		printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %"
2485 			B_PRId32 " as creator of node %" B_PRId32 "\n", creator,
2486 			node->ID());
2487 
2488 		rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator);
2489 		if (rv != B_OK) {
2490 			ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign "
2491 				"team %" B_PRId32 " as creator of node %" B_PRId32 "\n",
2492 				creator, node->ID());
2493 			// do not return, this is a minor problem, not a reason to fail
2494 		}
2495 	}
2496 
2497 	// RegisterNode() does remember the add-on id in the server
2498 	// and UnregisterNode() will call DormantNodeManager::PutAddon()
2499 	// when the node is unregistered.
2500 
2501 	*_node = node->Node();
2502 
2503 	TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %" B_PRId32
2504 		", flavor_id %" B_PRId32 " instanciated as node %" B_PRId32 ", port %"
2505 		B_PRId32 " in team %" B_PRId32 "\n", addonID, flavorID, _node->node,
2506 		_node->port, BPrivate::current_team());
2507 
2508 	return B_OK;
2509 }
2510 
2511 
2512 status_t
2513 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2514 	media_node* _node, uint32 flags)
2515 {
2516 	CALLED();
2517 	if (_node == NULL)
2518 		return B_BAD_VALUE;
2519 	if (info.addon <= B_OK) {
2520 		ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32
2521 			" invalid.\n", info.addon);
2522 		return B_BAD_VALUE;
2523 	}
2524 
2525 	printf("BMediaRoster::InstantiateDormantNode: addon-id %" B_PRId32
2526 		", flavor_id %" B_PRId32 ", flags 0x%" B_PRIx32 "\n", info.addon,
2527 		info.flavor_id, flags);
2528 
2529 	// Get flavor_info from the server
2530 	// TODO: this is a little overhead, as we get the full blown
2531 	// dormant_flavor_info,
2532 	// TODO: but only need the flags.
2533 	dormant_flavor_info flavorInfo;
2534 	status_t rv;
2535 	rv = MediaRosterEx(this)->GetDormantFlavorInfo(info.addon, info.flavor_id,
2536 		&flavorInfo);
2537 	if (rv != B_OK) {
2538 		ERROR("BMediaRoster::InstantiateDormantNode: failed to get "
2539 			"dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2540 			B_PRId32 "\n", info.addon, info.flavor_id);
2541 		return B_NAME_NOT_FOUND;
2542 	}
2543 
2544 	ASSERT(flavorInfo.internal_id == info.flavor_id);
2545 
2546 #if DEBUG
2547 	printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", "
2548 		"flavor_flags 0x%" B_PRIx32 ", internal_id %" B_PRId32
2549 		", possible_count %" B_PRId32 "\n", flavorInfo.name, flavorInfo.info,
2550 		flavorInfo.flavor_flags, flavorInfo.internal_id,
2551 		flavorInfo.possible_count);
2552 
2553 	if ((flags & B_FLAVOR_IS_LOCAL) != 0) {
2554 		printf("BMediaRoster::InstantiateDormantNode: caller requested "
2555 			"B_FLAVOR_IS_LOCAL\n");
2556 	}
2557 	if ((flags & B_FLAVOR_IS_GLOBAL) != 0) {
2558 		printf("BMediaRoster::InstantiateDormantNode: caller requested "
2559 			"B_FLAVOR_IS_GLOBAL\n");
2560 	}
2561 	if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0) {
2562 		printf("BMediaRoster::InstantiateDormantNode: node requires "
2563 			"B_FLAVOR_IS_LOCAL\n");
2564 	}
2565 	if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0) {
2566 		printf("BMediaRoster::InstantiateDormantNode: node requires "
2567 			"B_FLAVOR_IS_GLOBAL\n");
2568 	}
2569 #endif
2570 
2571 	// Make sure that flags demanded by the dormant node and those requested
2572 	// by the caller are not incompatible.
2573 	if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2574 		&& (flags & B_FLAVOR_IS_LOCAL) != 0) {
2575 		ERROR("BMediaRoster::InstantiateDormantNode: requested "
2576 			"B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n");
2577 		return B_NAME_NOT_FOUND;
2578 	}
2579 	if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0
2580 		&& (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2581 		ERROR("BMediaRoster::InstantiateDormantNode: requested "
2582 			"B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
2583 		return B_NAME_NOT_FOUND;
2584 	}
2585 
2586 	// If either the node, or the caller requested to make the instance global
2587 	// we will do it by forwarding this request into the media_addon_server,
2588 	// which in turn will call BMediaRosterEx::InstantiateDormantNode to create
2589 	// the node there and make it globally available.
2590 	if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2591 		|| (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2592 		TRACE("BMediaRoster::InstantiateDormantNode: creating global object "
2593 			"in media_addon_server\n");
2594 
2595 		add_on_server_instantiate_dormant_node_request request;
2596 		add_on_server_instantiate_dormant_node_reply reply;
2597 		request.add_on_id = info.addon;
2598 		request.flavor_id = info.flavor_id;
2599 		request.creator_team = BPrivate::current_team();
2600 			// creator team is allowed to also release global nodes
2601 		rv = QueryAddOnServer(ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE, &request,
2602 			sizeof(request), &reply, sizeof(reply));
2603 		if (rv == B_OK)
2604 			*_node = reply.node;
2605 	} else {
2606 		// creator team = -1, as this is a local node
2607 		rv = MediaRosterEx(this)->InstantiateDormantNode(info.addon,
2608 			info.flavor_id, -1, _node);
2609 	}
2610 	if (rv != B_OK) {
2611 		*_node = media_node::null;
2612 		return B_NAME_NOT_FOUND;
2613 	}
2614 	return B_OK;
2615 }
2616 
2617 
2618 status_t
2619 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2620 	media_node* _node)
2621 {
2622 	return InstantiateDormantNode(info, _node, 0);
2623 }
2624 
2625 
2626 status_t
2627 BMediaRoster::GetDormantNodeFor(const media_node& node,
2628 	dormant_node_info* _info)
2629 {
2630 	CALLED();
2631 	if (_info == NULL)
2632 		return B_BAD_VALUE;
2633 	if (IS_INVALID_NODE(node))
2634 		return B_MEDIA_BAD_NODE;
2635 
2636 	server_get_dormant_node_for_request request;
2637 	server_get_dormant_node_for_reply reply;
2638 	status_t rv;
2639 
2640 	request.node = node;
2641 
2642 	rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request),
2643 		&reply, sizeof(reply));
2644 	if (rv != B_OK)
2645 		return rv;
2646 
2647 	*_info = reply.node_info;
2648 	return B_OK;
2649 }
2650 
2651 
2652 status_t
2653 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID, int32 flavorID,
2654 	dormant_flavor_info* _flavor)
2655 {
2656 	CALLED();
2657 	if (_flavor == NULL)
2658 		return B_BAD_VALUE;
2659 
2660 	// TODO: better use an area here as well!
2661 
2662 	server_get_dormant_flavor_info_reply* reply
2663 		= (server_get_dormant_flavor_info_reply*)malloc(16300);
2664 	if (reply == NULL)
2665 		return B_NO_MEMORY;
2666 
2667 	server_get_dormant_flavor_info_request request;
2668 	request.add_on_id = addonID;
2669 	request.flavor_id = flavorID;
2670 
2671 	status_t status = QueryServer(SERVER_GET_DORMANT_FLAVOR_INFO, &request,
2672 		sizeof(request), reply, 16300);
2673 	if (status != B_OK) {
2674 		free(reply);
2675 		return status;
2676 	}
2677 
2678 	if (reply->result == B_OK) {
2679 		status = _flavor->Unflatten(reply->type, &reply->flattened_data,
2680 			reply->flattened_size);
2681 	} else
2682 		status = reply->result;
2683 
2684 	free(reply);
2685 	return status;
2686 }
2687 
2688 
2689 status_t
2690 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info& dormant,
2691 	dormant_flavor_info* _flavor)
2692 {
2693 	return MediaRosterEx(this)->GetDormantFlavorInfo(dormant.addon,
2694 		dormant.flavor_id, _flavor);
2695 }
2696 
2697 
2698 // Reports in outLatency the maximum latency found downstream from
2699 // the specified BBufferProducer, producer, given the current connections.
2700 status_t
2701 BMediaRoster::GetLatencyFor(const media_node& producer, bigtime_t* _latency)
2702 {
2703 	CALLED();
2704 	if (_latency == NULL)
2705 		return B_BAD_VALUE;
2706 	if (IS_INVALID_NODE(producer)
2707 		|| (producer.kind & B_BUFFER_PRODUCER) == 0)
2708 		return B_MEDIA_BAD_NODE;
2709 
2710 	producer_get_latency_request request;
2711 	producer_get_latency_reply reply;
2712 	status_t rv;
2713 
2714 	rv = QueryPort(producer.port, PRODUCER_GET_LATENCY, &request,
2715 		sizeof(request), &reply, sizeof(reply));
2716 	if (rv != B_OK)
2717 		return rv;
2718 
2719 	*_latency = reply.latency;
2720 
2721 //	printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2722 	return B_OK;
2723 }
2724 
2725 
2726 status_t
2727 BMediaRoster::GetInitialLatencyFor(const media_node& producer,
2728 	bigtime_t* _latency, uint32* _flags)
2729 {
2730 	CALLED();
2731 	if (_latency == NULL)
2732 		return B_BAD_VALUE;
2733 	if (IS_INVALID_NODE(producer)
2734 		|| (producer.kind & B_BUFFER_PRODUCER) == 0)
2735 		return B_MEDIA_BAD_NODE;
2736 
2737 	producer_get_initial_latency_request request;
2738 	producer_get_initial_latency_reply reply;
2739 	status_t rv;
2740 
2741 	rv = QueryPort(producer.port, PRODUCER_GET_INITIAL_LATENCY, &request,
2742 		sizeof(request), &reply, sizeof(reply));
2743 	if (rv != B_OK)
2744 		return rv;
2745 
2746 	*_latency = reply.initial_latency;
2747 	if (_flags != NULL)
2748 		*_flags = reply.flags;
2749 
2750 	TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32 " has "
2751 		"maximum initial latency %" B_PRId64 "\n", producer.node, *_latency);
2752 	return B_OK;
2753 }
2754 
2755 
2756 status_t
2757 BMediaRoster::GetStartLatencyFor(const media_node& timeSource,
2758 	bigtime_t* _latency)
2759 {
2760 	CALLED();
2761 	if (_latency == NULL)
2762 		return B_BAD_VALUE;
2763 	if (IS_INVALID_NODE(timeSource)
2764 		|| (timeSource.kind & B_TIME_SOURCE) == 0)
2765 		return B_MEDIA_BAD_NODE;
2766 
2767 	timesource_get_start_latency_request request;
2768 	timesource_get_start_latency_reply reply;
2769 	status_t rv;
2770 
2771 	rv = QueryPort(timeSource.port, TIMESOURCE_GET_START_LATENCY, &request,
2772 		sizeof(request), &reply, sizeof(reply));
2773 	if (rv != B_OK)
2774 		return rv;
2775 
2776 	*_latency = reply.start_latency;
2777 
2778 	TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32 " has "
2779 		"maximum initial latency %" B_PRId64 "\n", timeSource.node, *_latency);
2780 	return B_OK;
2781 }
2782 
2783 
2784 status_t
2785 BMediaRoster::GetFileFormatsFor(const media_node& fileInterface,
2786 	media_file_format* _formats, int32* _numFormats)
2787 {
2788 	UNIMPLEMENTED();
2789 	return B_ERROR;
2790 }
2791 
2792 
2793 status_t
2794 BMediaRoster::SetRefFor(const media_node& file_interface, const entry_ref& file,
2795 	bool createAndTruncate, bigtime_t* _length)
2796 {
2797 	CALLED();
2798 
2799 	fileinterface_set_ref_request request;
2800 	fileinterface_set_ref_reply reply;
2801 	status_t rv;
2802 
2803 	request.device = file.device;
2804 	request.directory = file.directory;
2805 	strcpy(request.name, file.name);
2806 	request.create = createAndTruncate;
2807 	if (_length != NULL)
2808 		request.duration = *_length;
2809 
2810 	rv = QueryPort(file_interface.port, FILEINTERFACE_SET_REF, &request,
2811 		sizeof(request), &reply, sizeof(reply));
2812 	if (rv != B_OK)
2813 		return rv;
2814 
2815 	if (!createAndTruncate && _length)
2816 		*_length = reply.duration;
2817 
2818 	return B_OK;
2819 }
2820 
2821 
2822 status_t
2823 BMediaRoster::GetRefFor(const media_node& node, entry_ref* _file,
2824 	BMimeType* mimeType)
2825 {
2826 	CALLED();
2827 
2828 	if (!_file)
2829 		return B_BAD_VALUE;
2830 
2831 	fileinterface_get_ref_request request;
2832 	fileinterface_get_ref_reply reply;
2833 	status_t rv;
2834 
2835 	rv = QueryPort(node.port, FILEINTERFACE_GET_REF, &request, sizeof(request),
2836 		&reply, sizeof(reply));
2837 	if (rv != B_OK)
2838 		return rv;
2839 
2840 	*_file = entry_ref(reply.device, reply.directory, reply.name);
2841 
2842 	if (mimeType)
2843 		mimeType->SetTo(reply.mimetype);
2844 
2845 	return B_OK;
2846 }
2847 
2848 
2849 status_t
2850 BMediaRoster::SniffRefFor(const media_node& file_interface,
2851 	const entry_ref& file, BMimeType* mimeType, float* _capability)
2852 {
2853 	CALLED();
2854 	if (mimeType == NULL || _capability == NULL)
2855 		return B_BAD_VALUE;
2856 
2857 	fileinterface_sniff_ref_request request;
2858 	fileinterface_sniff_ref_reply reply;
2859 	status_t rv;
2860 
2861 	request.device = file.device;
2862 	request.directory = file.directory;
2863 	strcpy(request.name, file.name);
2864 
2865 	rv = QueryPort(file_interface.port, FILEINTERFACE_SNIFF_REF, &request,
2866 		sizeof(request), &reply, sizeof(reply));
2867 	if (rv != B_OK)
2868 		return rv;
2869 
2870 	mimeType->SetTo(reply.mimetype);
2871 	*_capability = reply.capability;
2872 
2873 	return B_OK;
2874 }
2875 
2876 
2877 /*!	This is the generic "here's a file, now can someone please play it"
2878 	interface.
2879 */
2880 status_t
2881 BMediaRoster::SniffRef(const entry_ref& file, uint64 requireNodeKinds,
2882 	dormant_node_info* _node, BMimeType* mimeType)
2883 {
2884 	CALLED();
2885 
2886 	TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64
2887 		"\n", file.name, requireNodeKinds);
2888 
2889 	if (_node == NULL)
2890 		return B_BAD_VALUE;
2891 
2892 	BMimeType aMimeType;
2893 
2894 	dormant_node_info nodes[30];
2895 	int32 count = 30;
2896 	int32 highestCapability = -1;
2897 	float capability;
2898 
2899 	media_node node;
2900 
2901 	// Get all dormant nodes using GetDormantNodes
2902 	if (GetDormantNodes(nodes, &count, NULL, NULL, NULL, requireNodeKinds | B_FILE_INTERFACE, 0) == B_OK) {
2903 		// Call SniffRefFor on each node that matches requireNodeKinds
2904 		for (int32 i=0;i<count;i++) {
2905 			if (InstantiateDormantNode(nodes[i], &node) == B_OK) {
2906 
2907 				if (SniffRefFor(node, file, &aMimeType, &capability) == B_OK) {
2908 					// find the first node that has 100% capability
2909 					TRACE("%s has a %f%% chance of playing file\n",nodes[i].name, capability * 100.0);
2910 					if (capability == 1.0) {
2911 						highestCapability = i;
2912 						break;
2913 					}
2914 				}
2915 				ReleaseNode(node);
2916 			}
2917 		}
2918 
2919 		if (highestCapability != -1) {
2920 			*_node = nodes[highestCapability];
2921 
2922 			TRACE("BMediaRoster::SniffRef: found a node %s addon-id %" B_PRId32
2923 				", flavor_id %" B_PRId32 "\n",
2924 			nodes[highestCapability].name, nodes[highestCapability].addon,
2925 				nodes[highestCapability].flavor_id);
2926 
2927 			if (mimeType != NULL) {
2928 				//*mimeType = aMimeType; -- need a copy constructor
2929 			}
2930 
2931 			return B_OK;
2932 		}
2933 
2934 	}
2935 
2936 	return B_ERROR;
2937 }
2938 
2939 
2940 status_t
2941 BMediaRoster::GetDormantNodeForType(const BMimeType& type,
2942 	uint64 requireNodeKinds, dormant_node_info* _node)
2943 {
2944 	UNIMPLEMENTED();
2945 	return B_ERROR;
2946 }
2947 
2948 
2949 status_t
2950 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info& node,
2951 	media_file_format* _readFormats, int32 readCount, int32* _readCount)
2952 {
2953 	UNIMPLEMENTED();
2954 	return B_ERROR;
2955 }
2956 
2957 
2958 status_t
2959 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info& node,
2960 	media_file_format* _write_formats, int32 writeCount, int32* _writeCount)
2961 {
2962 	UNIMPLEMENTED();
2963 	return B_ERROR;
2964 }
2965 
2966 
2967 status_t
2968 BMediaRoster::GetFormatFor(const media_output& output, media_format* _format,
2969 	uint32 flags)
2970 {
2971 	CALLED();
2972 	if (_format == NULL)
2973 		return B_BAD_VALUE;
2974 	if ((output.node.kind & B_BUFFER_PRODUCER) == 0)
2975 		return B_MEDIA_BAD_NODE;
2976 	if (IS_INVALID_SOURCE(output.source))
2977 		return B_MEDIA_BAD_SOURCE;
2978 
2979 	producer_format_suggestion_requested_request request;
2980 	producer_format_suggestion_requested_reply reply;
2981 	status_t rv;
2982 
2983 	request.type = B_MEDIA_UNKNOWN_TYPE;
2984 	request.quality = 0; // TODO: what should this be?
2985 
2986 	rv = QueryPort(output.source.port, PRODUCER_FORMAT_SUGGESTION_REQUESTED,
2987 		&request, sizeof(request), &reply, sizeof(reply));
2988 	if (rv != B_OK)
2989 		return rv;
2990 
2991 	*_format = reply.format;
2992 	return B_OK;
2993 }
2994 
2995 
2996 status_t
2997 BMediaRoster::GetFormatFor(const media_input& input, media_format* _format,
2998 	uint32 flags)
2999 {
3000 	CALLED();
3001 	if (_format == NULL)
3002 		return B_BAD_VALUE;
3003 	if ((input.node.kind & B_BUFFER_CONSUMER) == 0)
3004 		return B_MEDIA_BAD_NODE;
3005 	if (IS_INVALID_DESTINATION(input.destination))
3006 		return B_MEDIA_BAD_DESTINATION;
3007 
3008 	consumer_accept_format_request request;
3009 	consumer_accept_format_reply reply;
3010 	status_t rv;
3011 
3012 	request.dest = input.destination;
3013 	memset(&request.format, 0, sizeof(request.format)); // wildcard
3014 
3015 	rv = QueryPort(input.destination.port, CONSUMER_ACCEPT_FORMAT, &request,
3016 		sizeof(request), &reply, sizeof(reply));
3017 	if (rv != B_OK)
3018 		return rv;
3019 
3020 	*_format = reply.format;
3021 	return B_OK;
3022 }
3023 
3024 
3025 status_t
3026 BMediaRoster::GetFormatFor(const media_node& node, media_format* _format,
3027 	float quality)
3028 {
3029 	UNIMPLEMENTED();
3030 	if (_format == NULL)
3031 		return B_BAD_VALUE;
3032 	if (IS_INVALID_NODE(node))
3033 		return B_MEDIA_BAD_NODE;
3034 	if ((node.kind & (B_BUFFER_CONSUMER | B_BUFFER_PRODUCER)) == 0)
3035 		return B_MEDIA_BAD_NODE;
3036 
3037 	return B_ERROR;
3038 }
3039 
3040 
3041 ssize_t
3042 BMediaRoster::GetNodeAttributesFor(const media_node& node,
3043 	media_node_attribute* _array, size_t maxCount)
3044 {
3045 	UNIMPLEMENTED();
3046 	return B_ERROR;
3047 }
3048 
3049 
3050 media_node_id
3051 BMediaRoster::NodeIDFor(port_id port)
3052 {
3053 	CALLED();
3054 
3055 	server_node_id_for_request request;
3056 	server_node_id_for_reply reply;
3057 	status_t rv;
3058 
3059 	request.port = port;
3060 
3061 	rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply,
3062 		sizeof(reply));
3063 	if (rv != B_OK) {
3064 		ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32 ")\n", rv);
3065 		return -1;
3066 	}
3067 
3068 	return reply.node_id;
3069 }
3070 
3071 
3072 status_t
3073 BMediaRoster::GetInstancesFor(media_addon_id addon, int32 flavor,
3074 	media_node_id* _id, int32* _count)
3075 {
3076 	CALLED();
3077 	if (_id == NULL)
3078 		return B_BAD_VALUE;
3079 	if (_count && *_count <= 0)
3080 		return B_BAD_VALUE;
3081 
3082 	server_get_instances_for_request request;
3083 	server_get_instances_for_reply reply;
3084 	status_t rv;
3085 
3086 	request.max_count = (_count ? *_count : 1);
3087 	request.add_on_id = addon;
3088 	request.flavor_id = flavor;
3089 
3090 	rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request),
3091 		&reply, sizeof(reply));
3092 	if (rv != B_OK) {
3093 		ERROR("BMediaRoster::GetLiveNodes failed\n");
3094 		return rv;
3095 	}
3096 
3097 	if (_count)
3098 		*_count = reply.count;
3099 	if (reply.count > 0)
3100 		memcpy(_id, reply.node_id, sizeof(media_node_id) * reply.count);
3101 
3102 	return B_OK;
3103 }
3104 
3105 
3106 status_t
3107 BMediaRoster::SetRealtimeFlags(uint32 enabled)
3108 {
3109 	UNIMPLEMENTED();
3110 	return B_ERROR;
3111 }
3112 
3113 
3114 status_t
3115 BMediaRoster::GetRealtimeFlags(uint32* _enabled)
3116 {
3117 	UNIMPLEMENTED();
3118 	return B_ERROR;
3119 }
3120 
3121 
3122 ssize_t
3123 BMediaRoster::AudioBufferSizeFor(int32 channelCount, uint32 sampleFormat,
3124 	float frameRate, bus_type busKind)
3125 {
3126 	bigtime_t bufferDuration;
3127 	ssize_t bufferSize;
3128 
3129 	system_info info;
3130 	get_system_info(&info);
3131 
3132 	if (info.cpu_clock_speed > 2000000000)	// 2 GHz
3133 		bufferDuration = 2500;
3134 	else if (info.cpu_clock_speed > 1000000000)
3135 		bufferDuration = 5000;
3136 	else if (info.cpu_clock_speed > 600000000)
3137 		bufferDuration = 10000;
3138 	else if (info.cpu_clock_speed > 200000000)
3139 		bufferDuration = 20000;
3140 	else if (info.cpu_clock_speed > 100000000)
3141 		bufferDuration = 30000;
3142 	else
3143 		bufferDuration = 50000;
3144 
3145 	if ((busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS)
3146 		&& bufferDuration < 25000)
3147 		bufferDuration = 25000;
3148 
3149 	bufferSize = (sampleFormat & 0xf) * channelCount
3150 		* (ssize_t)((frameRate * bufferDuration) / 1000000.0);
3151 
3152 	printf("Suggested buffer duration %" B_PRId64 ", size %" B_PRIdSSIZE "\n",
3153 		bufferDuration, bufferSize);
3154 
3155 	return bufferSize;
3156 }
3157 
3158 
3159 /*!	Use MediaFlags to inquire about specific features of the Media Kit.
3160 	Returns < 0 for "not present", positive size for output data size.
3161 	0 means that the capability is present, but no data about it.
3162 */
3163 /*static*/ ssize_t
3164 BMediaRoster::MediaFlags(media_flags cap, void* buffer, size_t maxSize)
3165 {
3166 	UNIMPLEMENTED();
3167 	return 0;
3168 }
3169 
3170 
3171 //	#pragma mark - BLooper overrides
3172 
3173 
3174 void
3175 BMediaRoster::MessageReceived(BMessage* message)
3176 {
3177 	switch (message->what) {
3178 		case 'PING':
3179 		{
3180 			// media_server plays ping-pong with the BMediaRosters
3181 			// to detect dead teams. Normal communication uses ports.
3182 			static BMessage pong('PONG');
3183 			message->SendReply(&pong, static_cast<BHandler *>(NULL), 2000000);
3184 			return;
3185 		}
3186 
3187 		case NODE_FINAL_RELEASE:
3188 		{
3189 			// this function is called by a BMediaNode to delete
3190 			// itself, as this needs to be done from another thread
3191 			// context, it is done here.
3192 			// TODO: If a node is released using BMediaRoster::ReleaseNode()
3193 			// TODO: instead of using BMediaNode::Release() / BMediaNode::Acquire()
3194 			// TODO: fRefCount of the BMediaNode will not be correct.
3195 
3196 			BMediaNode *node;
3197 			message->FindPointer("node", reinterpret_cast<void **>(&node));
3198 
3199 			TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE saving "
3200 				"node %" B_PRId32 " configuration\n", node->ID());
3201 			MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(node);
3202 
3203 			TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing "
3204 				"node %" B_PRId32 "\n", node->ID());
3205 			node->DeleteHook(node); // we don't call Release(), see above!
3206 			return;
3207 		}
3208 	}
3209 	printf("BMediaRoster::MessageReceived: unknown message!\n");
3210 	message->PrintToStream();
3211 }
3212 
3213 
3214 bool
3215 BMediaRoster::QuitRequested()
3216 {
3217 	UNIMPLEMENTED();
3218 	return true;
3219 }
3220 
3221 
3222 BHandler*
3223 BMediaRoster::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
3224 	int32 form, const char* property)
3225 {
3226 	return BLooper::ResolveSpecifier(msg, index, specifier, form, property);
3227 }
3228 
3229 
3230 status_t
3231 BMediaRoster::GetSupportedSuites(BMessage* data)
3232 {
3233 	return BLooper::GetSupportedSuites(data);
3234 }
3235 
3236 
3237 BMediaRoster::~BMediaRoster()
3238 {
3239 	CALLED();
3240 
3241 	delete gTimeSourceObjectManager;
3242 	delete gDormantNodeManager;
3243 
3244 	// unregister this application with the media server
3245 	server_unregister_app_request request;
3246 	server_unregister_app_reply reply;
3247 	request.team = BPrivate::current_team();
3248 	QueryServer(SERVER_UNREGISTER_APP, &request, sizeof(request), &reply,
3249 		sizeof(reply));
3250 
3251 	BPrivate::SharedBufferList::Invalidate();
3252 
3253 	// Unset the global instance pointer, the destructor is also called
3254 	// if a client app calls Lock(); and Quit(); directly.
3255 	sDefaultInstance = NULL;
3256 }
3257 
3258 
3259 //	#pragma mark - private BMediaRoster
3260 
3261 
3262 //! Deprecated call.
3263 status_t
3264 BMediaRoster::SetOutputBuffersFor(const media_source& output,
3265 	BBufferGroup* group, bool willReclaim)
3266 {
3267 	UNIMPLEMENTED();
3268 	debugger("BMediaRoster::SetOutputBuffersFor missing\n");
3269 	return B_ERROR;
3270 }
3271 
3272 
3273 // FBC reserved virtuals
3274 status_t BMediaRoster::_Reserved_MediaRoster_0(void*) { return B_ERROR; }
3275 status_t BMediaRoster::_Reserved_MediaRoster_1(void*) { return B_ERROR; }
3276 status_t BMediaRoster::_Reserved_MediaRoster_2(void*) { return B_ERROR; }
3277 status_t BMediaRoster::_Reserved_MediaRoster_3(void*) { return B_ERROR; }
3278 status_t BMediaRoster::_Reserved_MediaRoster_4(void*) { return B_ERROR; }
3279 status_t BMediaRoster::_Reserved_MediaRoster_5(void*) { return B_ERROR; }
3280 status_t BMediaRoster::_Reserved_MediaRoster_6(void*) { return B_ERROR; }
3281 status_t BMediaRoster::_Reserved_MediaRoster_7(void*) { return B_ERROR; }
3282 
3283 
3284 BMediaRoster::BMediaRoster()
3285 	:
3286 	BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY,
3287 		B_LOOPER_PORT_DEFAULT_CAPACITY)
3288 {
3289 	CALLED();
3290 
3291 	// start the looper
3292 	Run();
3293 }
3294 
3295 
3296 // TODO: Looks like these can be safely removed:
3297 /*static*/ status_t
3298 BMediaRoster::ParseCommand(BMessage& reply)
3299 {
3300 	UNIMPLEMENTED();
3301 	return B_ERROR;
3302 }
3303 
3304 
3305 status_t
3306 BMediaRoster::GetDefaultInfo(media_node_id forDefault, BMessage& config)
3307 {
3308 	UNIMPLEMENTED();
3309 	return B_ERROR;
3310 }
3311 
3312 
3313 status_t
3314 BMediaRoster::SetRunningDefault(media_node_id forDefault,
3315 	const media_node& node)
3316 {
3317 	UNIMPLEMENTED();
3318 	return B_ERROR;
3319 }
3320 
3321 
3322 // #pragma mark - static variables
3323 
3324 
3325 BMediaRoster* BMediaRoster::sDefaultInstance = NULL;
3326