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