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