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