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