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