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