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