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