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