tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / media / MediaRoster.cpp
blobe386c2d0fb6effa35f6b23b36ca67967ede1020a
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
6 * All rights reserved. Distributed under the terms of the MIT License.
7 */
9 /*
10 * Copyright (c) 2002-2006 Marcus Overhagen <Marcus@Overhagen.de>
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:
20 * * Redistributions of source code must retain the above copyright notice,
21 * this list of conditions and the following disclaimer.
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.
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.
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>";
43 #include <MediaRoster.h>
45 #include <new>
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>
60 #include <AppMisc.h>
62 #include <DataExchange.h>
63 #include <debug.h>
64 #include <DormantNodeManager.h>
65 #include <MediaMisc.h>
66 #include <MediaRosterEx.h>
67 #include <Notifications.h>
68 #include <ServerInterface.h>
69 #include <SharedBufferList.h>
70 #include <TList.h>
72 #include "TimeSourceObjectManager.h"
75 namespace BPrivate {
76 namespace media {
79 struct RosterNotification {
80 BMessenger messenger;
81 int32 what;
84 static bool sServerIsUp = false;
85 static List<RosterNotification> sNotificationList;
87 } // namespace media
88 } // namespace BPrivate
90 using namespace BPrivate::media;
93 BMediaRosterEx::BMediaRosterEx(status_t* _error)
95 BMediaRoster()
97 gDormantNodeManager = new DormantNodeManager;
98 gTimeSourceObjectManager = new TimeSourceObjectManager;
100 *_error = BuildConnections();
102 InitRosterDataExchange(BMessenger(this, this));
104 if (be_roster->StartWatching(BMessenger(this, this),
105 B_REQUEST_LAUNCHED | B_REQUEST_QUIT) != B_OK) {
106 *_error = B_ERROR;
108 sServerIsUp = BMediaRoster::IsRunning();
112 status_t
113 BMediaRosterEx::BuildConnections()
115 InitServerDataExchange();
116 // register this application with the media server
117 server_register_app_request request;
118 server_register_app_reply reply;
119 request.team = BPrivate::current_team();
120 request.messenger = BMessenger(NULL, this);
121 status_t status = QueryServer(SERVER_REGISTER_APP, &request,
122 sizeof(request), &reply, sizeof(reply));
123 if (status != B_OK)
124 return B_MEDIA_SYSTEM_FAILURE;
126 return B_OK;
130 BMediaRosterEx::~BMediaRosterEx()
132 CALLED();
134 delete gTimeSourceObjectManager;
135 delete gDormantNodeManager;
137 // unregister this application with the media server
138 server_unregister_app_request request;
139 server_unregister_app_reply reply;
140 request.team = BPrivate::current_team();
141 QueryServer(SERVER_UNREGISTER_APP, &request, sizeof(request), &reply,
142 sizeof(reply));
144 BPrivate::SharedBufferList::Invalidate();
148 status_t
149 BMediaRosterEx::SaveNodeConfiguration(BMediaNode* node)
151 int32 flavorID;
152 BMediaAddOn* addon = node->AddOn(&flavorID);
153 if (addon == NULL) {
154 // NOTE: This node could have been created by an application,
155 // it does not mean there is an error.
156 // TODO: this check incorrectly triggers on BeOS R5 BT848 node
157 TRACE("BMediaRosterEx::SaveNodeConfiguration node %" B_PRId32 " not "
158 "instantiated from BMediaAddOn!\n", node->ID());
159 return B_ERROR;
162 media_addon_id addonID = addon->AddonID();
164 // TODO: fix this
165 printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id "
166 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID,
167 flavorID);
168 return B_OK;
172 status_t
173 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonID, int32 flavorID,
174 BMessage *_msg)
176 // TODO: fix this
177 _msg->MakeEmpty(); // to be fully R5 compliant
178 printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id "
179 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID,
180 flavorID);
181 return B_OK;
185 status_t
186 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonID,
187 int32 flavorID)
189 server_change_flavor_instances_count_request request;
190 server_change_flavor_instances_count_reply reply;
192 request.add_on_id = addonID;
193 request.flavor_id = flavorID;
194 request.delta = 1;
195 request.team = BPrivate::current_team();
196 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request,
197 sizeof(request), &reply, sizeof(reply));
201 status_t
202 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonID,
203 int32 flavorID)
205 server_change_flavor_instances_count_request request;
206 server_change_flavor_instances_count_reply reply;
208 request.add_on_id = addonID;
209 request.flavor_id = flavorID;
210 request.delta = -1;
211 request.team = BPrivate::current_team();
212 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request,
213 sizeof(request), &reply, sizeof(reply));
217 status_t
218 BMediaRosterEx::ReleaseNodeAll(const media_node& node)
220 CALLED();
221 if (IS_INVALID_NODE(node))
222 return B_MEDIA_BAD_NODE;
224 if (node.kind & NODE_KIND_NO_REFCOUNTING)
225 return B_OK;
227 server_release_node_request request;
228 server_release_node_reply reply;
229 status_t rv;
231 request.node = node;
232 request.team = BPrivate::current_team();
234 TRACE("BMediaRoster::ReleaseNodeAll, node %" B_PRId32 ", port %" B_PRId32
235 ", team %" B_PRId32 "\n",
236 node.node, node.port, BPrivate::current_team());
238 rv = QueryServer(SERVER_RELEASE_NODE_ALL, &request, sizeof(request), &reply,
239 sizeof(reply));
240 if (rv != B_OK) {
241 ERROR("BMediaRoster::ReleaseNodeAll failed to query media_server, "
242 "retrying local, node %" B_PRId32 ", port %"
243 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
244 BPrivate::current_team());
245 node_final_release_command command;
246 rv = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
247 sizeof(command));
248 if (rv != B_OK) {
249 ERROR("BMediaRoster::ReleaseNodeAll FAILED, node %" B_PRId32 ", port %"
250 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
251 BPrivate::current_team());
254 return rv;
258 status_t
259 BMediaRosterEx::SetNodeCreator(media_node_id node, team_id creator)
261 server_set_node_creator_request request;
262 server_set_node_creator_reply reply;
264 request.node = node;
265 request.creator = creator;
266 return QueryServer(SERVER_SET_NODE_CREATOR, &request, sizeof(request),
267 &reply, sizeof(reply));
271 status_t
272 BMediaRosterEx::GetNode(node_type type, media_node* out_node,
273 int32* out_input_id, BString* out_input_name)
275 if (out_node == NULL)
276 return B_BAD_VALUE;
278 server_get_node_request request;
279 server_get_node_reply reply;
280 status_t rv;
282 request.type = type;
283 request.team = BPrivate::current_team();
284 rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply,
285 sizeof(reply));
286 if (rv != B_OK)
287 return rv;
289 *out_node = reply.node;
290 if (out_input_id)
291 *out_input_id = reply.input_id;
292 if (out_input_name)
293 *out_input_name = reply.input_name;
294 return rv;
298 status_t
299 BMediaRosterEx::SetNode(node_type type, const media_node* node,
300 const dormant_node_info* info, const media_input* input)
302 server_set_node_request request;
303 server_set_node_reply reply;
305 request.type = type;
306 request.use_node = node != NULL;
307 if (node != NULL)
308 request.node = *node;
309 request.use_dni = info != NULL;
310 if (info != NULL)
311 request.dni = *info;
312 request.use_input = input != NULL;
313 if (input != NULL)
314 request.input = *input;
316 return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply,
317 sizeof(reply));
321 status_t
322 BMediaRosterEx::GetAllOutputs(const media_node& node, List<media_output>* list)
324 int32 cookie;
325 status_t rv;
326 status_t result;
328 PRINT(4, "BMediaRosterEx::GetAllOutputs() node %" B_PRId32 ", port %"
329 B_PRId32 "\n", node.node, node.port);
331 if (!(node.kind & B_BUFFER_PRODUCER)) {
332 ERROR("BMediaRosterEx::GetAllOutputs: node %" B_PRId32 " is not a "
333 "B_BUFFER_PRODUCER\n", node.node);
334 return B_MEDIA_BAD_NODE;
337 result = B_OK;
338 cookie = 0;
339 list->MakeEmpty();
340 for (;;) {
341 producer_get_next_output_request request;
342 producer_get_next_output_reply reply;
343 request.cookie = cookie;
344 rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request,
345 sizeof(request), &reply, sizeof(reply));
346 if (rv != B_OK)
347 break;
348 cookie = reply.cookie;
349 if (!list->Insert(reply.output)) {
350 ERROR("GetAllOutputs: list->Insert failed\n");
351 result = B_ERROR;
353 #if DEBUG >= 3
354 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
355 PRINT_OUTPUT("output ", reply.output);
356 #endif
359 producer_dispose_output_cookie_request request;
360 producer_dispose_output_cookie_reply reply;
361 QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request,
362 sizeof(request), &reply, sizeof(reply));
364 return result;
368 status_t
369 BMediaRosterEx::GetAllOutputs(BBufferProducer* node, List<media_output>* list)
371 int32 cookie;
372 status_t result;
374 PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %" B_PRId32
375 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort());
377 result = B_OK;
378 cookie = 0;
379 list->MakeEmpty();
380 for (;;) {
381 media_output output;
382 if (B_OK != node->GetNextOutput(&cookie, &output))
383 break;
384 if (!list->Insert(output)) {
385 ERROR("GetAllOutputs: list->Insert failed\n");
386 result = B_ERROR;
388 #if DEBUG >= 3
389 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
390 PRINT_OUTPUT("output ", output);
391 #endif
393 node->DisposeOutputCookie(cookie);
394 return result;
398 status_t
399 BMediaRosterEx::GetAllInputs(const media_node& node, List<media_input>* list)
401 int32 cookie;
402 status_t rv;
403 status_t result;
405 PRINT(4, "BMediaRosterEx::GetAllInputs() node %" B_PRId32 ", port %"
406 B_PRId32 "\n", node.node, node.port);
408 if (!(node.kind & B_BUFFER_CONSUMER)) {
409 ERROR("BMediaRosterEx::GetAllInputs: node %" B_PRId32 " is not a "
410 "B_BUFFER_CONSUMER\n", node.node);
411 return B_MEDIA_BAD_NODE;
414 result = B_OK;
415 cookie = 0;
416 list->MakeEmpty();
417 for (;;) {
418 consumer_get_next_input_request request;
419 consumer_get_next_input_reply reply;
420 request.cookie = cookie;
421 rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request,
422 sizeof(request), &reply, sizeof(reply));
423 if (rv != B_OK)
424 break;
425 cookie = reply.cookie;
426 if (!list->Insert(reply.input)) {
427 ERROR("GetAllInputs: list->Insert failed\n");
428 result = B_ERROR;
430 #if DEBUG >= 3
431 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
432 PRINT_OUTPUT("input ", reply.input);
433 #endif
436 consumer_dispose_input_cookie_request request;
437 consumer_dispose_input_cookie_reply reply;
438 QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request,
439 sizeof(request), &reply, sizeof(reply));
441 return result;
445 status_t
446 BMediaRosterEx::GetAllInputs(BBufferConsumer* node, List<media_input>* list)
448 int32 cookie;
449 status_t result;
451 PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %" B_PRId32
452 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort());
454 result = B_OK;
455 cookie = 0;
456 list->MakeEmpty();
457 for (;;) {
458 media_input input;
459 if (B_OK != node->GetNextInput(&cookie, &input))
460 break;
461 if (!list->Insert(input)) {
462 ERROR("GetAllInputs: list->Insert failed\n");
463 result = B_ERROR;
465 #if DEBUG >= 3
466 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
467 PRINT_INPUT("input ", input);
468 #endif
470 node->DisposeInputCookie(cookie);
471 return result;
475 status_t
476 BMediaRosterEx::PublishOutputs(const media_node& node, List<media_output>* list)
478 server_publish_outputs_request request;
479 server_publish_outputs_reply reply;
480 media_output* output;
481 media_output* outputs;
482 int32 count;
483 status_t rv;
485 count = list->CountItems();
486 TRACE("PublishOutputs: publishing %" B_PRId32 "\n", count);
488 request.node = node;
489 request.count = count;
490 if (count > MAX_OUTPUTS) {
491 void *start_addr;
492 size_t size;
493 size = ROUND_UP_TO_PAGE(count * sizeof(media_output));
494 request.area = create_area("publish outputs", &start_addr,
495 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
496 if (request.area < B_OK) {
497 ERROR("PublishOutputs: failed to create area, %#" B_PRIx32 "\n",
498 request.area);
499 return (status_t)request.area;
501 outputs = static_cast<media_output *>(start_addr);
502 } else {
503 request.area = -1;
504 outputs = request.outputs;
506 TRACE("PublishOutputs: area %" B_PRId32 "\n", request.area);
508 int i;
509 for (i = 0, list->Rewind(); list->GetNext(&output); i++) {
510 ASSERT(i < count);
511 outputs[i] = *output;
514 rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request),
515 &reply, sizeof(reply));
517 if (request.area != -1)
518 delete_area(request.area);
520 return rv;
524 status_t
525 BMediaRosterEx::PublishInputs(const media_node& node, List<media_input>* list)
527 server_publish_inputs_request request;
528 server_publish_inputs_reply reply;
529 media_input* input;
530 media_input* inputs;
531 int32 count;
532 status_t rv;
534 count = list->CountItems();
535 TRACE("PublishInputs: publishing %" B_PRId32 "\n", count);
537 request.node = node;
538 request.count = count;
539 if (count > MAX_INPUTS) {
540 void* start_addr;
541 size_t size;
542 size = ROUND_UP_TO_PAGE(count * sizeof(media_input));
543 request.area = create_area("publish inputs", &start_addr,
544 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
545 if (request.area < B_OK) {
546 ERROR("PublishInputs: failed to create area, %#" B_PRIx32 "\n",
547 request.area);
548 return (status_t)request.area;
550 inputs = static_cast<media_input *>(start_addr);
551 } else {
552 request.area = -1;
553 inputs = request.inputs;
555 TRACE("PublishInputs: area %" B_PRId32 "\n", request.area);
557 int i;
558 for (i = 0, list->Rewind(); list->GetNext(&input); i++) {
559 ASSERT(i < count);
560 inputs[i] = *input;
563 rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request),
564 &reply, sizeof(reply));
566 if (request.area != -1)
567 delete_area(request.area);
569 return rv;
573 BTimeSource*
574 BMediaRosterEx::MakeTimeSourceObject(media_node_id timeSourceID)
576 media_node clone;
577 status_t status = GetNodeFor(timeSourceID, &clone);
578 if (status != B_OK) {
579 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed: %s\n",
580 strerror(status));
581 return NULL;
584 BTimeSource* source = gTimeSourceObjectManager->GetTimeSource(clone);
585 if (source == NULL) {
586 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n");
587 return NULL;
590 // TODO: release?
591 ReleaseNode(clone);
593 return source;
597 // #pragma mark - public BMediaRoster
600 status_t
601 BMediaRoster::GetVideoInput(media_node* _node)
603 CALLED();
604 return MediaRosterEx(this)->GetNode(VIDEO_INPUT, _node);
608 status_t
609 BMediaRoster::GetAudioInput(media_node* _node)
611 CALLED();
612 return MediaRosterEx(this)->GetNode(AUDIO_INPUT, _node);
616 status_t
617 BMediaRoster::GetVideoOutput(media_node* _node)
619 CALLED();
620 return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT, _node);
624 status_t
625 BMediaRoster::GetAudioMixer(media_node* _node)
627 CALLED();
628 return MediaRosterEx(this)->GetNode(AUDIO_MIXER, _node);
632 status_t
633 BMediaRoster::GetAudioOutput(media_node* _node)
635 CALLED();
636 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT, _node);
640 status_t
641 BMediaRoster::GetAudioOutput(media_node* _node, int32* _inputID,
642 BString* _inputName)
644 CALLED();
645 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX, _node, _inputID,
646 _inputName);
650 status_t
651 BMediaRoster::GetTimeSource(media_node* _node)
653 CALLED();
654 status_t rv;
656 // TODO: need to do this in a nicer way.
658 rv = MediaRosterEx(this)->GetNode(TIME_SOURCE, _node);
659 if (rv != B_OK)
660 return rv;
662 // We don't do reference counting for timesources, that's why we
663 // release the node immediately.
664 ReleaseNode(*_node);
666 // we need to remember to not use this node with server side reference counting
667 _node->kind |= NODE_KIND_NO_REFCOUNTING;
668 return B_OK;
672 status_t
673 BMediaRoster::SetVideoInput(const media_node& producer)
675 CALLED();
676 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, &producer);
680 status_t
681 BMediaRoster::SetVideoInput(const dormant_node_info& producer)
683 CALLED();
684 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, NULL, &producer);
688 status_t
689 BMediaRoster::SetAudioInput(const media_node& producer)
691 CALLED();
692 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, &producer);
696 status_t
697 BMediaRoster::SetAudioInput(const dormant_node_info& producer)
699 CALLED();
700 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, NULL, &producer);
704 status_t
705 BMediaRoster::SetVideoOutput(const media_node& consumer)
707 CALLED();
708 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, &consumer);
712 status_t
713 BMediaRoster::SetVideoOutput(const dormant_node_info& consumer)
715 CALLED();
716 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, NULL, &consumer);
720 status_t
721 BMediaRoster::SetAudioOutput(const media_node& consumer)
723 CALLED();
724 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, &consumer);
728 status_t
729 BMediaRoster::SetAudioOutput(const media_input& input)
731 CALLED();
732 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, NULL, &input);
736 status_t
737 BMediaRoster::SetAudioOutput(const dormant_node_info& consumer)
739 CALLED();
740 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, &consumer);
744 status_t
745 BMediaRoster::GetNodeFor(media_node_id node, media_node* clone)
747 CALLED();
748 if (clone == NULL)
749 return B_BAD_VALUE;
750 if (IS_INVALID_NODEID(node))
751 return B_MEDIA_BAD_NODE;
753 server_get_node_for_request request;
754 server_get_node_for_reply reply;
755 status_t rv;
757 request.node_id = node;
758 request.team = BPrivate::current_team();
760 rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply,
761 sizeof(reply));
762 if (rv != B_OK)
763 return rv;
765 *clone = reply.clone;
766 return B_OK;
770 status_t
771 BMediaRoster::GetSystemTimeSource(media_node* clone)
773 CALLED();
774 status_t rv;
776 // TODO: need to do this in a nicer way.
778 rv = MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE, clone);
779 if (rv != B_OK)
780 return rv;
782 // We don't do reference counting for timesources, that's why we
783 // release the node immediately.
784 ReleaseNode(*clone);
786 // we need to remember to not use this node with server side reference
787 // counting
788 clone->kind |= NODE_KIND_NO_REFCOUNTING;
790 return B_OK;
794 status_t
795 BMediaRoster::ReleaseNode(const media_node& node)
797 CALLED();
798 if (IS_INVALID_NODE(node))
799 return B_MEDIA_BAD_NODE;
801 if (node.kind & NODE_KIND_NO_REFCOUNTING) {
802 TRACE("BMediaRoster::ReleaseNode, trying to release reference "
803 "counting disabled timesource, node %" B_PRId32 ", port %" B_PRId32
804 ", team %" B_PRId32 "\n", node.node, node.port,
805 BPrivate::current_team());
806 return B_OK;
809 server_release_node_request request;
810 server_release_node_reply reply;
811 status_t rv;
813 request.node = node;
814 request.team = BPrivate::current_team();
816 TRACE("BMediaRoster::ReleaseNode, node %" B_PRId32 ", port %" B_PRId32
817 ", team %" B_PRId32 "\n", node.node, node.port,
818 BPrivate::current_team());
820 rv = QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply,
821 sizeof(reply));
822 if (rv != B_OK) {
823 ERROR("BMediaRoster::ReleaseNode FAILED, node %" B_PRId32 ", port %"
824 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
825 BPrivate::current_team());
827 return rv;
831 BTimeSource*
832 BMediaRoster::MakeTimeSourceFor(const media_node& forNode)
834 // MakeTimeSourceFor() returns a BTimeSource object
835 // corresponding to the specified node's time source.
837 CALLED();
839 if (IS_SYSTEM_TIMESOURCE(forNode)) {
840 // special handling for the system time source
841 TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time "
842 "source\n");
843 return MediaRosterEx(this)->MakeTimeSourceObject(
844 NODE_SYSTEM_TIMESOURCE_ID);
847 if (IS_INVALID_NODE(forNode)) {
848 ERROR("BMediaRoster::MakeTimeSourceFor: for_node invalid, node %"
849 B_PRId32 ", port %" B_PRId32 ", kinds 0x%" B_PRIx32 "\n",
850 forNode.node, forNode.port, forNode.kind);
851 return NULL;
854 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " enter\n",
855 forNode.node);
857 node_get_timesource_request request;
858 node_get_timesource_reply reply;
859 BTimeSource *source;
860 status_t rv;
862 // ask the node to get it's current timesource id
863 rv = QueryPort(forNode.port, NODE_GET_TIMESOURCE, &request,
864 sizeof(request), &reply, sizeof(reply));
865 if (rv != B_OK) {
866 ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n");
867 return NULL;
870 source = MediaRosterEx(this)->MakeTimeSourceObject(reply.timesource_id);
872 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " leave\n",
873 forNode.node);
875 return source;
879 status_t
880 BMediaRoster::Connect(const media_source& from, const media_destination& to,
881 media_format* _format, media_output* _output, media_input* _input)
883 return BMediaRoster::Connect(from, to, _format, _output, _input, 0);
887 status_t
888 BMediaRoster::Connect(const media_source& from, const media_destination& to,
889 media_format* io_format, media_output* out_output, media_input* out_input,
890 uint32 in_flags, void* _reserved)
892 CALLED();
893 if (io_format == NULL || out_output == NULL || out_input == NULL)
894 return B_BAD_VALUE;
895 if (IS_INVALID_SOURCE(from)) {
896 ERROR("BMediaRoster::Connect: media_source invalid\n");
897 return B_MEDIA_BAD_SOURCE;
899 if (IS_INVALID_DESTINATION(to)) {
900 ERROR("BMediaRoster::Connect: media_destination invalid\n");
901 return B_MEDIA_BAD_DESTINATION;
904 status_t rv;
906 // find the output and input nodes
907 // TODO: isn't there a easier way?
908 media_node sourcenode;
909 media_node destnode;
910 rv = GetNodeFor(NodeIDFor(from.port), &sourcenode);
911 if (rv != B_OK) {
912 ERROR("BMediaRoster::Connect: Can't find source node for port %"
913 B_PRId32 "\n", from.port);
914 return B_MEDIA_BAD_SOURCE;
916 ReleaseNode(sourcenode);
917 rv = GetNodeFor(NodeIDFor(to.port), &destnode);
918 if (rv != B_OK) {
919 ERROR("BMediaRoster::Connect: Can't find destination node for port "
920 "%" B_PRId32 "\n", to.port);
921 return B_MEDIA_BAD_DESTINATION;
923 ReleaseNode(destnode);
925 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) {
926 ERROR("BMediaRoster::Connect: source node %" B_PRId32 " is not a "
927 "B_BUFFER_PRODUCER\n", sourcenode.node);
928 return B_MEDIA_BAD_SOURCE;
930 if (!(destnode.kind & B_BUFFER_CONSUMER)) {
931 ERROR("BMediaRoster::Connect: destination node %" B_PRId32 " is not a "
932 "B_BUFFER_CONSUMER\n", destnode.node);
933 return B_MEDIA_BAD_DESTINATION;
936 producer_format_proposal_request request1;
937 producer_format_proposal_reply reply1;
939 PRINT_FORMAT("BMediaRoster::Connect calling "
940 "BBufferProducer::FormatProposal with format ", *io_format);
942 // BBufferProducer::FormatProposal
943 request1.output = from;
944 request1.format = *io_format;
945 rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1,
946 sizeof(request1), &reply1, sizeof(reply1));
947 if (rv != B_OK) {
948 ERROR("BMediaRoster::Connect: aborted after "
949 "BBufferProducer::FormatProposal, status = %#" B_PRIx32 "\n",rv);
950 return rv;
952 // reply1.format now contains the format proposed by the producer
954 consumer_accept_format_request request2;
955 consumer_accept_format_reply reply2;
957 PRINT_FORMAT("BMediaRoster::Connect calling "
958 "BBufferConsumer::AcceptFormat with format ", reply1.format);
960 // BBufferConsumer::AcceptFormat
961 request2.dest = to;
962 request2.format = reply1.format;
963 rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2,
964 sizeof(request2), &reply2, sizeof(reply2));
965 if (rv != B_OK) {
966 ERROR("BMediaRoster::Connect: aborted after "
967 "BBufferConsumer::AcceptFormat, status = %#" B_PRIx32 "\n",rv);
968 return rv;
970 // reply2.format now contains the format accepted by the consumer
972 // BBufferProducer::PrepareToConnect
973 producer_prepare_to_connect_request request3;
974 producer_prepare_to_connect_reply reply3;
976 PRINT_FORMAT("BMediaRoster::Connect calling "
977 "BBufferProducer::PrepareToConnect with format", reply2.format);
979 request3.source = from;
980 request3.destination = to;
981 request3.format = reply2.format;
982 strcpy(request3.name, "XXX some default name"); // TODO: fix this
983 rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3,
984 sizeof(request3), &reply3, sizeof(reply3));
985 if (rv != B_OK) {
986 ERROR("BMediaRoster::Connect: aborted after "
987 "BBufferProducer::PrepareToConnect, status = %#" B_PRIx32 "\n", rv);
988 return rv;
990 // reply3.format is still our pretty media format
991 // reply3.out_source the real source to be used for the connection
992 // reply3.name the name BBufferConsumer::Connected will see in the
993 // outInput->name argument
995 // BBufferConsumer::Connected
996 consumer_connected_request request4;
997 consumer_connected_reply reply4;
998 status_t con_status;
1000 PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::Connected() "
1001 "with format ", reply3.format);
1003 request4.input.node = destnode;
1004 request4.input.source = reply3.out_source;
1005 request4.input.destination = to;
1006 request4.input.format = reply3.format;
1007 strcpy(request4.input.name, reply3.name);
1009 con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4,
1010 sizeof(request4), &reply4, sizeof(reply4));
1011 if (con_status != B_OK) {
1012 ERROR("BMediaRoster::Connect: aborting after "
1013 "BBufferConsumer::Connected, status = %#" B_PRIx32 "\n",
1014 con_status);
1015 // we do NOT return here!
1017 // con_status contains the status code to be supplied to
1018 // BBufferProducer::Connect's status argument
1019 // reply4.input contains the media_input that describes the connection
1020 // from the consumer point of view
1022 // BBufferProducer::Connect
1023 producer_connect_request request5;
1024 producer_connect_reply reply5;
1026 PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::Connect with "
1027 "format ", reply4.input.format);
1029 request5.error = con_status;
1030 request5.source = reply3.out_source;
1031 request5.destination = reply4.input.destination;
1032 request5.format = reply4.input.format;
1033 strcpy(request5.name, reply4.input.name);
1034 rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5,
1035 sizeof(request5), &reply5, sizeof(reply5));
1036 if (con_status != B_OK) {
1037 ERROR("BMediaRoster::Connect: aborted\n");
1038 return con_status;
1040 if (rv != B_OK) {
1041 ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect()"
1042 ", status = %#" B_PRIx32 "\n", rv);
1043 return rv;
1045 // reply5.name contains the name assigned to the connection by the producer
1047 // initilize connection info
1048 *io_format = reply4.input.format;
1049 *out_input = reply4.input;
1050 out_output->node = sourcenode;
1051 out_output->source = reply4.input.source;
1052 out_output->destination = reply4.input.destination;
1053 out_output->format = reply4.input.format;
1054 strcpy(out_output->name, reply5.name);
1056 // the connection is now made
1057 PRINT_FORMAT(" format", *io_format);
1058 PRINT_INPUT(" input", *out_input);
1059 PRINT_OUTPUT(" output", *out_output);
1061 // TODO: register connection with server
1062 // TODO: we should just send a notification, instead of republishing all
1063 // endpoints
1064 List<media_output> outlist;
1065 List<media_input> inlist;
1066 if (MediaRosterEx(this)->GetAllOutputs(out_output->node , &outlist) == B_OK)
1067 MediaRosterEx(this)->PublishOutputs(out_output->node , &outlist);
1068 if (MediaRosterEx(this)->GetAllInputs(out_input->node , &inlist) == B_OK)
1069 MediaRosterEx(this)->PublishInputs(out_input->node, &inlist);
1071 // TODO: if (mute) BBufferProducer::EnableOutput(false)
1072 if (in_flags & B_CONNECT_MUTED) {
1075 // send a notification
1076 BPrivate::media::notifications::ConnectionMade(*out_input, *out_output,
1077 *io_format);
1079 return B_OK;
1083 status_t
1084 BMediaRoster::Disconnect(media_node_id source_nodeid,
1085 const media_source& source, media_node_id destination_nodeid,
1086 const media_destination& destination)
1088 CALLED();
1089 if (IS_INVALID_NODEID(source_nodeid)) {
1090 ERROR("BMediaRoster::Disconnect: source media_node_id invalid\n");
1091 return B_MEDIA_BAD_SOURCE;
1093 if (IS_INVALID_NODEID(destination_nodeid)) {
1094 ERROR("BMediaRoster::Disconnect: destination media_node_id invalid\n");
1095 return B_MEDIA_BAD_DESTINATION;
1097 if (IS_INVALID_SOURCE(source)) {
1098 ERROR("BMediaRoster::Disconnect: media_source invalid\n");
1099 return B_MEDIA_BAD_SOURCE;
1101 if (IS_INVALID_DESTINATION(destination)) {
1102 ERROR("BMediaRoster::Disconnect: media_destination invalid\n");
1103 return B_MEDIA_BAD_DESTINATION;
1106 producer_disconnect_request request2;
1107 producer_disconnect_reply reply2;
1108 consumer_disconnected_request request1;
1109 consumer_disconnected_reply reply1;
1110 status_t rv1, rv2;
1112 // TODO: we should ask the server if this connection really exists
1114 request1.source = source;
1115 request1.destination = destination;
1116 request2.source = source;
1117 request2.destination = destination;
1119 rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1,
1120 sizeof(request1), &reply1, sizeof(reply1));
1121 rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2,
1122 sizeof(request2), &reply2, sizeof(reply2));
1124 // TODO: unregister connection with server
1125 // TODO: we should just send a notification, instead of republishing all
1126 // endpoints
1127 List<media_output> outlist;
1128 List<media_input> inlist;
1129 media_node sourcenode;
1130 media_node destnode;
1131 if (GetNodeFor(source_nodeid, &sourcenode) == B_OK) {
1132 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) {
1133 ERROR("BMediaRoster::Disconnect: source_nodeid %" B_PRId32
1134 " is not a B_BUFFER_PRODUCER\n", source_nodeid);
1136 if (MediaRosterEx(this)->GetAllOutputs(sourcenode , &outlist) == B_OK)
1137 MediaRosterEx(this)->PublishOutputs(sourcenode , &outlist);
1138 ReleaseNode(sourcenode);
1139 } else {
1140 ERROR("BMediaRoster::Disconnect: GetNodeFor source_nodeid %" B_PRId32
1141 " failed\n", source_nodeid);
1143 if (GetNodeFor(destination_nodeid, &destnode) == B_OK) {
1144 if (!(destnode.kind & B_BUFFER_CONSUMER)) {
1145 ERROR("BMediaRoster::Disconnect: destination_nodeid %" B_PRId32
1146 " is not a B_BUFFER_CONSUMER\n", destination_nodeid);
1148 if (MediaRosterEx(this)->GetAllInputs(destnode , &inlist) == B_OK)
1149 MediaRosterEx(this)->PublishInputs(destnode, &inlist);
1150 ReleaseNode(destnode);
1151 } else {
1152 ERROR("BMediaRoster::Disconnect: GetNodeFor destination_nodeid %"
1153 B_PRId32 " failed\n", destination_nodeid);
1156 // send a notification
1157 BPrivate::media::notifications::ConnectionBroken(source, destination);
1159 return rv1 != B_OK || rv2 != B_OK ? B_ERROR : B_OK;
1163 status_t
1164 BMediaRoster::Disconnect(const media_output& output, const media_input& input)
1166 if (IS_INVALID_NODEID(output.node.node)) {
1167 printf("BMediaRoster::Disconnect: output.node.node %" B_PRId32
1168 " invalid\n", output.node.node);
1169 return B_MEDIA_BAD_SOURCE;
1171 if (IS_INVALID_NODEID(input.node.node)) {
1172 printf("BMediaRoster::Disconnect: input.node.node %" B_PRId32
1173 " invalid\n", input.node.node);
1174 return B_MEDIA_BAD_DESTINATION;
1176 if (!(output.node.kind & B_BUFFER_PRODUCER)) {
1177 printf("BMediaRoster::Disconnect: output.node.kind 0x%" B_PRIx32
1178 " is no B_BUFFER_PRODUCER\n", output.node.kind);
1179 return B_MEDIA_BAD_SOURCE;
1181 if (!(input.node.kind & B_BUFFER_CONSUMER)) {
1182 printf("BMediaRoster::Disconnect: input.node.kind 0x%" B_PRIx32
1183 " is no B_BUFFER_PRODUCER\n", input.node.kind);
1184 return B_MEDIA_BAD_DESTINATION;
1186 if (input.source.port != output.source.port) {
1187 printf("BMediaRoster::Disconnect: input.source.port %" B_PRId32
1188 " doesn't match output.source.port %" B_PRId32 "\n",
1189 input.source.port, output.source.port);
1190 return B_MEDIA_BAD_SOURCE;
1192 if (input.source.id != output.source.id) {
1193 printf("BMediaRoster::Disconnect: input.source.id %" B_PRId32
1194 " doesn't match output.source.id %" B_PRId32 "\n", input.source.id,
1195 output.source.id);
1196 return B_MEDIA_BAD_SOURCE;
1198 if (input.destination.port != output.destination.port) {
1199 printf("BMediaRoster::Disconnect: input.destination.port %" B_PRId32
1200 " doesn't match output.destination.port %" B_PRId32 "\n",
1201 input.destination.port, output.destination.port);
1202 return B_MEDIA_BAD_DESTINATION;
1204 if (input.destination.id != output.destination.id) {
1205 printf("BMediaRoster::Disconnect: input.destination.id %" B_PRId32
1206 " doesn't match output.destination.id %" B_PRId32 "\n",
1207 input.destination.id, output.destination.id);
1208 return B_MEDIA_BAD_DESTINATION;
1211 return Disconnect(output.node.node, output.source, input.node.node,
1212 input.destination);
1216 status_t
1217 BMediaRoster::StartNode(const media_node& node, bigtime_t atPerformanceTime)
1219 CALLED();
1220 if (node.node <= 0)
1221 return B_MEDIA_BAD_NODE;
1223 TRACE("BMediaRoster::StartNode, node %" B_PRId32 ", at perf %" B_PRId64
1224 "\n", node.node, atPerformanceTime);
1226 node_start_command command;
1227 command.performance_time = atPerformanceTime;
1229 return SendToPort(node.port, NODE_START, &command, sizeof(command));
1233 status_t
1234 BMediaRoster::StopNode(const media_node& node, bigtime_t atPerformanceTime,
1235 bool immediate)
1237 CALLED();
1238 if (IS_INVALID_NODE(node))
1239 return B_MEDIA_BAD_NODE;
1241 TRACE("BMediaRoster::StopNode, node %" B_PRId32 ", at perf %" B_PRId64
1242 " %s\n", node.node, atPerformanceTime, immediate ? "NOW" : "");
1244 node_stop_command command;
1245 command.performance_time = atPerformanceTime;
1246 command.immediate = immediate;
1248 return SendToPort(node.port, NODE_STOP, &command, sizeof(command));
1252 status_t
1253 BMediaRoster::SeekNode(const media_node& node, bigtime_t toMediaTime,
1254 bigtime_t atPerformanceTime)
1256 CALLED();
1257 if (IS_INVALID_NODE(node))
1258 return B_MEDIA_BAD_NODE;
1260 TRACE("BMediaRoster::SeekNode, node %" B_PRId32 ", at perf %" B_PRId64
1261 ", to perf %" B_PRId64 "\n", node.node, atPerformanceTime, toMediaTime);
1263 node_seek_command command;
1264 command.media_time = toMediaTime;
1265 command.performance_time = atPerformanceTime;
1267 return SendToPort(node.port, NODE_SEEK, &command, sizeof(command));
1271 status_t
1272 BMediaRoster::StartTimeSource(const media_node& node, bigtime_t atRealTime)
1274 CALLED();
1275 if (IS_SYSTEM_TIMESOURCE(node)) {
1276 // TODO: debug this
1277 //ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is system timesource\n", node.node);
1278 return B_OK;
1280 // if (IS_SHADOW_TIMESOURCE(node)) {
1281 // // TODO: debug this
1282 // ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is shadow timesource\n", node.node);
1283 // return B_OK;
1284 // }
1285 if (IS_INVALID_NODE(node)) {
1286 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " invalid\n",
1287 node.node);
1288 return B_MEDIA_BAD_NODE;
1290 if ((node.kind & B_TIME_SOURCE) == 0) {
1291 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32
1292 " is no timesource\n", node.node);
1293 return B_MEDIA_BAD_NODE;
1296 TRACE("BMediaRoster::StartTimeSource, node %" B_PRId32 ", at real %"
1297 B_PRId64 "\n", node.node, atRealTime);
1299 BTimeSource::time_source_op_info msg;
1300 msg.op = BTimeSource::B_TIMESOURCE_START;
1301 msg.real_time = atRealTime;
1303 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1307 status_t
1308 BMediaRoster::StopTimeSource(const media_node& node, bigtime_t atRealTime,
1309 bool immediate)
1311 CALLED();
1312 if (IS_SYSTEM_TIMESOURCE(node)) {
1313 // TODO: debug this
1314 //ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node);
1315 return B_OK;
1317 // if (IS_SHADOW_TIMESOURCE(node)) {
1318 // // TODO: debug this
1319 // ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node);
1320 // return B_OK;
1321 // }
1322 if (IS_INVALID_NODE(node)) {
1323 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " invalid\n",
1324 node.node);
1325 return B_MEDIA_BAD_NODE;
1327 if ((node.kind & B_TIME_SOURCE) == 0) {
1328 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " is no "
1329 "timesource\n", node.node);
1330 return B_MEDIA_BAD_NODE;
1333 TRACE("BMediaRoster::StopTimeSource, node %" B_PRId32 ", at real %" B_PRId64
1334 " %s\n", node.node, atRealTime, immediate ? "NOW" : "");
1336 BTimeSource::time_source_op_info msg;
1337 msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY
1338 : BTimeSource::B_TIMESOURCE_STOP;
1339 msg.real_time = atRealTime;
1341 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1345 status_t
1346 BMediaRoster::SeekTimeSource(const media_node& node,
1347 bigtime_t toPerformanceTime, bigtime_t atRealTime)
1349 CALLED();
1350 if (IS_SYSTEM_TIMESOURCE(node)) {
1351 // TODO: debug this
1352 // ERROR("BMediaRoster::SeekTimeSource node %ld is system timesource\n", node.node);
1353 // you can't seek the system time source, but
1354 // returning B_ERROR would break StampTV
1355 return B_OK;
1357 // if (IS_SHADOW_TIMESOURCE(node)) {
1358 // // TODO: debug this
1359 // ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node);
1360 // return B_OK;
1361 // }
1362 if (IS_INVALID_NODE(node)) {
1363 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32 " invalid\n",
1364 node.node);
1365 return B_MEDIA_BAD_NODE;
1367 if ((node.kind & B_TIME_SOURCE) == 0) {
1368 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32
1369 " is no timesource\n", node.node);
1370 return B_MEDIA_BAD_NODE;
1373 TRACE("BMediaRoster::SeekTimeSource, node %" B_PRId32 ", at real %" B_PRId64
1374 ", to perf %" B_PRId64 "\n", node.node, atRealTime, toPerformanceTime);
1376 BTimeSource::time_source_op_info msg;
1377 msg.op = BTimeSource::B_TIMESOURCE_SEEK;
1378 msg.real_time = atRealTime;
1379 msg.performance_time = toPerformanceTime;
1381 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1385 status_t
1386 BMediaRoster::SyncToNode(const media_node& node, bigtime_t atTime,
1387 bigtime_t timeout)
1389 TRACE("BMediaRoster::SyncToNode, node %" B_PRId32 ", at real %" B_PRId64
1390 ", at timeout %" B_PRId64 "\n", node.node, atTime, timeout);
1391 if (IS_INVALID_NODE(node))
1392 return B_MEDIA_BAD_NODE;
1394 port_id waitPort = create_port(1, "SyncToNode wait port");
1395 if (waitPort < B_OK)
1396 return waitPort;
1398 node_sync_to_request request;
1399 node_sync_to_reply reply;
1400 request.performance_time = atTime;
1401 request.port = waitPort;
1403 status_t status = QueryPort(node.port, NODE_SYNC_TO, &request,
1404 sizeof(request), &reply, sizeof(reply));
1406 if (status == B_OK) {
1407 ssize_t readSize = read_port_etc(waitPort, NULL, &status,
1408 sizeof(status), B_TIMEOUT, timeout);
1409 if (readSize < 0)
1410 status = readSize;
1412 close_port(waitPort);
1413 delete_port(waitPort);
1414 return status;
1418 status_t
1419 BMediaRoster::SetRunModeNode(const media_node& node, BMediaNode::run_mode mode)
1421 TRACE("BMediaRoster::SetRunModeNode, node %" B_PRId32 ", mode %d\n",
1422 node.node, mode);
1423 if (IS_INVALID_NODE(node))
1424 return B_MEDIA_BAD_NODE;
1426 node_set_run_mode_command msg;
1427 msg.mode = mode;
1429 return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg));
1433 status_t
1434 BMediaRoster::PrerollNode(const media_node& node)
1436 CALLED();
1437 if (IS_INVALID_NODE(node))
1438 return B_MEDIA_BAD_NODE;
1440 char dummy;
1441 return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy));
1445 status_t
1446 BMediaRoster::RollNode(const media_node& node, bigtime_t startPerformance,
1447 bigtime_t stopPerformance, bigtime_t atMediaTime)
1449 CALLED();
1450 if (IS_INVALID_NODE(node))
1451 return B_MEDIA_BAD_NODE;
1453 TRACE("BMediaRoster::RollNode, node %" B_PRId32 ", at start perf %"
1454 B_PRId64 ", at stop perf %" B_PRId64 ", at media time %"
1455 B_PRId64 "\n", node.node, startPerformance,
1456 stopPerformance, atMediaTime);
1458 node_roll_command command;
1459 command.start_performance_time = startPerformance;
1460 command.stop_performance_time = stopPerformance;
1461 command.seek_media_time = atMediaTime;
1463 return write_port(node.port, NODE_ROLL, &command, sizeof(command));
1467 status_t
1468 BMediaRoster::SetProducerRunModeDelay(const media_node& node,
1469 bigtime_t delay, BMediaNode::run_mode mode)
1471 TRACE("BMediaRoster::SetProducerRunModeDelay, node %" B_PRId32 ", delay %"
1472 B_PRId64 ", mode %d\n", node.node, delay, mode);
1473 if (IS_INVALID_NODE(node))
1474 return B_MEDIA_BAD_NODE;
1475 if ((node.kind & B_BUFFER_PRODUCER) == 0)
1476 return B_MEDIA_BAD_NODE;
1478 producer_set_run_mode_delay_command command;
1479 command.mode = mode;
1480 command.delay = delay;
1482 return SendToPort(node.port, PRODUCER_SET_RUN_MODE_DELAY, &command,
1483 sizeof(command));
1487 status_t
1488 BMediaRoster::SetProducerRate(const media_node& producer, int32 numer,
1489 int32 denom)
1491 CALLED();
1492 if (IS_INVALID_NODE(producer))
1493 return B_MEDIA_BAD_NODE;
1494 if ((producer.kind & B_BUFFER_PRODUCER) == 0)
1495 return B_MEDIA_BAD_NODE;
1497 producer_set_play_rate_request request;
1498 request.numer = numer;
1499 request.denom = denom;
1500 status_t status = write_port(producer.node, PRODUCER_SET_PLAY_RATE,
1501 &request, sizeof(request));
1502 if (status != B_OK)
1503 return status;
1505 producer_set_play_rate_reply reply;
1506 int32 code;
1507 status = read_port(request.reply_port, &code, &reply, sizeof(reply));
1509 return status < B_OK ? status : reply.result;
1513 /*! Nodes will have available inputs/outputs as long as they are capable
1514 of accepting more connections. The node may create an additional
1515 output or input as the currently available is taken into usage.
1517 status_t
1518 BMediaRoster::GetLiveNodeInfo(const media_node& node,
1519 live_node_info* out_live_info)
1521 CALLED();
1522 if (out_live_info == NULL)
1523 return B_BAD_VALUE;
1524 if (IS_INVALID_NODE(node))
1525 return B_MEDIA_BAD_NODE;
1527 server_get_live_node_info_request request;
1528 server_get_live_node_info_reply reply;
1529 status_t rv;
1531 request.node = node;
1533 rv = QueryServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request),
1534 &reply, sizeof(reply));
1535 if (rv != B_OK)
1536 return rv;
1538 *out_live_info = reply.live_info;
1539 return B_OK;
1543 status_t
1544 BMediaRoster::GetLiveNodes(live_node_info* liveNodes, int32* _totalCount,
1545 const media_format* hasInput, const media_format* hasOutput,
1546 const char* name, uint64 nodeKinds)
1548 CALLED();
1549 if (liveNodes == NULL || _totalCount == NULL || *_totalCount <= 0)
1550 return B_BAD_VALUE;
1552 // TODO: we also support the wildcard search as GetDormantNodes does.
1553 // This needs to be documented
1555 server_get_live_nodes_request request;
1556 request.team = BPrivate::current_team();
1558 request.max_count = *_totalCount;
1559 request.has_input = hasInput != NULL;
1560 if (hasInput != NULL) {
1561 // TODO: we should not make a flat copy of media_format
1562 request.input_format = *hasInput;
1564 request.has_output = hasOutput != NULL;
1565 if (hasOutput != NULL) {
1566 // TODO: we should not make a flat copy of media_format
1567 request.output_format = *hasOutput;
1569 request.has_name = name != NULL;
1570 if (name != NULL)
1571 strlcpy(request.name, name, sizeof(request.name));
1572 request.require_kinds = nodeKinds;
1574 server_get_live_nodes_reply reply;
1575 status_t status = QueryServer(SERVER_GET_LIVE_NODES, &request,
1576 sizeof(request), &reply, sizeof(reply));
1577 if (status != B_OK) {
1578 ERROR("BMediaRoster::GetLiveNodes failed querying server: %s\n",
1579 strerror(status));
1580 *_totalCount = 0;
1581 return status;
1584 const live_node_info* info;
1585 if (reply.area >= 0)
1586 info = (live_node_info*)reply.address;
1587 else
1588 info = reply.live_info;
1590 for (int32 i = 0; i < reply.count; i++)
1591 liveNodes[i] = info[i];
1593 if (reply.area >= 0)
1594 delete_area(reply.area);
1596 *_totalCount = reply.count;
1597 return B_OK;
1601 status_t
1602 BMediaRoster::GetFreeInputsFor(const media_node& node,
1603 media_input * out_free_inputs, int32 buf_num_inputs,
1604 int32 * out_total_count, media_type filter_type)
1606 CALLED();
1607 if (IS_INVALID_NODE(node)) {
1608 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %"
1609 B_PRId32 " invalid\n", node.node, node.port);
1610 return B_MEDIA_BAD_NODE;
1612 if ((node.kind & B_BUFFER_CONSUMER) == 0) {
1613 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %"
1614 B_PRId32 " is not a consumer\n", node.node, node.port);
1615 return B_MEDIA_BAD_NODE;
1617 if (out_free_inputs == NULL || out_total_count == NULL)
1618 return B_BAD_VALUE;
1620 List<media_input> list;
1621 media_input *input;
1622 status_t rv;
1624 *out_total_count = 0;
1626 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1627 if (B_OK != rv)
1628 return rv;
1630 PRINT(4, "BMediaRoster::GetFreeInputsFor node %" B_PRId32 ", max %" B_PRId32
1631 ", filter-type %" B_PRId32 "\n", node.node, buf_num_inputs,
1632 filter_type);
1634 int32 i;
1635 for (i = 0, list.Rewind(); list.GetNext(&input);) {
1636 if (filter_type != B_MEDIA_UNKNOWN_TYPE
1637 && filter_type != input->format.type) {
1638 // media_type used, but doesn't match
1639 continue;
1641 if (input->source != media_source::null) {
1642 // consumer source already connected
1643 continue;
1646 out_free_inputs[i] = *input;
1647 *out_total_count += 1;
1648 buf_num_inputs -= 1;
1649 #if DEBUG >= 3
1650 PRINT_OUTPUT(" input", out_free_inputs[i]);
1651 #endif
1652 if (buf_num_inputs == 0)
1653 break;
1654 i++;
1657 MediaRosterEx(this)->PublishInputs(node, &list);
1658 return B_OK;
1662 status_t
1663 BMediaRoster::GetConnectedInputsFor(const media_node& node,
1664 media_input* out_active_inputs, int32 buf_num_inputs,
1665 int32* out_total_count)
1667 CALLED();
1668 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1669 return B_MEDIA_BAD_NODE;
1670 if (out_active_inputs == NULL || out_total_count == NULL)
1671 return B_BAD_VALUE;
1673 List<media_input> list;
1674 media_input *input;
1675 status_t rv;
1677 *out_total_count = 0;
1679 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1680 if (B_OK != rv)
1681 return rv;
1683 PRINT(4, "BMediaRoster::GetConnectedInputsFor node %" B_PRId32 ", max %"
1684 B_PRId32 "\n", node.node, buf_num_inputs);
1686 int32 i;
1687 for (i = 0, list.Rewind(); list.GetNext(&input);) {
1688 if (input->source == media_source::null)
1689 continue; // consumer source not connected
1690 out_active_inputs[i] = *input;
1691 *out_total_count += 1;
1692 buf_num_inputs -= 1;
1693 #if DEBUG >= 3
1694 PRINT_OUTPUT(" input ", out_active_inputs[i]);
1695 #endif
1696 if (buf_num_inputs == 0)
1697 break;
1698 i++;
1701 MediaRosterEx(this)->PublishInputs(node, &list);
1702 return B_OK;
1706 status_t
1707 BMediaRoster::GetAllInputsFor(const media_node& node, media_input* out_inputs,
1708 int32 buf_num_inputs, int32* out_total_count)
1710 CALLED();
1711 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1712 return B_MEDIA_BAD_NODE;
1713 if (out_inputs == NULL || out_total_count == NULL)
1714 return B_BAD_VALUE;
1716 List<media_input> list;
1717 media_input *input;
1718 status_t rv;
1720 *out_total_count = 0;
1722 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1723 if (B_OK != rv)
1724 return rv;
1726 PRINT(4, "BMediaRoster::GetAllInputsFor node %" B_PRId32 ", max %" B_PRId32
1727 "\n", node.node, buf_num_inputs);
1729 int32 i;
1730 for (i = 0, list.Rewind(); list.GetNext(&input); i++) {
1731 out_inputs[i] = *input;
1732 *out_total_count += 1;
1733 buf_num_inputs -= 1;
1734 #if DEBUG >= 3
1735 PRINT_OUTPUT(" input ", out_inputs[i]);
1736 #endif
1737 if (buf_num_inputs == 0)
1738 break;
1741 MediaRosterEx(this)->PublishInputs(node, &list);
1742 return B_OK;
1746 status_t
1747 BMediaRoster::GetFreeOutputsFor(const media_node& node,
1748 media_output* out_free_outputs, int32 buf_num_outputs,
1749 int32* out_total_count, media_type filter_type)
1751 CALLED();
1752 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1753 return B_MEDIA_BAD_NODE;
1754 if (out_free_outputs == NULL || out_total_count == NULL)
1755 return B_BAD_VALUE;
1757 List<media_output> list;
1758 media_output *output;
1759 status_t rv;
1761 *out_total_count = 0;
1763 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1764 if (B_OK != rv)
1765 return rv;
1767 PRINT(4, "BMediaRoster::GetFreeOutputsFor node %" B_PRId32 ", max %"
1768 B_PRId32 ", filter-type %" B_PRId32 "\n", node.node, buf_num_outputs,
1769 filter_type);
1771 int32 i;
1772 for (i = 0, list.Rewind(); list.GetNext(&output);) {
1773 if (filter_type != B_MEDIA_UNKNOWN_TYPE
1774 && filter_type != output->format.type) {
1775 // media_type used, but doesn't match
1776 continue;
1778 if (output->destination != media_destination::null) {
1779 // producer destination already connected
1780 continue;
1783 out_free_outputs[i] = *output;
1784 *out_total_count += 1;
1785 buf_num_outputs -= 1;
1786 #if DEBUG >= 3
1787 PRINT_OUTPUT(" output ", out_free_outputs[i]);
1788 #endif
1789 if (buf_num_outputs == 0)
1790 break;
1791 i++;
1794 MediaRosterEx(this)->PublishOutputs(node, &list);
1795 return B_OK;
1799 status_t
1800 BMediaRoster::GetConnectedOutputsFor(const media_node& node,
1801 media_output* out_active_outputs, int32 buf_num_outputs,
1802 int32* out_total_count)
1804 CALLED();
1805 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1806 return B_MEDIA_BAD_NODE;
1807 if (out_active_outputs == NULL || out_total_count == NULL)
1808 return B_BAD_VALUE;
1810 List<media_output> list;
1811 media_output *output;
1812 status_t rv;
1814 *out_total_count = 0;
1816 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1817 if (B_OK != rv)
1818 return rv;
1820 PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %" B_PRId32 ", max %"
1821 B_PRId32 "\n", node.node, buf_num_outputs);
1823 int32 i;
1824 for (i = 0, list.Rewind(); list.GetNext(&output);) {
1825 if (output->destination == media_destination::null) {
1826 // producer destination not connected
1827 continue;
1829 out_active_outputs[i] = *output;
1830 *out_total_count += 1;
1831 buf_num_outputs -= 1;
1832 #if DEBUG >= 3
1833 PRINT_OUTPUT(" output ", out_active_outputs[i]);
1834 #endif
1835 if (buf_num_outputs == 0)
1836 break;
1837 i++;
1840 MediaRosterEx(this)->PublishOutputs(node, &list);
1841 return B_OK;
1845 status_t
1846 BMediaRoster::GetAllOutputsFor(const media_node& node,
1847 media_output* out_outputs, int32 buf_num_outputs, int32* out_total_count)
1849 CALLED();
1850 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1851 return B_MEDIA_BAD_NODE;
1852 if (out_outputs == NULL || out_total_count == NULL)
1853 return B_BAD_VALUE;
1855 List<media_output> list;
1856 media_output *output;
1857 status_t rv;
1859 *out_total_count = 0;
1861 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1862 if (B_OK != rv)
1863 return rv;
1865 PRINT(4, "BMediaRoster::GetAllOutputsFor node %" B_PRId32 ", max %" B_PRId32
1866 "\n", node.node, buf_num_outputs);
1868 int32 i;
1869 for (i = 0, list.Rewind(); list.GetNext(&output); i++) {
1870 out_outputs[i] = *output;
1871 *out_total_count += 1;
1872 buf_num_outputs -= 1;
1873 #if DEBUG >= 3
1874 PRINT_OUTPUT(" output ", out_outputs[i]);
1875 #endif
1876 if (buf_num_outputs == 0)
1877 break;
1880 MediaRosterEx(this)->PublishOutputs(node, &list);
1881 return B_OK;
1885 status_t
1886 BMediaRoster::StartWatching(const BMessenger& where)
1888 CALLED();
1889 if (!where.IsValid()) {
1890 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1891 return B_BAD_VALUE;
1893 return BPrivate::media::notifications::Register(where, media_node::null,
1894 B_MEDIA_WILDCARD);
1898 status_t
1899 BMediaRoster::StartWatching(const BMessenger & where, int32 notificationType)
1901 CALLED();
1902 if (!where.IsValid()) {
1903 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1904 return B_BAD_VALUE;
1906 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
1907 notificationType)) {
1908 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1909 return B_BAD_VALUE;
1912 // NOTE: we support only explicitly B_MEDIA_SERVER_STARTED/QUIT
1913 // notifications. This should be cleared in documentation.
1915 return BPrivate::media::notifications::Register(where, media_node::null,
1916 notificationType);
1920 status_t
1921 BMediaRoster::StartWatching(const BMessenger& where, const media_node& node,
1922 int32 notificationType)
1924 CALLED();
1925 if (!where.IsValid()) {
1926 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1927 return B_BAD_VALUE;
1929 if (IS_INVALID_NODE(node)) {
1930 ERROR("BMediaRoster::StartWatching: node invalid!\n");
1931 return B_MEDIA_BAD_NODE;
1933 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
1934 notificationType)) {
1935 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1936 return B_BAD_VALUE;
1938 return BPrivate::media::notifications::Register(where, node,
1939 notificationType);
1943 status_t
1944 BMediaRoster::StopWatching(const BMessenger& where)
1946 CALLED();
1947 // messenger may already be invalid, so we don't check this
1948 return BPrivate::media::notifications::Unregister(where, media_node::null,
1949 B_MEDIA_WILDCARD);
1953 status_t
1954 BMediaRoster::StopWatching(const BMessenger& where, int32 notificationType)
1956 CALLED();
1957 // messenger may already be invalid, so we don't check this
1958 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
1959 notificationType)) {
1960 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1961 return B_BAD_VALUE;
1963 return BPrivate::media::notifications::Unregister(where, media_node::null,
1964 notificationType);
1968 status_t
1969 BMediaRoster::StopWatching(const BMessenger& where, const media_node& node,
1970 int32 notificationType)
1972 CALLED();
1973 // messenger may already be invalid, so we don't check this
1974 if (IS_INVALID_NODE(node)) {
1975 ERROR("BMediaRoster::StopWatching: node invalid!\n");
1976 return B_MEDIA_BAD_NODE;
1978 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
1979 notificationType)) {
1980 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1981 return B_BAD_VALUE;
1983 return BPrivate::media::notifications::Unregister(where, node,
1984 notificationType);
1988 status_t
1989 BMediaRoster::RegisterNode(BMediaNode* node)
1991 CALLED();
1992 // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too)
1993 return MediaRosterEx(this)->RegisterNode(node, -1, 0);
1997 status_t
1998 BMediaRosterEx::RegisterNode(BMediaNode* node, media_addon_id addOnID,
1999 int32 flavorID)
2001 CALLED();
2002 if (node == NULL)
2003 return B_BAD_VALUE;
2005 // some sanity check
2006 // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here.
2007 // Perhaps we don't need it.
2008 DEBUG_ONLY(
2009 int32 testFlavorID;
2010 BMediaAddOn* addon = node->AddOn(&testFlavorID);
2012 ASSERT(addOnID == (addon != NULL ? addon->AddonID() : -1));
2013 // ASSERT(flavorID == testFlavorID);
2016 server_register_node_request request;
2017 server_register_node_reply reply;
2019 request.add_on_id = addOnID;
2020 request.flavor_id = flavorID;
2021 strcpy(request.name, node->Name());
2022 request.kinds = node->Kinds();
2023 request.port = node->ControlPort();
2024 request.team = BPrivate::current_team();
2025 request.timesource_id = node->fTimeSourceID;
2027 TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port "
2028 "%" B_PRId32 ", kinds 0x%" B_PRIx64 ", team %" B_PRId32 ", name '%s'\n",
2029 request.port, request.kinds, request.team, request.name);
2031 status_t status = QueryServer(SERVER_REGISTER_NODE, &request,
2032 sizeof(request), &reply, sizeof(reply));
2033 if (status != B_OK) {
2034 ERROR("BMediaRoster::RegisterNode: failed to register node %s: %s\n",
2035 node->Name(), strerror(status));
2036 return status;
2039 TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE "
2040 "finished\n");
2042 // we are a friend class of BMediaNode and initialize this member variable
2043 node->fNodeID = reply.node_id;
2044 ASSERT(reply.node_id == node->Node().node);
2045 ASSERT(reply.node_id == node->ID());
2047 // call the callback
2048 node->NodeRegistered();
2050 TRACE("BMediaRoster::RegisterNode: NodeRegistered callback finished\n");
2052 // if the BMediaNode also inherits from BTimeSource, we need to call
2053 // BTimeSource::FinishCreate()
2054 if ((node->Kinds() & B_TIME_SOURCE) != 0) {
2055 if (BTimeSource* timeSource = dynamic_cast<BTimeSource*>(node))
2056 timeSource->FinishCreate();
2059 TRACE("BMediaRoster::RegisterNode: publishing inputs/outputs\n");
2061 // register existing inputs and outputs with the
2062 // media_server, this allows GetLiveNodes() to work
2063 // with created, but unconnected nodes.
2064 // The node control loop might not be running, or might deadlock
2065 // if we send a message and wait for a reply here.
2066 // We have a pointer to the node, and thus call the functions directly
2068 if ((node->Kinds() & B_BUFFER_PRODUCER) != 0) {
2069 if (BBufferProducer* producer = dynamic_cast<BBufferProducer*>(node)) {
2070 List<media_output> list;
2071 if (GetAllOutputs(producer, &list) == B_OK)
2072 PublishOutputs(node->Node(), &list);
2075 if ((node->Kinds() & B_BUFFER_CONSUMER) != 0) {
2076 if (BBufferConsumer* consumer = dynamic_cast<BBufferConsumer*>(node)) {
2077 List<media_input> list;
2078 if (GetAllInputs(consumer, &list) == B_OK)
2079 PublishInputs(node->Node(), &list);
2083 TRACE("BMediaRoster::RegisterNode: sending NodesCreated\n");
2085 BPrivate::media::notifications::NodesCreated(&reply.node_id, 1);
2087 TRACE("BMediaRoster::RegisterNode: finished\n");
2090 TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld,
2091 addon %ld, flavor %ld\n", node->Name(), node->ID(), addOnID, flavorID);
2092 TRACE("BMediaRoster::RegisterNode: node this %p\n", node);
2093 TRACE("BMediaRoster::RegisterNode: node fConsumerThis %p\n",
2094 node->fConsumerThis);
2095 TRACE("BMediaRoster::RegisterNode: node fProducerThis %p\n",
2096 node->fProducerThis);
2097 TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n",
2098 node->fFileInterfaceThis);
2099 TRACE("BMediaRoster::RegisterNode: node fControllableThis %p\n",
2100 node->fControllableThis);
2101 TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis %p\n",
2102 node->fTimeSourceThis);
2104 return B_OK;
2108 status_t
2109 BMediaRoster::UnregisterNode(BMediaNode* node)
2111 CALLED();
2112 if (node == NULL)
2113 return B_BAD_VALUE;
2115 TRACE("BMediaRoster::UnregisterNode %ld (%p)\n", node->ID(), node);
2117 if ((node->fKinds & NODE_KIND_NO_REFCOUNTING) !=0) {
2118 TRACE("BMediaRoster::UnregisterNode, trying to unregister reference "
2119 "counting disabled timesource, node %ld, port %ld, team %ld\n",
2120 node->ID(), node->ControlPort(), BPrivate::current_team());
2121 return B_OK;
2123 if (node->ID() == NODE_UNREGISTERED_ID) {
2124 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2125 "'%s' already unregistered\n", node->ID(), node->Name());
2126 return B_OK;
2128 if (node->fRefCount != 0) {
2129 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2130 "'%s' has local reference count of %ld\n", node->ID(), node->Name(),
2131 node->fRefCount);
2132 // no return here, we continue and unregister!
2135 // Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node,
2136 // BMessage *config) if this node was instanciated by an add-on needs to
2137 // be done *somewhere*
2138 // We can't do it here because it is already to late (destructor of the node
2139 // might have been called).
2141 server_unregister_node_request request;
2142 request.node_id = node->ID();
2143 request.team = BPrivate::current_team();
2145 // send a notification
2146 BPrivate::media::notifications::NodesDeleted(&request.node_id, 1);
2148 server_unregister_node_reply reply;
2149 reply.add_on_id = -1;
2150 status_t status = QueryServer(SERVER_UNREGISTER_NODE, &request,
2151 sizeof(request), &reply, sizeof(reply));
2152 if (status != B_OK) {
2153 ERROR("BMediaRoster::UnregisterNode: failed to unregister node id %"
2154 B_PRId32 ", name '%s': %s\n", node->ID(), node->Name(),
2155 strerror(status));
2156 BMediaAddOn *addon = node->AddOn(&reply.flavor_id);
2157 if (addon != NULL)
2158 reply.add_on_id = addon->AddonID();
2161 if (reply.add_on_id != -1) {
2162 // TODO: this doesn't look right
2163 // Small problem here, we can't use DormantNodeManager::PutAddOn(), as
2164 // UnregisterNode() is called by a dormant node itself (by the
2165 // destructor).
2166 // The add-on that contains the node needs to remain in memory until the
2167 // destructor execution is finished.
2168 // DormantNodeManager::PutAddOnDelayed() will delay unloading.
2169 gDormantNodeManager->PutAddOnDelayed(reply.add_on_id);
2171 status = MediaRosterEx(this)->DecrementAddonFlavorInstancesCount(
2172 reply.add_on_id, reply.flavor_id);
2173 if (status != B_OK) {
2174 ERROR("BMediaRoster::UnregisterNode: "
2175 "DecrementAddonFlavorInstancesCount() failed\n");
2176 // this is really a problem, but we can't fail now
2180 // we are a friend class of BMediaNode and invalidate this member variable
2181 node->fNodeID = NODE_UNREGISTERED_ID;
2183 return status;
2187 //! Thread safe for multiple calls to Roster()
2188 /*static*/ BMediaRoster*
2189 BMediaRoster::Roster(status_t* out_error)
2191 static BLocker locker("BMediaRoster::Roster locker");
2192 locker.Lock();
2193 if (out_error)
2194 *out_error = B_OK;
2195 if (sDefaultInstance == NULL) {
2196 status_t err;
2197 sDefaultInstance = new (std::nothrow) BMediaRosterEx(&err);
2198 if (sDefaultInstance == NULL)
2199 err = B_NO_MEMORY;
2200 else if (err != B_OK) {
2201 if (sDefaultInstance) {
2202 sDefaultInstance->Lock();
2203 sDefaultInstance->Quit();
2204 sDefaultInstance = NULL;
2206 if (out_error)
2207 *out_error = err;
2210 locker.Unlock();
2211 return sDefaultInstance;
2215 /*static*/ BMediaRoster*
2216 BMediaRoster::CurrentRoster()
2218 return sDefaultInstance;
2222 status_t
2223 BMediaRoster::SetTimeSourceFor(media_node_id node, media_node_id time_source)
2225 CALLED();
2226 if (IS_INVALID_NODEID(node) || IS_INVALID_NODEID(time_source))
2227 return B_BAD_VALUE;
2229 media_node clone;
2230 // We need to get a clone of the node to have a port id
2231 status_t result = GetNodeFor(node, &clone);
2232 if (result == B_OK) {
2233 // We just send the request to set time_source-id as
2234 // timesource to the node, the NODE_SET_TIMESOURCE handler
2235 // code will do the real assignment.
2236 result = B_OK;
2237 node_set_timesource_command cmd;
2238 cmd.timesource_id = time_source;
2239 result = SendToPort(clone.port, NODE_SET_TIMESOURCE,
2240 &cmd, sizeof(cmd));
2241 if (result != B_OK) {
2242 ERROR("BMediaRoster::SetTimeSourceFor"
2243 "sending NODE_SET_TIMESOURCE failed, node id %"
2244 B_PRId32 "\n", clone.node);
2246 // We release the clone
2247 result = ReleaseNode(clone);
2248 if (result != B_OK) {
2249 ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed,"
2250 " node id %" B_PRId32 "\n", clone.node);
2252 } else {
2253 ERROR("BMediaRoster::SetTimeSourceFor GetCloneForID failed, "
2254 "node id %" B_PRId32 "\n", node);
2257 if (result == B_OK) {
2258 // Notify the server
2259 server_set_node_timesource_request request;
2260 server_set_node_timesource_reply reply;
2262 request.node_id = node;
2263 request.timesource_id = time_source;
2265 result = QueryServer(SERVER_SET_NODE_TIMESOURCE, &request,
2266 sizeof(request), &reply, sizeof(reply));
2267 if (result != B_OK) {
2268 ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE "
2269 "failed, node id %" B_PRId32 "\n", node);
2270 } else {
2271 TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %"
2272 B_PRId32 " OK\n", node, time_source);
2275 return result;
2279 status_t
2280 BMediaRoster::GetParameterWebFor(const media_node& node, BParameterWeb** _web)
2282 CALLED();
2283 if (_web == NULL)
2284 return B_BAD_VALUE;
2285 if (IS_INVALID_NODE(node))
2286 return B_MEDIA_BAD_NODE;
2287 if ((node.kind & B_CONTROLLABLE) == 0)
2288 return B_MEDIA_BAD_NODE;
2290 controllable_get_parameter_web_request request;
2291 controllable_get_parameter_web_reply reply;
2292 int32 requestsize[] = {B_PAGE_SIZE, 4 * B_PAGE_SIZE, 16 * B_PAGE_SIZE,
2293 64 * B_PAGE_SIZE, 128 * B_PAGE_SIZE, 256 * B_PAGE_SIZE, 0};
2294 int32 size;
2296 // TODO: it might be better to query the node for the (current) parameter
2297 // size first
2298 for (int i = 0; (size = requestsize[i]) != 0; i++) {
2299 status_t rv;
2300 area_id area;
2301 void *data;
2302 area = create_area("parameter web data", &data, B_ANY_ADDRESS, size,
2303 B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
2304 if (area < B_OK) {
2305 ERROR("BMediaRoster::GetParameterWebFor couldn't create area of "
2306 "size %" B_PRId32 "\n", size);
2307 return B_ERROR;
2309 request.max_size = size;
2310 request.area = area;
2311 rv = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_WEB, &request,
2312 sizeof(request), &reply, sizeof(reply));
2313 if (rv != B_OK) {
2314 ERROR("BMediaRoster::GetParameterWebFor "
2315 "CONTROLLABLE_GET_PARAMETER_WEB failed\n");
2316 delete_area(area);
2317 return B_ERROR;
2319 if (reply.size == 0) {
2320 // no parameter web available
2321 // TODO: should we return an error?
2322 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32
2323 " has no parameter web\n", node.node);
2324 *_web = new (std::nothrow) BParameterWeb();
2325 delete_area(area);
2326 return *_web != NULL ? B_OK : B_NO_MEMORY;
2328 if (reply.size > 0) {
2329 // we got a flattened parameter web!
2330 BParameterWeb* web = new (std::nothrow) BParameterWeb();
2331 if (web == NULL)
2332 rv = B_NO_MEMORY;
2333 else {
2334 rv = web->Unflatten(reply.code, data, reply.size);
2335 if (rv != B_OK) {
2336 ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, "
2337 "%s\n", strerror(rv));
2338 delete web;
2339 } else
2340 *_web = web;
2343 delete_area(area);
2344 return rv;
2346 delete_area(area);
2347 ASSERT(reply.size == -1);
2348 // parameter web data was too large
2349 // loop and try a larger size
2351 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32 " has no "
2352 "parameter web larger than %" B_PRId32 "\n", node.node, size);
2353 return B_ERROR;
2357 status_t
2358 BMediaRoster::StartControlPanel(const media_node& node, BMessenger* _messenger)
2360 CALLED();
2362 controllable_start_control_panel_request request;
2363 controllable_start_control_panel_reply reply;
2365 request.node = node;
2367 status_t rv;
2368 rv = QueryPort(node.port, CONTROLLABLE_START_CONTROL_PANEL, &request,
2369 sizeof(request), &reply, sizeof(reply));
2370 if (rv != B_OK)
2371 return rv;
2373 if (reply.team != -1 && _messenger != NULL)
2374 *_messenger = BMessenger(NULL, reply.team);
2376 return B_OK;
2380 status_t
2381 BMediaRoster::GetDormantNodes(dormant_node_info* _info, int32* _count,
2382 const media_format* hasInput, const media_format* hasOutput,
2383 const char* name, uint64 requireKinds, uint64 denyKinds)
2385 CALLED();
2386 if (_info == NULL || _count == NULL || *_count <= 0)
2387 return B_BAD_VALUE;
2389 server_get_dormant_nodes_request request;
2390 request.max_count = *_count;
2391 request.has_input = hasInput != NULL;
2392 if (hasInput != NULL) {
2393 // TODO: we should not make a flat copy of media_format
2394 request.input_format = *hasInput;
2396 request.has_output = hasOutput != NULL;
2397 if (hasOutput != NULL) {
2398 // TODO: we should not make a flat copy of media_format
2399 request.output_format = *hasOutput;
2402 request.has_name = name != NULL;
2403 if (name != NULL)
2404 strlcpy(request.name, name, sizeof(request.name));
2406 request.require_kinds = requireKinds;
2407 request.deny_kinds = denyKinds;
2409 server_get_dormant_nodes_reply reply;
2410 status_t status = QueryServer(SERVER_GET_DORMANT_NODES, &request,
2411 sizeof(request), &reply, sizeof(reply));
2412 if (status != B_OK)
2413 return status;
2415 *_count = reply.count;
2417 if (reply.count > 0) {
2418 int32 code;
2419 status = read_port(request.reply_port, &code, _info,
2420 reply.count * sizeof(dormant_node_info));
2421 if (status < B_OK)
2422 reply.result = status;
2425 return reply.result;
2429 /*! This function is used to do the real work of instantiating a dormant node.
2430 It is either called by the media_addon_server to instantiate a global node,
2431 or it gets called from BMediaRoster::InstantiateDormantNode() to create a
2432 local one.
2434 Checks concerning global/local are not done here.
2436 status_t
2437 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonID, int32 flavorID,
2438 team_id creator, media_node *_node)
2440 // This function is always called from the correct context, if the node
2441 // is supposed to be global, it is called from the media_addon_server.
2443 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
2444 // resides in the media_addon_server
2446 // RegisterNode() must be called for nodes instantiated from add-ons,
2447 // since the media kit warrants that it's done automatically.
2449 // addonID Indicates the ID number of the media add-on in which the
2450 // node resides.
2451 // flavorID Indicates the internal ID number that the add-on uses to
2452 // identify the flavor, this is the number that was published
2453 // by BMediaAddOn::GetFlavorAt() in the
2454 // flavor_info::internal_id field.
2455 // creator The creator team is -1 if nodes are created locally. If
2456 // created globally, it will contain (while called in
2457 // media_addon_server context) the team-id of the team that
2458 // requested the instantiation.
2460 TRACE("BMediaRosterEx::InstantiateDormantNode: addonID %" B_PRId32
2461 ", flavorID %" B_PRId32 "\n", addonID, flavorID);
2463 // Get flavor_info from the server
2464 dormant_flavor_info info;
2465 status_t rv;
2466 rv = GetDormantFlavorInfo(addonID, flavorID, &info);
2467 if (rv != B_OK) {
2468 ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get "
2469 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2470 B_PRId32 "\n", addonID, flavorID);
2471 return B_ERROR;
2474 ASSERT(info.internal_id == flavorID);
2476 // load the BMediaAddOn object
2477 BMediaAddOn* addon = gDormantNodeManager->GetAddOn(addonID);
2478 if (addon == NULL) {
2479 ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n");
2480 return B_ERROR;
2483 // Now we need to try to increment the use count of this addon flavor
2484 // in the server. This can fail if the total number instances of this
2485 // flavor is limited.
2486 rv = IncrementAddonFlavorInstancesCount(addonID, flavorID);
2487 if (rv != B_OK) {
2488 ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create "
2489 "more nodes for addon-id %" B_PRId32 ", flavor-id %" B_PRId32 "\n",
2490 addonID, flavorID);
2491 // Put the addon back into the pool
2492 gDormantNodeManager->PutAddOn(addonID);
2493 return B_ERROR;
2496 BMessage config;
2497 rv = LoadNodeConfiguration(addonID, flavorID, &config);
2498 if (rv != B_OK) {
2499 ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load "
2500 "configuration for addon-id %" B_PRId32 ", flavor-id %" B_PRId32
2501 "\n", addonID, flavorID);
2502 // do not return, this is a minor problem, not a reason to fail
2505 status_t status = B_OK;
2506 BMediaNode* node = addon->InstantiateNodeFor(&info, &config, &status);
2507 if (node == NULL) {
2508 ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor "
2509 "failed\n");
2511 // Put the addon back into the pool
2512 gDormantNodeManager->PutAddOn(addonID);
2514 // We must decrement the use count of this addon flavor in the
2515 // server to compensate the increment done in the beginning.
2516 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2517 if (rv != B_OK) {
2518 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2519 "FlavorInstancesCount failed\n");
2521 return status != B_OK ? status : B_ERROR;
2524 rv = RegisterNode(node, addonID, flavorID);
2525 if (rv != B_OK) {
2526 ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
2527 delete node;
2528 // Put the addon back into the pool
2529 gDormantNodeManager->PutAddOn(addonID);
2530 // We must decrement the use count of this addon flavor in the
2531 // server to compensate the increment done in the beginning.
2532 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2533 if (rv != B_OK) {
2534 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2535 "FlavorInstancesCount failed\n");
2537 return B_ERROR;
2540 if (creator != -1) {
2541 // send a message to the server to assign team "creator" as creator
2542 // of node "node->ID()"
2543 printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %"
2544 B_PRId32 " as creator of node %" B_PRId32 "\n", creator,
2545 node->ID());
2547 rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator);
2548 if (rv != B_OK) {
2549 ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign "
2550 "team %" B_PRId32 " as creator of node %" B_PRId32 "\n",
2551 creator, node->ID());
2552 // do not return, this is a minor problem, not a reason to fail
2556 // RegisterNode() does remember the add-on id in the server
2557 // and UnregisterNode() will call DormantNodeManager::PutAddon()
2558 // when the node is unregistered.
2560 *_node = node->Node();
2562 TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %" B_PRId32
2563 ", flavor_id %" B_PRId32 " instanciated as node %" B_PRId32 ", port %"
2564 B_PRId32 " in team %" B_PRId32 "\n", addonID, flavorID, _node->node,
2565 _node->port, BPrivate::current_team());
2567 return B_OK;
2571 status_t
2572 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2573 media_node* _node, uint32 flags)
2575 CALLED();
2576 if (_node == NULL)
2577 return B_BAD_VALUE;
2578 if (info.addon <= B_OK) {
2579 ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32
2580 " invalid.\n", info.addon);
2581 return B_BAD_VALUE;
2584 printf("BMediaRoster::InstantiateDormantNode: addon-id %" B_PRId32
2585 ", flavor_id %" B_PRId32 ", flags 0x%" B_PRIx32 "\n", info.addon,
2586 info.flavor_id, flags);
2588 // Get flavor_info from the server
2589 // TODO: this is a little overhead, as we get the full blown
2590 // dormant_flavor_info,
2591 // TODO: but only need the flags.
2592 dormant_flavor_info flavorInfo;
2593 status_t rv;
2594 rv = MediaRosterEx(this)->GetDormantFlavorInfo(info.addon, info.flavor_id,
2595 &flavorInfo);
2596 if (rv != B_OK) {
2597 ERROR("BMediaRoster::InstantiateDormantNode: failed to get "
2598 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2599 B_PRId32 "\n", info.addon, info.flavor_id);
2600 return B_NAME_NOT_FOUND;
2603 ASSERT(flavorInfo.internal_id == info.flavor_id);
2605 #if DEBUG
2606 printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", "
2607 "flavor_flags 0x%" B_PRIx32 ", internal_id %" B_PRId32
2608 ", possible_count %" B_PRId32 "\n", flavorInfo.name, flavorInfo.info,
2609 flavorInfo.flavor_flags, flavorInfo.internal_id,
2610 flavorInfo.possible_count);
2612 if ((flags & B_FLAVOR_IS_LOCAL) != 0) {
2613 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2614 "B_FLAVOR_IS_LOCAL\n");
2616 if ((flags & B_FLAVOR_IS_GLOBAL) != 0) {
2617 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2618 "B_FLAVOR_IS_GLOBAL\n");
2620 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0) {
2621 printf("BMediaRoster::InstantiateDormantNode: node requires "
2622 "B_FLAVOR_IS_LOCAL\n");
2624 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0) {
2625 printf("BMediaRoster::InstantiateDormantNode: node requires "
2626 "B_FLAVOR_IS_GLOBAL\n");
2628 #endif
2630 // Make sure that flags demanded by the dormant node and those requested
2631 // by the caller are not incompatible.
2632 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2633 && (flags & B_FLAVOR_IS_LOCAL) != 0) {
2634 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2635 "B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n");
2636 return B_NAME_NOT_FOUND;
2638 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0
2639 && (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2640 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2641 "B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
2642 return B_NAME_NOT_FOUND;
2645 // If either the node, or the caller requested to make the instance global
2646 // we will do it by forwarding this request into the media_addon_server,
2647 // which in turn will call BMediaRosterEx::InstantiateDormantNode to create
2648 // the node there and make it globally available.
2649 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2650 || (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2651 TRACE("BMediaRoster::InstantiateDormantNode: creating global object "
2652 "in media_addon_server\n");
2654 add_on_server_instantiate_dormant_node_request request;
2655 add_on_server_instantiate_dormant_node_reply reply;
2656 request.add_on_id = info.addon;
2657 request.flavor_id = info.flavor_id;
2658 request.creator_team = BPrivate::current_team();
2659 // creator team is allowed to also release global nodes
2660 rv = QueryAddOnServer(ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE, &request,
2661 sizeof(request), &reply, sizeof(reply));
2662 if (rv == B_OK)
2663 *_node = reply.node;
2664 } else {
2665 // creator team = -1, as this is a local node
2666 rv = MediaRosterEx(this)->InstantiateDormantNode(info.addon,
2667 info.flavor_id, -1, _node);
2669 if (rv != B_OK) {
2670 *_node = media_node::null;
2671 return B_NAME_NOT_FOUND;
2673 return B_OK;
2677 status_t
2678 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2679 media_node* _node)
2681 return InstantiateDormantNode(info, _node, 0);
2685 status_t
2686 BMediaRoster::GetDormantNodeFor(const media_node& node,
2687 dormant_node_info* _info)
2689 CALLED();
2690 if (_info == NULL)
2691 return B_BAD_VALUE;
2692 if (IS_INVALID_NODE(node))
2693 return B_MEDIA_BAD_NODE;
2695 server_get_dormant_node_for_request request;
2696 server_get_dormant_node_for_reply reply;
2697 status_t rv;
2699 request.node = node;
2701 rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request),
2702 &reply, sizeof(reply));
2703 if (rv != B_OK)
2704 return rv;
2706 *_info = reply.node_info;
2707 return B_OK;
2711 status_t
2712 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID, int32 flavorID,
2713 dormant_flavor_info* _flavor)
2715 CALLED();
2716 if (_flavor == NULL)
2717 return B_BAD_VALUE;
2719 // TODO: better use an area here as well!
2721 server_get_dormant_flavor_info_reply* reply
2722 = (server_get_dormant_flavor_info_reply*)malloc(16300);
2723 if (reply == NULL)
2724 return B_NO_MEMORY;
2726 server_get_dormant_flavor_info_request request;
2727 request.add_on_id = addonID;
2728 request.flavor_id = flavorID;
2730 status_t status = QueryServer(SERVER_GET_DORMANT_FLAVOR_INFO, &request,
2731 sizeof(request), reply, 16300);
2732 if (status != B_OK) {
2733 free(reply);
2734 return status;
2737 if (reply->result == B_OK) {
2738 status = _flavor->Unflatten(reply->type, &reply->flattened_data,
2739 reply->flattened_size);
2740 } else
2741 status = reply->result;
2743 free(reply);
2744 return status;
2748 status_t
2749 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info& dormant,
2750 dormant_flavor_info* _flavor)
2752 return MediaRosterEx(this)->GetDormantFlavorInfo(dormant.addon,
2753 dormant.flavor_id, _flavor);
2757 // Reports in outLatency the maximum latency found downstream from
2758 // the specified BBufferProducer, producer, given the current connections.
2759 status_t
2760 BMediaRoster::GetLatencyFor(const media_node& producer, bigtime_t* _latency)
2762 CALLED();
2763 if (_latency == NULL)
2764 return B_BAD_VALUE;
2765 if (IS_INVALID_NODE(producer)
2766 || (producer.kind & B_BUFFER_PRODUCER) == 0)
2767 return B_MEDIA_BAD_NODE;
2769 producer_get_latency_request request;
2770 producer_get_latency_reply reply;
2771 status_t rv;
2773 rv = QueryPort(producer.port, PRODUCER_GET_LATENCY, &request,
2774 sizeof(request), &reply, sizeof(reply));
2775 if (rv != B_OK)
2776 return rv;
2778 *_latency = reply.latency;
2780 // printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2781 return B_OK;
2785 status_t
2786 BMediaRoster::GetInitialLatencyFor(const media_node& producer,
2787 bigtime_t* _latency, uint32* _flags)
2789 CALLED();
2790 if (_latency == NULL)
2791 return B_BAD_VALUE;
2792 if (IS_INVALID_NODE(producer)
2793 || (producer.kind & B_BUFFER_PRODUCER) == 0)
2794 return B_MEDIA_BAD_NODE;
2796 producer_get_initial_latency_request request;
2797 producer_get_initial_latency_reply reply;
2798 status_t rv;
2800 rv = QueryPort(producer.port, PRODUCER_GET_INITIAL_LATENCY, &request,
2801 sizeof(request), &reply, sizeof(reply));
2802 if (rv != B_OK)
2803 return rv;
2805 *_latency = reply.initial_latency;
2806 if (_flags != NULL)
2807 *_flags = reply.flags;
2809 TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32 " has "
2810 "maximum initial latency %" B_PRId64 "\n", producer.node, *_latency);
2811 return B_OK;
2815 status_t
2816 BMediaRoster::GetStartLatencyFor(const media_node& timeSource,
2817 bigtime_t* _latency)
2819 CALLED();
2820 if (_latency == NULL)
2821 return B_BAD_VALUE;
2822 if (IS_INVALID_NODE(timeSource)
2823 || (timeSource.kind & B_TIME_SOURCE) == 0)
2824 return B_MEDIA_BAD_NODE;
2826 timesource_get_start_latency_request request;
2827 timesource_get_start_latency_reply reply;
2828 status_t rv;
2830 rv = QueryPort(timeSource.port, TIMESOURCE_GET_START_LATENCY, &request,
2831 sizeof(request), &reply, sizeof(reply));
2832 if (rv != B_OK)
2833 return rv;
2835 *_latency = reply.start_latency;
2837 TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32 " has "
2838 "maximum initial latency %" B_PRId64 "\n", timeSource.node, *_latency);
2839 return B_OK;
2843 status_t
2844 BMediaRoster::GetFileFormatsFor(const media_node& fileInterface,
2845 media_file_format* _formats, int32* _numFormats)
2847 CALLED();
2849 if (IS_INVALID_NODE(fileInterface)
2850 || (fileInterface.kind & B_FILE_INTERFACE) == 0)
2851 return B_MEDIA_BAD_NODE;
2853 if (_numFormats == NULL || *_numFormats < 1)
2854 return B_BAD_VALUE;
2856 fileinterface_get_formats_request request;
2857 fileinterface_get_formats_reply reply;
2859 media_file_format* formats;
2860 size_t needSize = sizeof(media_file_format) * *_numFormats;
2861 size_t size = (needSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
2863 area_id area = create_area("formats area", (void**)&formats,
2864 B_ANY_ADDRESS, size, B_NO_LOCK,
2865 B_READ_AREA | B_WRITE_AREA);
2867 if (area < 0)
2868 return B_NO_MEMORY;
2870 request.num_formats = *_numFormats;
2871 request.data_area = area;
2873 status_t status = QueryPort(fileInterface.port,
2874 FILEINTERFACE_GET_FORMATS, &request,
2875 sizeof(request), &reply, sizeof(reply));
2877 if (status == B_OK) {
2878 memcpy(_formats, formats, sizeof(media_file_format)*reply.filled_slots);
2879 *_numFormats = reply.filled_slots;
2881 delete_area(area);
2882 return status;
2886 status_t
2887 BMediaRoster::SetRefFor(const media_node& file_interface, const entry_ref& file,
2888 bool createAndTruncate, bigtime_t* _length)
2890 CALLED();
2892 if (IS_INVALID_NODE(file_interface)
2893 || (file_interface.kind & B_FILE_INTERFACE) == 0)
2894 return B_MEDIA_BAD_NODE;
2896 fileinterface_set_ref_request request;
2897 fileinterface_set_ref_reply reply;
2898 status_t rv;
2900 request.device = file.device;
2901 request.directory = file.directory;
2902 strcpy(request.name, file.name);
2903 request.create = createAndTruncate;
2904 if (_length != NULL)
2905 request.duration = *_length;
2907 rv = QueryPort(file_interface.port, FILEINTERFACE_SET_REF, &request,
2908 sizeof(request), &reply, sizeof(reply));
2909 if (rv != B_OK)
2910 return rv;
2912 if (!createAndTruncate && _length)
2913 *_length = reply.duration;
2915 return B_OK;
2919 status_t
2920 BMediaRoster::GetRefFor(const media_node& node, entry_ref* _file,
2921 BMimeType* mimeType)
2923 CALLED();
2925 if (IS_INVALID_NODE(node)
2926 || (node.kind & B_FILE_INTERFACE) == 0)
2927 return B_MEDIA_BAD_NODE;
2929 if (!_file)
2930 return B_BAD_VALUE;
2932 fileinterface_get_ref_request request;
2933 fileinterface_get_ref_reply reply;
2934 status_t rv;
2936 rv = QueryPort(node.port, FILEINTERFACE_GET_REF, &request, sizeof(request),
2937 &reply, sizeof(reply));
2938 if (rv != B_OK)
2939 return rv;
2941 *_file = entry_ref(reply.device, reply.directory, reply.name);
2943 if (mimeType)
2944 mimeType->SetTo(reply.mimetype);
2946 return B_OK;
2950 status_t
2951 BMediaRoster::SniffRefFor(const media_node& file_interface,
2952 const entry_ref& file, BMimeType* mimeType, float* _capability)
2954 CALLED();
2956 if (IS_INVALID_NODE(file_interface)
2957 || (file_interface.kind & B_FILE_INTERFACE) == 0)
2958 return B_MEDIA_BAD_NODE;
2960 if (mimeType == NULL || _capability == NULL)
2961 return B_BAD_VALUE;
2963 fileinterface_sniff_ref_request request;
2964 fileinterface_sniff_ref_reply reply;
2965 status_t rv;
2967 request.device = file.device;
2968 request.directory = file.directory;
2969 strcpy(request.name, file.name);
2971 rv = QueryPort(file_interface.port, FILEINTERFACE_SNIFF_REF, &request,
2972 sizeof(request), &reply, sizeof(reply));
2973 if (rv != B_OK)
2974 return rv;
2976 mimeType->SetTo(reply.mimetype);
2977 *_capability = reply.capability;
2979 return B_OK;
2983 /*! This is the generic "here's a file, now can someone please play it"
2984 interface.
2986 status_t
2987 BMediaRoster::SniffRef(const entry_ref& file, uint64 requireNodeKinds,
2988 dormant_node_info* _node, BMimeType* mimeType)
2990 CALLED();
2992 TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64
2993 "\n", file.name, requireNodeKinds);
2995 if (_node == NULL)
2996 return B_BAD_VALUE;
2998 BMimeType aMimeType;
3000 dormant_node_info nodes[30];
3001 int32 count = 30;
3002 int32 highestCapability = -1;
3003 float capability;
3005 media_node node;
3007 // Get all dormant nodes using GetDormantNodes
3008 if (GetDormantNodes(nodes, &count, NULL, NULL, NULL, requireNodeKinds | B_FILE_INTERFACE, 0) == B_OK) {
3009 // Call SniffRefFor on each node that matches requireNodeKinds
3010 for (int32 i=0;i<count;i++) {
3011 if (InstantiateDormantNode(nodes[i], &node) == B_OK) {
3013 if (SniffRefFor(node, file, &aMimeType, &capability) == B_OK) {
3014 // find the first node that has 100% capability
3015 TRACE("%s has a %f%% chance of playing file\n",nodes[i].name, capability * 100.0);
3016 if (capability == 1.0) {
3017 highestCapability = i;
3018 break;
3021 ReleaseNode(node);
3025 if (highestCapability != -1) {
3026 *_node = nodes[highestCapability];
3028 TRACE("BMediaRoster::SniffRef: found a node %s addon-id %" B_PRId32
3029 ", flavor_id %" B_PRId32 "\n",
3030 nodes[highestCapability].name, nodes[highestCapability].addon,
3031 nodes[highestCapability].flavor_id);
3033 if (mimeType != NULL) {
3034 //*mimeType = aMimeType; -- need a copy constructor
3037 return B_OK;
3042 return B_ERROR;
3046 status_t
3047 BMediaRoster::GetDormantNodeForType(const BMimeType& type,
3048 uint64 requireNodeKinds, dormant_node_info* _node)
3050 UNIMPLEMENTED();
3051 return B_ERROR;
3055 status_t
3056 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info& node,
3057 media_file_format* _readFormats, int32 readCount, int32* _readCount)
3059 UNIMPLEMENTED();
3060 return B_ERROR;
3064 status_t
3065 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info& node,
3066 media_file_format* _write_formats, int32 writeCount, int32* _writeCount)
3068 UNIMPLEMENTED();
3069 return B_ERROR;
3073 status_t
3074 BMediaRoster::GetFormatFor(const media_output& output, media_format* _format,
3075 uint32 flags)
3077 CALLED();
3078 if (_format == NULL)
3079 return B_BAD_VALUE;
3080 if ((output.node.kind & B_BUFFER_PRODUCER) == 0)
3081 return B_MEDIA_BAD_NODE;
3082 if (IS_INVALID_SOURCE(output.source))
3083 return B_MEDIA_BAD_SOURCE;
3085 producer_format_suggestion_requested_request request;
3086 producer_format_suggestion_requested_reply reply;
3087 status_t rv;
3089 request.type = B_MEDIA_UNKNOWN_TYPE;
3090 request.quality = 0; // TODO: what should this be?
3092 rv = QueryPort(output.source.port, PRODUCER_FORMAT_SUGGESTION_REQUESTED,
3093 &request, sizeof(request), &reply, sizeof(reply));
3094 if (rv != B_OK)
3095 return rv;
3097 *_format = reply.format;
3098 return B_OK;
3102 status_t
3103 BMediaRoster::GetFormatFor(const media_input& input, media_format* _format,
3104 uint32 flags)
3106 CALLED();
3107 if (_format == NULL)
3108 return B_BAD_VALUE;
3109 if ((input.node.kind & B_BUFFER_CONSUMER) == 0)
3110 return B_MEDIA_BAD_NODE;
3111 if (IS_INVALID_DESTINATION(input.destination))
3112 return B_MEDIA_BAD_DESTINATION;
3114 consumer_accept_format_request request;
3115 consumer_accept_format_reply reply;
3116 status_t rv;
3118 request.dest = input.destination;
3119 memset(&request.format, 0, sizeof(request.format)); // wildcard
3121 rv = QueryPort(input.destination.port, CONSUMER_ACCEPT_FORMAT, &request,
3122 sizeof(request), &reply, sizeof(reply));
3123 if (rv != B_OK)
3124 return rv;
3126 *_format = reply.format;
3127 return B_OK;
3131 status_t
3132 BMediaRoster::GetFormatFor(const media_node& node, media_format* _format,
3133 float quality)
3135 UNIMPLEMENTED();
3136 if (_format == NULL)
3137 return B_BAD_VALUE;
3138 if (IS_INVALID_NODE(node))
3139 return B_MEDIA_BAD_NODE;
3140 if ((node.kind & (B_BUFFER_CONSUMER | B_BUFFER_PRODUCER)) == 0)
3141 return B_MEDIA_BAD_NODE;
3143 return B_ERROR;
3147 ssize_t
3148 BMediaRoster::GetNodeAttributesFor(const media_node& node,
3149 media_node_attribute* _array, size_t maxCount)
3151 CALLED();
3153 if (IS_INVALID_NODE(node))
3154 return B_MEDIA_BAD_NODE;
3156 node_get_attributes_for_request request;
3157 node_get_attributes_for_reply reply;
3158 status_t status;
3160 media_node_attribute* addr = NULL;
3161 size_t totalSize = maxCount*sizeof(media_node_attribute);
3162 size_t size = (totalSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
3164 area_id dataArea = create_area("attributes area", (void**)&addr,
3165 B_ANY_ADDRESS, size, B_NO_LOCK,
3166 B_READ_AREA | B_WRITE_AREA);
3167 // No need to memset the padding
3168 memset(addr, 0, totalSize);
3170 if (dataArea < 0)
3171 return B_NO_MEMORY;
3173 request.count = maxCount;
3174 request.area = dataArea;
3176 status = QueryPort(node.port, NODE_GET_ATTRIBUTES_FOR, &request,
3177 sizeof(request), &reply, sizeof(reply));
3178 if (status != B_OK)
3179 return status;
3181 memcpy(_array, addr, reply.filled_count
3182 * sizeof(media_node_attribute));
3184 delete_area(dataArea);
3185 return reply.filled_count;
3189 media_node_id
3190 BMediaRoster::NodeIDFor(port_id port)
3192 CALLED();
3194 server_node_id_for_request request;
3195 server_node_id_for_reply reply;
3196 status_t rv;
3198 request.port = port;
3200 rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply,
3201 sizeof(reply));
3202 if (rv != B_OK) {
3203 ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32 ")\n", rv);
3204 return -1;
3207 return reply.node_id;
3211 status_t
3212 BMediaRoster::GetInstancesFor(media_addon_id addon, int32 flavor,
3213 media_node_id* _id, int32* _count)
3215 CALLED();
3216 if (_id == NULL)
3217 return B_BAD_VALUE;
3218 if (_count && *_count <= 0)
3219 return B_BAD_VALUE;
3221 server_get_instances_for_request request;
3222 server_get_instances_for_reply reply;
3223 status_t rv;
3225 request.max_count = (_count ? *_count : 1);
3226 request.add_on_id = addon;
3227 request.flavor_id = flavor;
3229 rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request),
3230 &reply, sizeof(reply));
3231 if (rv != B_OK) {
3232 ERROR("BMediaRoster::GetLiveNodes failed\n");
3233 return rv;
3236 if (_count)
3237 *_count = reply.count;
3238 if (reply.count > 0)
3239 memcpy(_id, reply.node_id, sizeof(media_node_id) * reply.count);
3241 return B_OK;
3245 bool
3246 BMediaRoster::IsRunning()
3248 return be_roster->IsRunning(B_MEDIA_SERVER_SIGNATURE)
3249 && be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE);
3253 status_t
3254 BMediaRoster::SetRealtimeFlags(uint32 enabled)
3256 UNIMPLEMENTED();
3257 return B_ERROR;
3261 status_t
3262 BMediaRoster::GetRealtimeFlags(uint32* _enabled)
3264 UNIMPLEMENTED();
3265 return B_ERROR;
3269 ssize_t
3270 BMediaRoster::AudioBufferSizeFor(int32 channelCount, uint32 sampleFormat,
3271 float frameRate, bus_type busKind)
3273 bigtime_t bufferDuration;
3274 ssize_t bufferSize;
3276 if (busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS)
3277 bufferDuration = 25000;
3278 else
3279 bufferDuration = 10000;
3281 bufferSize = (sampleFormat & 0xf) * channelCount
3282 * (ssize_t)((frameRate * bufferDuration) / 1000000.0);
3284 printf("Suggested buffer duration %" B_PRId64 ", size %" B_PRIdSSIZE "\n",
3285 bufferDuration, bufferSize);
3287 return bufferSize;
3291 /*! Use MediaFlags to inquire about specific features of the Media Kit.
3292 Returns < 0 for "not present", positive size for output data size.
3293 0 means that the capability is present, but no data about it.
3295 /*static*/ ssize_t
3296 BMediaRoster::MediaFlags(media_flags cap, void* buffer, size_t maxSize)
3298 UNIMPLEMENTED();
3299 return 0;
3303 // #pragma mark - BLooper overrides
3306 void
3307 BMediaRoster::MessageReceived(BMessage* message)
3309 switch (message->what) {
3310 case 'PING':
3312 // media_server plays ping-pong with the BMediaRosters
3313 // to detect dead teams. Normal communication uses ports.
3314 static BMessage pong('PONG');
3315 message->SendReply(&pong, static_cast<BHandler *>(NULL), 2000000);
3316 return;
3319 case MEDIA_ROSTER_REQUEST_NOTIFICATIONS:
3321 RosterNotification notification;
3322 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, &notification.what)
3323 != B_OK) {
3324 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3325 "find what parameter");
3326 return;
3328 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER,
3329 &notification.messenger) != B_OK) {
3330 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3331 "find messenger");
3332 return;
3334 sNotificationList.Insert(notification);
3335 return;
3338 case MEDIA_ROSTER_CANCEL_NOTIFICATIONS:
3340 RosterNotification notification;
3341 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, &notification.what)
3342 != B_OK) {
3343 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3344 "find what parameter");
3345 return;
3347 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER,
3348 &notification.messenger) != B_OK) {
3349 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3350 "find messenger");
3351 return;
3353 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3354 RosterNotification* current;
3355 if (sNotificationList.Get(i, &current) != true)
3356 return;
3357 if (current->what == notification.what
3358 && current->messenger == notification.messenger) {
3359 sNotificationList.Remove(i);
3360 return;
3363 return;
3366 case B_SOME_APP_LAUNCHED:
3368 BString mimeSig;
3369 if (message->FindString("be:signature", &mimeSig) != B_OK)
3370 return;
3371 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE
3372 && mimeSig != B_MEDIA_SERVER_SIGNATURE)
3373 return;
3375 TRACE("BMediaRoster::MessageReceived media services are going up.");
3377 // Send the notification to our subscribers
3378 if (BMediaRoster::IsRunning()) {
3379 sServerIsUp = true;
3380 // Wait for media services to wake up
3381 // TODO: This should be solved so that the server
3382 // have a way to notify us when the system is really
3383 // ready to run and we avoid sleeping.
3384 snooze(2000000);
3385 // Restore our friendship with the media servers
3386 if (MediaRosterEx(this)->BuildConnections() != B_OK) {
3387 TRACE("BMediaRoster::MessageReceived can't reconnect"
3388 "to media_server.");
3391 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3392 RosterNotification* current;
3393 if (sNotificationList.Get(i, &current) != true)
3394 return;
3395 if (current->what == B_MEDIA_SERVER_STARTED) {
3396 if (current->messenger.SendMessage(
3397 B_MEDIA_SERVER_STARTED) != B_OK) {
3398 if(!current->messenger.IsValid())
3399 sNotificationList.Remove(i);
3404 return;
3407 case B_SOME_APP_QUIT:
3409 BString mimeSig;
3410 if (message->FindString("be:signature", &mimeSig) != B_OK)
3411 return;
3412 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE
3413 && mimeSig != B_MEDIA_SERVER_SIGNATURE)
3414 return;
3416 TRACE("BMediaRoster::MessageReceived media services are down.");
3418 // Send the notification to our subscribers
3419 if (!BMediaRoster::IsRunning() && sServerIsUp == true) {
3420 sServerIsUp = false;
3421 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3422 RosterNotification* current;
3423 if (sNotificationList.Get(i, &current) != true)
3424 return;
3425 if (current->what == B_MEDIA_SERVER_QUIT) {
3426 if (current->messenger.SendMessage(
3427 B_MEDIA_SERVER_QUIT) != B_OK) {
3428 if(!current->messenger.IsValid())
3429 sNotificationList.Remove(i);
3434 return;
3437 case NODE_FINAL_RELEASE:
3439 // this function is called by a BMediaNode to delete
3440 // itself, as this needs to be done from another thread
3441 // context, it is done here.
3442 // TODO: If a node is released using BMediaRoster::ReleaseNode()
3443 // TODO: instead of using BMediaNode::Release() / BMediaNode::Acquire()
3444 // TODO: fRefCount of the BMediaNode will not be correct.
3446 BMediaNode *node;
3447 message->FindPointer("node", reinterpret_cast<void **>(&node));
3449 TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE saving "
3450 "node %" B_PRId32 " configuration\n", node->ID());
3451 MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(node);
3453 TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing "
3454 "node %" B_PRId32 "\n", node->ID());
3455 node->DeleteHook(node); // we don't call Release(), see above!
3456 return;
3459 printf("BMediaRoster::MessageReceived: unknown message!\n");
3460 message->PrintToStream();
3464 bool
3465 BMediaRoster::QuitRequested()
3467 CALLED();
3469 if (be_roster->StopWatching(BMessenger(this, this)) != B_OK)
3470 TRACE("Can't unregister roster notifications");
3472 if (sNotificationList.CountItems() != 0)
3473 sNotificationList.MakeEmpty();
3475 return true;
3479 BHandler*
3480 BMediaRoster::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
3481 int32 form, const char* property)
3483 return BLooper::ResolveSpecifier(msg, index, specifier, form, property);
3487 status_t
3488 BMediaRoster::GetSupportedSuites(BMessage* data)
3490 return BLooper::GetSupportedSuites(data);
3494 BMediaRoster::~BMediaRoster()
3496 CALLED();
3498 // Unset the global instance pointer, the destructor is also called
3499 // if a client app calls Lock(); and Quit(); directly.
3500 sDefaultInstance = NULL;
3504 // #pragma mark - private BMediaRoster
3507 //! Deprecated call.
3508 status_t
3509 BMediaRoster::SetOutputBuffersFor(const media_source& output,
3510 BBufferGroup* group, bool willReclaim)
3512 UNIMPLEMENTED();
3513 debugger("BMediaRoster::SetOutputBuffersFor missing\n");
3514 return B_ERROR;
3518 // FBC reserved virtuals
3519 status_t BMediaRoster::_Reserved_MediaRoster_0(void*) { return B_ERROR; }
3520 status_t BMediaRoster::_Reserved_MediaRoster_1(void*) { return B_ERROR; }
3521 status_t BMediaRoster::_Reserved_MediaRoster_2(void*) { return B_ERROR; }
3522 status_t BMediaRoster::_Reserved_MediaRoster_3(void*) { return B_ERROR; }
3523 status_t BMediaRoster::_Reserved_MediaRoster_4(void*) { return B_ERROR; }
3524 status_t BMediaRoster::_Reserved_MediaRoster_5(void*) { return B_ERROR; }
3525 status_t BMediaRoster::_Reserved_MediaRoster_6(void*) { return B_ERROR; }
3526 status_t BMediaRoster::_Reserved_MediaRoster_7(void*) { return B_ERROR; }
3529 BMediaRoster::BMediaRoster()
3531 BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY,
3532 B_LOOPER_PORT_DEFAULT_CAPACITY)
3534 CALLED();
3536 // start the looper
3537 Run();
3541 // TODO: Looks like these can be safely removed:
3542 /*static*/ status_t
3543 BMediaRoster::ParseCommand(BMessage& reply)
3545 UNIMPLEMENTED();
3546 return B_ERROR;
3550 status_t
3551 BMediaRoster::GetDefaultInfo(media_node_id forDefault, BMessage& config)
3553 UNIMPLEMENTED();
3554 return B_ERROR;
3558 status_t
3559 BMediaRoster::SetRunningDefault(media_node_id forDefault,
3560 const media_node& node)
3562 UNIMPLEMENTED();
3563 return B_ERROR;
3567 // #pragma mark - static variables
3570 BMediaRoster* BMediaRoster::sDefaultInstance = NULL;