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