vfs: check userland buffers before reading them.
[haiku.git] / src / kits / media / MediaRoster.cpp
bloba7f257f0c2036ebe0c9350c06c4aaed297460391
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 <Application.h>
46 #include <Autolock.h>
47 #include <BufferConsumer.h>
48 #include <BufferProducer.h>
49 #include <Locker.h>
50 #include <Message.h>
51 #include <Messenger.h>
52 #include <MimeType.h>
53 #include <OS.h>
54 #include <ParameterWeb.h>
55 #include <Roster.h>
56 #include <StopWatch.h>
57 #include <String.h>
58 #include <TimeSource.h>
60 #include <new>
62 #include <AppMisc.h>
63 #include <DataExchange.h>
64 #include <debug.h>
65 #include <DormantNodeManager.h>
66 #include <MediaMisc.h>
67 #include <MediaRosterEx.h>
68 #include <Notifications.h>
69 #include <ServerInterface.h>
70 #include <SharedBufferList.h>
71 #include <TList.h>
73 #include "TimeSourceObjectManager.h"
76 namespace BPrivate {
77 namespace media {
80 struct RosterNotification {
81 BMessenger messenger;
82 int32 what;
86 struct SyncedMessage {
87 BMessage* message;
91 struct LocalNode {
92 LocalNode(BMediaNode* local_node)
94 node(local_node) {}
96 LocalNode()
98 node(NULL) {}
100 bool operator==(const LocalNode& a)
102 if (a.node == this->node)
103 return true;
104 return false;
107 BMediaNode* node;
111 static bool sServerIsUp = false;
112 static List<RosterNotification> sNotificationList;
113 static BLocker sInitLocker("BMediaRoster::Roster locker");
114 static List<LocalNode> sRegisteredNodes;
117 class MediaRosterUndertaker {
118 public:
119 ~MediaRosterUndertaker()
121 BAutolock _(sInitLocker);
122 if (BMediaRoster::CurrentRoster() != NULL) {
124 // Detect any forgotten node
125 if (sRegisteredNodes.CountItems() > 0) {
126 for (int32 i = 0; i < sRegisteredNodes.CountItems(); i++) {
127 LocalNode* node = NULL;
128 sRegisteredNodes.Get(i, &node);
129 if (node != NULL) {
130 ERROR("BMediaRoster: Node with ID %" B_PRId32
131 " was not released correctly\n", node->node->ID());
136 if (be_app != NULL)
137 be_app->UnregisterLooper(BMediaRoster::CurrentRoster());
139 status_t err = B_ERROR;
140 thread_id roster = BMediaRoster::CurrentRoster()->Thread();
142 BMediaRoster::CurrentRoster()->PostMessage(B_QUIT_REQUESTED);
144 wait_for_thread(roster, &err);
145 if (err != B_OK)
146 ERROR("BMediaRoster: wait_for_thread returned error");
152 static MediaRosterUndertaker sMediaRosterUndertaker;
154 } // namespace media
155 } // namespace BPrivate
157 using namespace BPrivate::media;
160 BMediaRosterEx::BMediaRosterEx(status_t* _error)
162 BMediaRoster(),
163 fLaunchNotification(false),
164 fAutoExit(false)
166 gDormantNodeManager = new DormantNodeManager();
167 gTimeSourceObjectManager = new TimeSourceObjectManager();
169 *_error = BuildConnections();
171 InitRosterDataExchange(BMessenger(this, this));
173 if (be_roster->StartWatching(BMessenger(this, this),
174 B_REQUEST_LAUNCHED | B_REQUEST_QUIT) != B_OK) {
175 *_error = B_ERROR;
177 sServerIsUp = BMediaRoster::IsRunning();
181 void
182 BMediaRosterEx::Quit()
184 if (be_roster->StopWatching(BMessenger(this, this)) != B_OK)
185 TRACE("Can't unregister roster notifications");
187 if (sNotificationList.CountItems() != 0)
188 sNotificationList.MakeEmpty();
190 BMediaRoster::Quit();
194 status_t
195 BMediaRosterEx::BuildConnections()
197 InitServerDataExchange();
198 // register this application with the media server
199 server_register_app_request request;
200 server_register_app_reply reply;
201 request.team = BPrivate::current_team();
202 request.messenger = BMessenger(NULL, this);
203 status_t status = QueryServer(SERVER_REGISTER_APP, &request,
204 sizeof(request), &reply, sizeof(reply));
205 if (status != B_OK)
206 return B_MEDIA_SYSTEM_FAILURE;
208 return B_OK;
212 BMediaRosterEx::~BMediaRosterEx()
214 CALLED();
216 delete gTimeSourceObjectManager;
217 delete gDormantNodeManager;
219 // unregister this application with the media server
220 server_unregister_app_request request;
221 server_unregister_app_reply reply;
222 request.team = BPrivate::current_team();
223 QueryServer(SERVER_UNREGISTER_APP, &request, sizeof(request), &reply,
224 sizeof(reply));
226 BPrivate::SharedBufferList::Invalidate();
230 void
231 BMediaRosterEx::RegisterLocalNode(BMediaNode* node)
233 sRegisteredNodes.Insert(LocalNode(node));
237 void
238 BMediaRosterEx::UnregisterLocalNode(BMediaNode* node)
240 int32 index = sRegisteredNodes.Find(LocalNode(node));
241 if (index != -1)
242 sRegisteredNodes.Remove(index);
246 void
247 BMediaRosterEx::EnableLaunchNotification(bool enable, bool autoExit)
249 // NOTE: in theory, we should personalize it depending on each
250 // request, but we are using it just in launch/shutdown_media_server,
251 // so we are enough safe to don't care about that.
252 fLaunchNotification = enable;
253 fAutoExit = autoExit;
257 status_t
258 BMediaRosterEx::SaveNodeConfiguration(BMediaNode* node)
260 int32 flavorID;
261 BMediaAddOn* addon = node->AddOn(&flavorID);
262 if (addon == NULL) {
263 // NOTE: This node could have been created by an application,
264 // it does not mean there is an error.
265 // TODO: this check incorrectly triggers on BeOS R5 BT848 node
266 TRACE("BMediaRosterEx::SaveNodeConfiguration node %" B_PRId32 " not "
267 "instantiated from BMediaAddOn!\n", node->ID());
268 return B_ERROR;
271 media_addon_id addonID = addon->AddonID();
273 // TODO: fix this
274 printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id "
275 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID,
276 flavorID);
277 return B_OK;
281 status_t
282 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonID, int32 flavorID,
283 BMessage *_msg)
285 // TODO: fix this
286 _msg->MakeEmpty(); // to be fully R5 compliant
287 printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id "
288 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID,
289 flavorID);
290 return B_OK;
294 status_t
295 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonID,
296 int32 flavorID)
298 server_change_flavor_instances_count_request request;
299 server_change_flavor_instances_count_reply reply;
301 request.add_on_id = addonID;
302 request.flavor_id = flavorID;
303 request.delta = 1;
304 request.team = BPrivate::current_team();
305 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request,
306 sizeof(request), &reply, sizeof(reply));
310 status_t
311 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonID,
312 int32 flavorID)
314 server_change_flavor_instances_count_request request;
315 server_change_flavor_instances_count_reply reply;
317 request.add_on_id = addonID;
318 request.flavor_id = flavorID;
319 request.delta = -1;
320 request.team = BPrivate::current_team();
321 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request,
322 sizeof(request), &reply, sizeof(reply));
326 status_t
327 BMediaRosterEx::ReleaseNodeAll(const media_node& node)
329 CALLED();
330 if (IS_INVALID_NODE(node))
331 return B_MEDIA_BAD_NODE;
333 if (node.kind & NODE_KIND_NO_REFCOUNTING)
334 return B_OK;
336 server_release_node_request request;
337 server_release_node_reply reply;
338 status_t rv;
340 request.node = node;
341 request.team = BPrivate::current_team();
343 TRACE("BMediaRoster::ReleaseNodeAll, node %" B_PRId32 ", port %" B_PRId32
344 ", team %" B_PRId32 "\n",
345 node.node, node.port, BPrivate::current_team());
347 rv = QueryServer(SERVER_RELEASE_NODE_ALL, &request, sizeof(request), &reply,
348 sizeof(reply));
349 if (rv != B_OK) {
350 ERROR("BMediaRoster::ReleaseNodeAll failed to query media_server, "
351 "retrying local, node %" B_PRId32 ", port %"
352 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
353 BPrivate::current_team());
354 node_final_release_command command;
355 rv = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
356 sizeof(command));
357 if (rv != B_OK) {
358 ERROR("BMediaRoster::ReleaseNodeAll FAILED, node %" B_PRId32 ", port %"
359 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
360 BPrivate::current_team());
363 return rv;
367 status_t
368 BMediaRosterEx::SetNodeCreator(media_node_id node, team_id creator)
370 server_set_node_creator_request request;
371 server_set_node_creator_reply reply;
373 request.node = node;
374 request.creator = creator;
375 return QueryServer(SERVER_SET_NODE_CREATOR, &request, sizeof(request),
376 &reply, sizeof(reply));
380 status_t
381 BMediaRosterEx::GetNode(node_type type, media_node* out_node,
382 int32* out_input_id, BString* out_input_name)
384 if (out_node == NULL)
385 return B_BAD_VALUE;
387 server_get_node_request request;
388 server_get_node_reply reply;
389 status_t rv;
391 request.type = type;
392 request.team = BPrivate::current_team();
393 rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply,
394 sizeof(reply));
395 if (rv != B_OK)
396 return rv;
398 *out_node = reply.node;
399 if (out_input_id)
400 *out_input_id = reply.input_id;
401 if (out_input_name)
402 *out_input_name = reply.input_name;
403 return rv;
407 status_t
408 BMediaRosterEx::SetNode(node_type type, const media_node* node,
409 const dormant_node_info* info, const media_input* input)
411 server_set_node_request request;
412 server_set_node_reply reply;
414 request.type = type;
415 request.use_node = node != NULL;
416 if (node != NULL)
417 request.node = *node;
418 request.use_dni = info != NULL;
419 if (info != NULL)
420 request.dni = *info;
421 request.use_input = input != NULL;
422 if (input != NULL)
423 request.input = *input;
425 return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply,
426 sizeof(reply));
430 status_t
431 BMediaRosterEx::GetAllOutputs(const media_node& node, List<media_output>* list)
433 int32 cookie;
434 status_t rv;
435 status_t result;
437 PRINT(4, "BMediaRosterEx::GetAllOutputs() node %" B_PRId32 ", port %"
438 B_PRId32 "\n", node.node, node.port);
440 if (!(node.kind & B_BUFFER_PRODUCER)) {
441 ERROR("BMediaRosterEx::GetAllOutputs: node %" B_PRId32 " is not a "
442 "B_BUFFER_PRODUCER\n", node.node);
443 return B_MEDIA_BAD_NODE;
446 result = B_OK;
447 cookie = 0;
448 list->MakeEmpty();
449 for (;;) {
450 producer_get_next_output_request request;
451 producer_get_next_output_reply reply;
452 request.cookie = cookie;
453 rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request,
454 sizeof(request), &reply, sizeof(reply));
455 if (rv != B_OK)
456 break;
457 cookie = reply.cookie;
458 if (!list->Insert(reply.output)) {
459 ERROR("GetAllOutputs: list->Insert failed\n");
460 result = B_ERROR;
462 #if DEBUG >= 3
463 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
464 PRINT_OUTPUT("output ", reply.output);
465 #endif
468 producer_dispose_output_cookie_request request;
469 producer_dispose_output_cookie_reply reply;
470 QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request,
471 sizeof(request), &reply, sizeof(reply));
473 return result;
477 status_t
478 BMediaRosterEx::GetAllOutputs(BBufferProducer* node, List<media_output>* list)
480 int32 cookie;
481 status_t result;
483 PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %" B_PRId32
484 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort());
486 result = B_OK;
487 cookie = 0;
488 list->MakeEmpty();
489 for (;;) {
490 media_output output;
491 if (B_OK != node->GetNextOutput(&cookie, &output))
492 break;
493 if (!list->Insert(output)) {
494 ERROR("GetAllOutputs: list->Insert failed\n");
495 result = B_ERROR;
497 #if DEBUG >= 3
498 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
499 PRINT_OUTPUT("output ", output);
500 #endif
502 node->DisposeOutputCookie(cookie);
503 return result;
507 status_t
508 BMediaRosterEx::GetAllInputs(const media_node& node, List<media_input>* list)
510 int32 cookie;
511 status_t rv;
512 status_t result;
514 PRINT(4, "BMediaRosterEx::GetAllInputs() node %" B_PRId32 ", port %"
515 B_PRId32 "\n", node.node, node.port);
517 if (!(node.kind & B_BUFFER_CONSUMER)) {
518 ERROR("BMediaRosterEx::GetAllInputs: node %" B_PRId32 " is not a "
519 "B_BUFFER_CONSUMER\n", node.node);
520 return B_MEDIA_BAD_NODE;
523 result = B_OK;
524 cookie = 0;
525 list->MakeEmpty();
526 for (;;) {
527 consumer_get_next_input_request request;
528 consumer_get_next_input_reply reply;
529 request.cookie = cookie;
530 rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request,
531 sizeof(request), &reply, sizeof(reply));
532 if (rv != B_OK)
533 break;
534 cookie = reply.cookie;
535 if (!list->Insert(reply.input)) {
536 ERROR("GetAllInputs: list->Insert failed\n");
537 result = B_ERROR;
539 #if DEBUG >= 3
540 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
541 PRINT_OUTPUT("input ", reply.input);
542 #endif
545 consumer_dispose_input_cookie_request request;
546 consumer_dispose_input_cookie_reply reply;
547 QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request,
548 sizeof(request), &reply, sizeof(reply));
550 return result;
554 status_t
555 BMediaRosterEx::GetAllInputs(BBufferConsumer* node, List<media_input>* list)
557 int32 cookie;
558 status_t result;
560 PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %" B_PRId32
561 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort());
563 result = B_OK;
564 cookie = 0;
565 list->MakeEmpty();
566 for (;;) {
567 media_input input;
568 if (B_OK != node->GetNextInput(&cookie, &input))
569 break;
570 if (!list->Insert(input)) {
571 ERROR("GetAllInputs: list->Insert failed\n");
572 result = B_ERROR;
574 #if DEBUG >= 3
575 PRINT(3," next cookie %" B_PRId32 ", ", cookie);
576 PRINT_INPUT("input ", input);
577 #endif
579 node->DisposeInputCookie(cookie);
580 return result;
584 status_t
585 BMediaRosterEx::PublishOutputs(const media_node& node, List<media_output>* list)
587 server_publish_outputs_request request;
588 server_publish_outputs_reply reply;
589 media_output* output;
590 media_output* outputs;
591 int32 count;
592 status_t rv;
594 count = list->CountItems();
595 TRACE("PublishOutputs: publishing %" B_PRId32 "\n", count);
597 request.node = node;
598 request.count = count;
599 if (count > MAX_OUTPUTS) {
600 void *start_addr;
601 size_t size;
602 size = ROUND_UP_TO_PAGE(count * sizeof(media_output));
603 request.area = create_area("publish outputs", &start_addr,
604 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
605 if (request.area < B_OK) {
606 ERROR("PublishOutputs: failed to create area, %#" B_PRIx32 "\n",
607 request.area);
608 return (status_t)request.area;
610 outputs = static_cast<media_output *>(start_addr);
611 } else {
612 request.area = -1;
613 outputs = request.outputs;
615 TRACE("PublishOutputs: area %" B_PRId32 "\n", request.area);
617 int i;
618 for (i = 0, list->Rewind(); list->GetNext(&output); i++) {
619 ASSERT(i < count);
620 outputs[i] = *output;
623 rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request),
624 &reply, sizeof(reply));
626 if (request.area != -1)
627 delete_area(request.area);
629 return rv;
633 status_t
634 BMediaRosterEx::PublishInputs(const media_node& node, List<media_input>* list)
636 server_publish_inputs_request request;
637 server_publish_inputs_reply reply;
638 media_input* input;
639 media_input* inputs;
640 int32 count;
641 status_t rv;
643 count = list->CountItems();
644 TRACE("PublishInputs: publishing %" B_PRId32 "\n", count);
646 request.node = node;
647 request.count = count;
648 if (count > MAX_INPUTS) {
649 void* start_addr;
650 size_t size;
651 size = ROUND_UP_TO_PAGE(count * sizeof(media_input));
652 request.area = create_area("publish inputs", &start_addr,
653 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
654 if (request.area < B_OK) {
655 ERROR("PublishInputs: failed to create area, %#" B_PRIx32 "\n",
656 request.area);
657 return (status_t)request.area;
659 inputs = static_cast<media_input *>(start_addr);
660 } else {
661 request.area = -1;
662 inputs = request.inputs;
664 TRACE("PublishInputs: area %" B_PRId32 "\n", request.area);
666 int i;
667 for (i = 0, list->Rewind(); list->GetNext(&input); i++) {
668 ASSERT(i < count);
669 inputs[i] = *input;
672 rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request),
673 &reply, sizeof(reply));
675 if (request.area != -1)
676 delete_area(request.area);
678 return rv;
682 BTimeSource*
683 BMediaRosterEx::MakeTimeSourceObject(media_node_id timeSourceID)
685 media_node clone;
686 status_t status = GetNodeFor(timeSourceID, &clone);
687 if (status != B_OK) {
688 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed: %s\n",
689 strerror(status));
690 return NULL;
693 BTimeSource* source = gTimeSourceObjectManager->GetTimeSource(clone);
694 if (source == NULL) {
695 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n");
696 return NULL;
699 // TODO: release?
700 ReleaseNode(clone);
702 return source;
706 // #pragma mark - public BMediaRoster
709 status_t
710 BMediaRoster::GetVideoInput(media_node* _node)
712 CALLED();
713 return MediaRosterEx(this)->GetNode(VIDEO_INPUT, _node);
717 status_t
718 BMediaRoster::GetAudioInput(media_node* _node)
720 CALLED();
721 return MediaRosterEx(this)->GetNode(AUDIO_INPUT, _node);
725 status_t
726 BMediaRoster::GetVideoOutput(media_node* _node)
728 CALLED();
729 return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT, _node);
733 status_t
734 BMediaRoster::GetAudioMixer(media_node* _node)
736 CALLED();
737 return MediaRosterEx(this)->GetNode(AUDIO_MIXER, _node);
741 status_t
742 BMediaRoster::GetAudioOutput(media_node* _node)
744 CALLED();
745 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT, _node);
749 status_t
750 BMediaRoster::GetAudioOutput(media_node* _node, int32* _inputID,
751 BString* _inputName)
753 CALLED();
754 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX, _node, _inputID,
755 _inputName);
759 status_t
760 BMediaRoster::GetTimeSource(media_node* _node)
762 CALLED();
763 status_t rv;
765 // TODO: need to do this in a nicer way.
767 rv = MediaRosterEx(this)->GetNode(TIME_SOURCE, _node);
768 if (rv != B_OK)
769 return rv;
771 // We don't do reference counting for timesources, that's why we
772 // release the node immediately.
773 ReleaseNode(*_node);
775 // we need to remember to not use this node with server side reference counting
776 _node->kind |= NODE_KIND_NO_REFCOUNTING;
777 return B_OK;
781 status_t
782 BMediaRoster::SetVideoInput(const media_node& producer)
784 CALLED();
785 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, &producer);
789 status_t
790 BMediaRoster::SetVideoInput(const dormant_node_info& producer)
792 CALLED();
793 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, NULL, &producer);
797 status_t
798 BMediaRoster::SetAudioInput(const media_node& producer)
800 CALLED();
801 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, &producer);
805 status_t
806 BMediaRoster::SetAudioInput(const dormant_node_info& producer)
808 CALLED();
809 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, NULL, &producer);
813 status_t
814 BMediaRoster::SetVideoOutput(const media_node& consumer)
816 CALLED();
817 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, &consumer);
821 status_t
822 BMediaRoster::SetVideoOutput(const dormant_node_info& consumer)
824 CALLED();
825 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, NULL, &consumer);
829 status_t
830 BMediaRoster::SetAudioOutput(const media_node& consumer)
832 CALLED();
833 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, &consumer);
837 status_t
838 BMediaRoster::SetAudioOutput(const media_input& input)
840 CALLED();
841 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, NULL, &input);
845 status_t
846 BMediaRoster::SetAudioOutput(const dormant_node_info& consumer)
848 CALLED();
849 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, &consumer);
853 status_t
854 BMediaRoster::GetNodeFor(media_node_id node, media_node* clone)
856 CALLED();
857 if (clone == NULL)
858 return B_BAD_VALUE;
859 if (IS_INVALID_NODEID(node))
860 return B_MEDIA_BAD_NODE;
862 server_get_node_for_request request;
863 server_get_node_for_reply reply;
864 status_t rv;
866 request.node_id = node;
867 request.team = BPrivate::current_team();
869 rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply,
870 sizeof(reply));
871 if (rv != B_OK)
872 return rv;
874 *clone = reply.clone;
875 return B_OK;
879 status_t
880 BMediaRoster::GetSystemTimeSource(media_node* clone)
882 CALLED();
883 status_t rv;
885 // TODO: need to do this in a nicer way.
887 rv = MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE, clone);
888 if (rv != B_OK)
889 return rv;
891 // We don't do reference counting for timesources, that's why we
892 // release the node immediately.
893 ReleaseNode(*clone);
895 // we need to remember to not use this node with server side reference
896 // counting
897 clone->kind |= NODE_KIND_NO_REFCOUNTING;
899 return B_OK;
903 status_t
904 BMediaRoster::ReleaseNode(const media_node& node)
906 CALLED();
907 if (IS_INVALID_NODE(node))
908 return B_MEDIA_BAD_NODE;
910 if (node.kind & NODE_KIND_NO_REFCOUNTING) {
911 TRACE("BMediaRoster::ReleaseNode, trying to release reference "
912 "counting disabled timesource, node %" B_PRId32 ", port %" B_PRId32
913 ", team %" B_PRId32 "\n", node.node, node.port,
914 BPrivate::current_team());
915 return B_OK;
918 server_release_node_request request;
919 server_release_node_reply reply;
920 status_t rv;
922 request.node = node;
923 request.team = BPrivate::current_team();
925 TRACE("BMediaRoster::ReleaseNode, node %" B_PRId32 ", port %" B_PRId32
926 ", team %" B_PRId32 "\n", node.node, node.port,
927 BPrivate::current_team());
929 rv = QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply,
930 sizeof(reply));
931 if (rv != B_OK) {
932 ERROR("BMediaRoster::ReleaseNode FAILED, node %" B_PRId32 ", port %"
933 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port,
934 BPrivate::current_team());
936 return rv;
940 BTimeSource*
941 BMediaRoster::MakeTimeSourceFor(const media_node& forNode)
943 // MakeTimeSourceFor() returns a BTimeSource object
944 // corresponding to the specified node's time source.
946 CALLED();
948 if (IS_SYSTEM_TIMESOURCE(forNode)) {
949 // special handling for the system time source
950 TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time "
951 "source\n");
952 return MediaRosterEx(this)->MakeTimeSourceObject(
953 NODE_SYSTEM_TIMESOURCE_ID);
956 if (IS_INVALID_NODE(forNode)) {
957 ERROR("BMediaRoster::MakeTimeSourceFor: for_node invalid, node %"
958 B_PRId32 ", port %" B_PRId32 ", kinds 0x%" B_PRIx32 "\n",
959 forNode.node, forNode.port, forNode.kind);
960 return NULL;
963 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " enter\n",
964 forNode.node);
966 node_get_timesource_request request;
967 node_get_timesource_reply reply;
968 BTimeSource *source;
969 status_t rv;
971 // ask the node to get it's current timesource id
972 rv = QueryPort(forNode.port, NODE_GET_TIMESOURCE, &request,
973 sizeof(request), &reply, sizeof(reply));
974 if (rv != B_OK) {
975 ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n");
976 return NULL;
979 source = MediaRosterEx(this)->MakeTimeSourceObject(reply.timesource_id);
981 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " leave\n",
982 forNode.node);
984 return source;
988 status_t
989 BMediaRoster::Connect(const media_source& from, const media_destination& to,
990 media_format* _format, media_output* _output, media_input* _input)
992 return BMediaRoster::Connect(from, to, _format, _output, _input, 0);
996 status_t
997 BMediaRoster::Connect(const media_source& from, const media_destination& to,
998 media_format* io_format, media_output* out_output, media_input* out_input,
999 uint32 in_flags, void* _reserved)
1001 CALLED();
1002 if (io_format == NULL || out_output == NULL || out_input == NULL)
1003 return B_BAD_VALUE;
1004 if (IS_INVALID_SOURCE(from)) {
1005 ERROR("BMediaRoster::Connect: media_source invalid\n");
1006 return B_MEDIA_BAD_SOURCE;
1008 if (IS_INVALID_DESTINATION(to)) {
1009 ERROR("BMediaRoster::Connect: media_destination invalid\n");
1010 return B_MEDIA_BAD_DESTINATION;
1013 status_t rv;
1015 // find the output and input nodes
1016 // TODO: isn't there a easier way?
1017 media_node sourcenode;
1018 media_node destnode;
1019 rv = GetNodeFor(NodeIDFor(from.port), &sourcenode);
1020 if (rv != B_OK) {
1021 ERROR("BMediaRoster::Connect: Can't find source node for port %"
1022 B_PRId32 "\n", from.port);
1023 return B_MEDIA_BAD_SOURCE;
1025 ReleaseNode(sourcenode);
1026 rv = GetNodeFor(NodeIDFor(to.port), &destnode);
1027 if (rv != B_OK) {
1028 ERROR("BMediaRoster::Connect: Can't find destination node for port "
1029 "%" B_PRId32 "\n", to.port);
1030 return B_MEDIA_BAD_DESTINATION;
1032 ReleaseNode(destnode);
1034 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) {
1035 ERROR("BMediaRoster::Connect: source node %" B_PRId32 " is not a "
1036 "B_BUFFER_PRODUCER\n", sourcenode.node);
1037 return B_MEDIA_BAD_SOURCE;
1039 if (!(destnode.kind & B_BUFFER_CONSUMER)) {
1040 ERROR("BMediaRoster::Connect: destination node %" B_PRId32 " is not a "
1041 "B_BUFFER_CONSUMER\n", destnode.node);
1042 return B_MEDIA_BAD_DESTINATION;
1045 producer_format_proposal_request request1;
1046 producer_format_proposal_reply reply1;
1048 PRINT_FORMAT("BMediaRoster::Connect calling "
1049 "BBufferProducer::FormatProposal with format ", *io_format);
1051 // BBufferProducer::FormatProposal
1052 request1.output = from;
1053 request1.format = *io_format;
1054 rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1,
1055 sizeof(request1), &reply1, sizeof(reply1));
1056 if (rv != B_OK) {
1057 ERROR("BMediaRoster::Connect: aborted after "
1058 "BBufferProducer::FormatProposal, status = %#" B_PRIx32 "\n",rv);
1059 return rv;
1061 // reply1.format now contains the format proposed by the producer
1063 consumer_accept_format_request request2;
1064 consumer_accept_format_reply reply2;
1066 PRINT_FORMAT("BMediaRoster::Connect calling "
1067 "BBufferConsumer::AcceptFormat with format ", reply1.format);
1069 // BBufferConsumer::AcceptFormat
1070 request2.dest = to;
1071 request2.format = reply1.format;
1072 rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2,
1073 sizeof(request2), &reply2, sizeof(reply2));
1074 if (rv != B_OK) {
1075 ERROR("BMediaRoster::Connect: aborted after "
1076 "BBufferConsumer::AcceptFormat, status = %#" B_PRIx32 "\n",rv);
1077 return rv;
1079 // reply2.format now contains the format accepted by the consumer
1081 // BBufferProducer::PrepareToConnect
1082 producer_prepare_to_connect_request request3;
1083 producer_prepare_to_connect_reply reply3;
1085 PRINT_FORMAT("BMediaRoster::Connect calling "
1086 "BBufferProducer::PrepareToConnect with format", reply2.format);
1088 request3.source = from;
1089 request3.destination = to;
1090 request3.format = reply2.format;
1091 strcpy(request3.name, "XXX some default name"); // TODO: fix this
1092 rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3,
1093 sizeof(request3), &reply3, sizeof(reply3));
1094 if (rv != B_OK) {
1095 ERROR("BMediaRoster::Connect: aborted after "
1096 "BBufferProducer::PrepareToConnect, status = %#" B_PRIx32 "\n", rv);
1097 return rv;
1099 // reply3.format is still our pretty media format
1100 // reply3.out_source the real source to be used for the connection
1101 // reply3.name the name BBufferConsumer::Connected will see in the
1102 // outInput->name argument
1104 // BBufferConsumer::Connected
1105 consumer_connected_request request4;
1106 consumer_connected_reply reply4;
1107 status_t con_status;
1109 PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::Connected() "
1110 "with format ", reply3.format);
1112 request4.input.node = destnode;
1113 request4.input.source = reply3.out_source;
1114 request4.input.destination = to;
1115 request4.input.format = reply3.format;
1116 strcpy(request4.input.name, reply3.name);
1118 con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4,
1119 sizeof(request4), &reply4, sizeof(reply4));
1120 if (con_status != B_OK) {
1121 ERROR("BMediaRoster::Connect: aborting after "
1122 "BBufferConsumer::Connected, status = %#" B_PRIx32 "\n",
1123 con_status);
1124 // we do NOT return here!
1126 // con_status contains the status code to be supplied to
1127 // BBufferProducer::Connect's status argument
1128 // reply4.input contains the media_input that describes the connection
1129 // from the consumer point of view
1131 // BBufferProducer::Connect
1132 producer_connect_request request5;
1133 producer_connect_reply reply5;
1135 PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::Connect with "
1136 "format ", reply4.input.format);
1138 request5.error = con_status;
1139 request5.source = reply3.out_source;
1140 request5.destination = reply4.input.destination;
1141 request5.format = reply4.input.format;
1142 strcpy(request5.name, reply4.input.name);
1143 rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5,
1144 sizeof(request5), &reply5, sizeof(reply5));
1145 if (con_status != B_OK) {
1146 ERROR("BMediaRoster::Connect: aborted\n");
1147 return con_status;
1149 if (rv != B_OK) {
1150 ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect()"
1151 ", status = %#" B_PRIx32 "\n", rv);
1152 return rv;
1154 // reply5.name contains the name assigned to the connection by the producer
1156 // initilize connection info
1157 *io_format = reply4.input.format;
1158 *out_input = reply4.input;
1159 out_output->node = sourcenode;
1160 out_output->source = reply4.input.source;
1161 out_output->destination = reply4.input.destination;
1162 out_output->format = reply4.input.format;
1163 strcpy(out_output->name, reply5.name);
1165 // the connection is now made
1166 PRINT_FORMAT(" format", *io_format);
1167 PRINT_INPUT(" input", *out_input);
1168 PRINT_OUTPUT(" output", *out_output);
1170 // TODO: register connection with server
1171 // TODO: we should just send a notification, instead of republishing all
1172 // endpoints
1173 List<media_output> outlist;
1174 List<media_input> inlist;
1175 if (MediaRosterEx(this)->GetAllOutputs(out_output->node , &outlist) == B_OK)
1176 MediaRosterEx(this)->PublishOutputs(out_output->node , &outlist);
1177 if (MediaRosterEx(this)->GetAllInputs(out_input->node , &inlist) == B_OK)
1178 MediaRosterEx(this)->PublishInputs(out_input->node, &inlist);
1180 // TODO: if (mute) BBufferProducer::EnableOutput(false)
1181 if (in_flags & B_CONNECT_MUTED) {
1184 // send a notification
1185 BPrivate::media::notifications::ConnectionMade(*out_input, *out_output,
1186 *io_format);
1188 return B_OK;
1192 status_t
1193 BMediaRoster::Disconnect(media_node_id source_nodeid,
1194 const media_source& source, media_node_id destination_nodeid,
1195 const media_destination& destination)
1197 CALLED();
1198 if (IS_INVALID_NODEID(source_nodeid)) {
1199 ERROR("BMediaRoster::Disconnect: source media_node_id invalid\n");
1200 return B_MEDIA_BAD_SOURCE;
1202 if (IS_INVALID_NODEID(destination_nodeid)) {
1203 ERROR("BMediaRoster::Disconnect: destination media_node_id invalid\n");
1204 return B_MEDIA_BAD_DESTINATION;
1206 if (IS_INVALID_SOURCE(source)) {
1207 ERROR("BMediaRoster::Disconnect: media_source invalid\n");
1208 return B_MEDIA_BAD_SOURCE;
1210 if (IS_INVALID_DESTINATION(destination)) {
1211 ERROR("BMediaRoster::Disconnect: media_destination invalid\n");
1212 return B_MEDIA_BAD_DESTINATION;
1215 producer_disconnect_request request2;
1216 producer_disconnect_reply reply2;
1217 consumer_disconnected_request request1;
1218 consumer_disconnected_reply reply1;
1219 status_t rv1, rv2;
1221 // TODO: we should ask the server if this connection really exists
1223 request1.source = source;
1224 request1.destination = destination;
1225 request2.source = source;
1226 request2.destination = destination;
1228 rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1,
1229 sizeof(request1), &reply1, sizeof(reply1));
1230 rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2,
1231 sizeof(request2), &reply2, sizeof(reply2));
1233 // TODO: unregister connection with server
1234 // TODO: we should just send a notification, instead of republishing all
1235 // endpoints
1236 List<media_output> outlist;
1237 List<media_input> inlist;
1238 media_node sourcenode;
1239 media_node destnode;
1240 if (GetNodeFor(source_nodeid, &sourcenode) == B_OK) {
1241 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) {
1242 ERROR("BMediaRoster::Disconnect: source_nodeid %" B_PRId32
1243 " is not a B_BUFFER_PRODUCER\n", source_nodeid);
1245 if (MediaRosterEx(this)->GetAllOutputs(sourcenode , &outlist) == B_OK)
1246 MediaRosterEx(this)->PublishOutputs(sourcenode , &outlist);
1247 ReleaseNode(sourcenode);
1248 } else {
1249 ERROR("BMediaRoster::Disconnect: GetNodeFor source_nodeid %" B_PRId32
1250 " failed\n", source_nodeid);
1252 if (GetNodeFor(destination_nodeid, &destnode) == B_OK) {
1253 if (!(destnode.kind & B_BUFFER_CONSUMER)) {
1254 ERROR("BMediaRoster::Disconnect: destination_nodeid %" B_PRId32
1255 " is not a B_BUFFER_CONSUMER\n", destination_nodeid);
1257 if (MediaRosterEx(this)->GetAllInputs(destnode , &inlist) == B_OK)
1258 MediaRosterEx(this)->PublishInputs(destnode, &inlist);
1259 ReleaseNode(destnode);
1260 } else {
1261 ERROR("BMediaRoster::Disconnect: GetNodeFor destination_nodeid %"
1262 B_PRId32 " failed\n", destination_nodeid);
1265 // send a notification
1266 BPrivate::media::notifications::ConnectionBroken(source, destination);
1268 return rv1 != B_OK || rv2 != B_OK ? B_ERROR : B_OK;
1272 status_t
1273 BMediaRoster::Disconnect(const media_output& output, const media_input& input)
1275 if (IS_INVALID_NODEID(output.node.node)) {
1276 printf("BMediaRoster::Disconnect: output.node.node %" B_PRId32
1277 " invalid\n", output.node.node);
1278 return B_MEDIA_BAD_SOURCE;
1280 if (IS_INVALID_NODEID(input.node.node)) {
1281 printf("BMediaRoster::Disconnect: input.node.node %" B_PRId32
1282 " invalid\n", input.node.node);
1283 return B_MEDIA_BAD_DESTINATION;
1285 if (!(output.node.kind & B_BUFFER_PRODUCER)) {
1286 printf("BMediaRoster::Disconnect: output.node.kind 0x%" B_PRIx32
1287 " is no B_BUFFER_PRODUCER\n", output.node.kind);
1288 return B_MEDIA_BAD_SOURCE;
1290 if (!(input.node.kind & B_BUFFER_CONSUMER)) {
1291 printf("BMediaRoster::Disconnect: input.node.kind 0x%" B_PRIx32
1292 " is no B_BUFFER_PRODUCER\n", input.node.kind);
1293 return B_MEDIA_BAD_DESTINATION;
1295 if (input.source.port != output.source.port) {
1296 printf("BMediaRoster::Disconnect: input.source.port %" B_PRId32
1297 " doesn't match output.source.port %" B_PRId32 "\n",
1298 input.source.port, output.source.port);
1299 return B_MEDIA_BAD_SOURCE;
1301 if (input.source.id != output.source.id) {
1302 printf("BMediaRoster::Disconnect: input.source.id %" B_PRId32
1303 " doesn't match output.source.id %" B_PRId32 "\n", input.source.id,
1304 output.source.id);
1305 return B_MEDIA_BAD_SOURCE;
1307 if (input.destination.port != output.destination.port) {
1308 printf("BMediaRoster::Disconnect: input.destination.port %" B_PRId32
1309 " doesn't match output.destination.port %" B_PRId32 "\n",
1310 input.destination.port, output.destination.port);
1311 return B_MEDIA_BAD_DESTINATION;
1313 if (input.destination.id != output.destination.id) {
1314 printf("BMediaRoster::Disconnect: input.destination.id %" B_PRId32
1315 " doesn't match output.destination.id %" B_PRId32 "\n",
1316 input.destination.id, output.destination.id);
1317 return B_MEDIA_BAD_DESTINATION;
1320 return Disconnect(output.node.node, output.source, input.node.node,
1321 input.destination);
1325 status_t
1326 BMediaRoster::StartNode(const media_node& node, bigtime_t atPerformanceTime)
1328 CALLED();
1329 if (node.node <= 0)
1330 return B_MEDIA_BAD_NODE;
1332 TRACE("BMediaRoster::StartNode, node %" B_PRId32 ", at perf %" B_PRId64
1333 "\n", node.node, atPerformanceTime);
1335 node_start_command command;
1336 command.performance_time = atPerformanceTime;
1338 return SendToPort(node.port, NODE_START, &command, sizeof(command));
1342 status_t
1343 BMediaRoster::StopNode(const media_node& node, bigtime_t atPerformanceTime,
1344 bool immediate)
1346 CALLED();
1347 if (IS_INVALID_NODE(node))
1348 return B_MEDIA_BAD_NODE;
1350 TRACE("BMediaRoster::StopNode, node %" B_PRId32 ", at perf %" B_PRId64
1351 " %s\n", node.node, atPerformanceTime, immediate ? "NOW" : "");
1353 node_stop_command command;
1354 command.performance_time = atPerformanceTime;
1355 command.immediate = immediate;
1357 return SendToPort(node.port, NODE_STOP, &command, sizeof(command));
1361 status_t
1362 BMediaRoster::SeekNode(const media_node& node, bigtime_t toMediaTime,
1363 bigtime_t atPerformanceTime)
1365 CALLED();
1366 if (IS_INVALID_NODE(node))
1367 return B_MEDIA_BAD_NODE;
1369 TRACE("BMediaRoster::SeekNode, node %" B_PRId32 ", at perf %" B_PRId64
1370 ", to perf %" B_PRId64 "\n", node.node, atPerformanceTime, toMediaTime);
1372 node_seek_command command;
1373 command.media_time = toMediaTime;
1374 command.performance_time = atPerformanceTime;
1376 return SendToPort(node.port, NODE_SEEK, &command, sizeof(command));
1380 status_t
1381 BMediaRoster::StartTimeSource(const media_node& node, bigtime_t atRealTime)
1383 CALLED();
1384 if (IS_SYSTEM_TIMESOURCE(node)) {
1385 // TODO: debug this
1386 //ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is system timesource\n", node.node);
1387 return B_OK;
1389 // if (IS_SHADOW_TIMESOURCE(node)) {
1390 // // TODO: debug this
1391 // ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is shadow timesource\n", node.node);
1392 // return B_OK;
1393 // }
1394 if (IS_INVALID_NODE(node)) {
1395 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " invalid\n",
1396 node.node);
1397 return B_MEDIA_BAD_NODE;
1399 if ((node.kind & B_TIME_SOURCE) == 0) {
1400 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32
1401 " is no timesource\n", node.node);
1402 return B_MEDIA_BAD_NODE;
1405 TRACE("BMediaRoster::StartTimeSource, node %" B_PRId32 ", at real %"
1406 B_PRId64 "\n", node.node, atRealTime);
1408 BTimeSource::time_source_op_info msg;
1409 msg.op = BTimeSource::B_TIMESOURCE_START;
1410 msg.real_time = atRealTime;
1412 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1416 status_t
1417 BMediaRoster::StopTimeSource(const media_node& node, bigtime_t atRealTime,
1418 bool immediate)
1420 CALLED();
1421 if (IS_SYSTEM_TIMESOURCE(node)) {
1422 // TODO: debug this
1423 //ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node);
1424 return B_OK;
1426 // if (IS_SHADOW_TIMESOURCE(node)) {
1427 // // TODO: debug this
1428 // ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node);
1429 // return B_OK;
1430 // }
1431 if (IS_INVALID_NODE(node)) {
1432 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " invalid\n",
1433 node.node);
1434 return B_MEDIA_BAD_NODE;
1436 if ((node.kind & B_TIME_SOURCE) == 0) {
1437 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " is no "
1438 "timesource\n", node.node);
1439 return B_MEDIA_BAD_NODE;
1442 TRACE("BMediaRoster::StopTimeSource, node %" B_PRId32 ", at real %" B_PRId64
1443 " %s\n", node.node, atRealTime, immediate ? "NOW" : "");
1445 BTimeSource::time_source_op_info msg;
1446 msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY
1447 : BTimeSource::B_TIMESOURCE_STOP;
1448 msg.real_time = atRealTime;
1450 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1454 status_t
1455 BMediaRoster::SeekTimeSource(const media_node& node,
1456 bigtime_t toPerformanceTime, bigtime_t atRealTime)
1458 CALLED();
1459 if (IS_SYSTEM_TIMESOURCE(node)) {
1460 // TODO: debug this
1461 // ERROR("BMediaRoster::SeekTimeSource node %ld is system timesource\n", node.node);
1462 // you can't seek the system time source, but
1463 // returning B_ERROR would break StampTV
1464 return B_OK;
1466 // if (IS_SHADOW_TIMESOURCE(node)) {
1467 // // TODO: debug this
1468 // ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node);
1469 // return B_OK;
1470 // }
1471 if (IS_INVALID_NODE(node)) {
1472 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32 " invalid\n",
1473 node.node);
1474 return B_MEDIA_BAD_NODE;
1476 if ((node.kind & B_TIME_SOURCE) == 0) {
1477 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32
1478 " is no timesource\n", node.node);
1479 return B_MEDIA_BAD_NODE;
1482 TRACE("BMediaRoster::SeekTimeSource, node %" B_PRId32 ", at real %" B_PRId64
1483 ", to perf %" B_PRId64 "\n", node.node, atRealTime, toPerformanceTime);
1485 BTimeSource::time_source_op_info msg;
1486 msg.op = BTimeSource::B_TIMESOURCE_SEEK;
1487 msg.real_time = atRealTime;
1488 msg.performance_time = toPerformanceTime;
1490 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg));
1494 status_t
1495 BMediaRoster::SyncToNode(const media_node& node, bigtime_t atTime,
1496 bigtime_t timeout)
1498 TRACE("BMediaRoster::SyncToNode, node %" B_PRId32 ", at real %" B_PRId64
1499 ", at timeout %" B_PRId64 "\n", node.node, atTime, timeout);
1500 if (IS_INVALID_NODE(node))
1501 return B_MEDIA_BAD_NODE;
1503 port_id waitPort = create_port(1, "SyncToNode wait port");
1504 if (waitPort < B_OK)
1505 return waitPort;
1507 node_sync_to_request request;
1508 node_sync_to_reply reply;
1509 request.performance_time = atTime;
1510 request.port = waitPort;
1512 status_t status = QueryPort(node.port, NODE_SYNC_TO, &request,
1513 sizeof(request), &reply, sizeof(reply));
1515 if (status == B_OK) {
1516 ssize_t readSize = read_port_etc(waitPort, NULL, &status,
1517 sizeof(status), B_TIMEOUT, timeout);
1518 if (readSize < 0)
1519 status = readSize;
1521 close_port(waitPort);
1522 delete_port(waitPort);
1523 return status;
1527 status_t
1528 BMediaRoster::SetRunModeNode(const media_node& node, BMediaNode::run_mode mode)
1530 TRACE("BMediaRoster::SetRunModeNode, node %" B_PRId32 ", mode %d\n",
1531 node.node, mode);
1532 if (IS_INVALID_NODE(node))
1533 return B_MEDIA_BAD_NODE;
1535 node_set_run_mode_command msg;
1536 msg.mode = mode;
1538 return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg));
1542 status_t
1543 BMediaRoster::PrerollNode(const media_node& node)
1545 CALLED();
1546 if (IS_INVALID_NODE(node))
1547 return B_MEDIA_BAD_NODE;
1549 char dummy;
1550 return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy));
1554 status_t
1555 BMediaRoster::RollNode(const media_node& node, bigtime_t startPerformance,
1556 bigtime_t stopPerformance, bigtime_t atMediaTime)
1558 CALLED();
1559 if (IS_INVALID_NODE(node))
1560 return B_MEDIA_BAD_NODE;
1562 TRACE("BMediaRoster::RollNode, node %" B_PRId32 ", at start perf %"
1563 B_PRId64 ", at stop perf %" B_PRId64 ", at media time %"
1564 B_PRId64 "\n", node.node, startPerformance,
1565 stopPerformance, atMediaTime);
1567 node_roll_command command;
1568 command.start_performance_time = startPerformance;
1569 command.stop_performance_time = stopPerformance;
1570 command.seek_media_time = atMediaTime;
1572 return write_port(node.port, NODE_ROLL, &command, sizeof(command));
1576 status_t
1577 BMediaRoster::SetProducerRunModeDelay(const media_node& node,
1578 bigtime_t delay, BMediaNode::run_mode mode)
1580 TRACE("BMediaRoster::SetProducerRunModeDelay, node %" B_PRId32 ", delay %"
1581 B_PRId64 ", mode %d\n", node.node, delay, mode);
1582 if (IS_INVALID_NODE(node))
1583 return B_MEDIA_BAD_NODE;
1584 if ((node.kind & B_BUFFER_PRODUCER) == 0)
1585 return B_MEDIA_BAD_NODE;
1587 producer_set_run_mode_delay_command command;
1588 command.mode = mode;
1589 command.delay = delay;
1591 return SendToPort(node.port, PRODUCER_SET_RUN_MODE_DELAY, &command,
1592 sizeof(command));
1596 status_t
1597 BMediaRoster::SetProducerRate(const media_node& producer, int32 numer,
1598 int32 denom)
1600 CALLED();
1601 if (IS_INVALID_NODE(producer))
1602 return B_MEDIA_BAD_NODE;
1603 if ((producer.kind & B_BUFFER_PRODUCER) == 0)
1604 return B_MEDIA_BAD_NODE;
1606 producer_set_play_rate_request request;
1607 request.numer = numer;
1608 request.denom = denom;
1609 status_t status = write_port(producer.node, PRODUCER_SET_PLAY_RATE,
1610 &request, sizeof(request));
1611 if (status != B_OK)
1612 return status;
1614 producer_set_play_rate_reply reply;
1615 int32 code;
1616 status = read_port(request.reply_port, &code, &reply, sizeof(reply));
1618 return status < B_OK ? status : reply.result;
1622 /*! Nodes will have available inputs/outputs as long as they are capable
1623 of accepting more connections. The node may create an additional
1624 output or input as the currently available is taken into usage.
1626 status_t
1627 BMediaRoster::GetLiveNodeInfo(const media_node& node,
1628 live_node_info* out_live_info)
1630 CALLED();
1631 if (out_live_info == NULL)
1632 return B_BAD_VALUE;
1633 if (IS_INVALID_NODE(node))
1634 return B_MEDIA_BAD_NODE;
1636 server_get_live_node_info_request request;
1637 server_get_live_node_info_reply reply;
1638 status_t rv;
1640 request.node = node;
1642 rv = QueryServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request),
1643 &reply, sizeof(reply));
1644 if (rv != B_OK)
1645 return rv;
1647 *out_live_info = reply.live_info;
1648 return B_OK;
1652 status_t
1653 BMediaRoster::GetLiveNodes(live_node_info* liveNodes, int32* _totalCount,
1654 const media_format* hasInput, const media_format* hasOutput,
1655 const char* name, uint64 nodeKinds)
1657 CALLED();
1658 if (liveNodes == NULL || _totalCount == NULL || *_totalCount <= 0)
1659 return B_BAD_VALUE;
1661 // TODO: we also support the wildcard search as GetDormantNodes does.
1662 // This needs to be documented
1664 server_get_live_nodes_request request;
1665 request.team = BPrivate::current_team();
1667 request.max_count = *_totalCount;
1668 request.has_input = hasInput != NULL;
1669 if (hasInput != NULL) {
1670 // TODO: we should not make a flat copy of media_format
1671 request.input_format = *hasInput;
1673 request.has_output = hasOutput != NULL;
1674 if (hasOutput != NULL) {
1675 // TODO: we should not make a flat copy of media_format
1676 request.output_format = *hasOutput;
1678 request.has_name = name != NULL;
1679 if (name != NULL)
1680 strlcpy(request.name, name, sizeof(request.name));
1681 request.require_kinds = nodeKinds;
1683 server_get_live_nodes_reply reply;
1684 status_t status = QueryServer(SERVER_GET_LIVE_NODES, &request,
1685 sizeof(request), &reply, sizeof(reply));
1686 if (status != B_OK) {
1687 ERROR("BMediaRoster::GetLiveNodes failed querying server: %s\n",
1688 strerror(status));
1689 *_totalCount = 0;
1690 return status;
1693 const live_node_info* info;
1694 if (reply.area >= 0)
1695 info = (live_node_info*)reply.address;
1696 else
1697 info = reply.live_info;
1699 for (int32 i = 0; i < reply.count; i++)
1700 liveNodes[i] = info[i];
1702 if (reply.area >= 0)
1703 delete_area(reply.area);
1705 *_totalCount = reply.count;
1706 return B_OK;
1710 status_t
1711 BMediaRoster::GetFreeInputsFor(const media_node& node,
1712 media_input * out_free_inputs, int32 buf_num_inputs,
1713 int32 * out_total_count, media_type filter_type)
1715 CALLED();
1716 if (IS_INVALID_NODE(node)) {
1717 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %"
1718 B_PRId32 " invalid\n", node.node, node.port);
1719 return B_MEDIA_BAD_NODE;
1721 if ((node.kind & B_BUFFER_CONSUMER) == 0) {
1722 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %"
1723 B_PRId32 " is not a consumer\n", node.node, node.port);
1724 return B_MEDIA_BAD_NODE;
1726 if (out_free_inputs == NULL || out_total_count == NULL)
1727 return B_BAD_VALUE;
1729 List<media_input> list;
1730 media_input *input;
1731 status_t rv;
1733 *out_total_count = 0;
1735 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1736 if (B_OK != rv)
1737 return rv;
1739 PRINT(4, "BMediaRoster::GetFreeInputsFor node %" B_PRId32 ", max %" B_PRId32
1740 ", filter-type %" B_PRId32 "\n", node.node, buf_num_inputs,
1741 filter_type);
1743 int32 i;
1744 for (i = 0, list.Rewind(); list.GetNext(&input);) {
1745 if (filter_type != B_MEDIA_UNKNOWN_TYPE
1746 && filter_type != input->format.type) {
1747 // media_type used, but doesn't match
1748 continue;
1750 if (input->source != media_source::null) {
1751 // consumer source already connected
1752 continue;
1755 out_free_inputs[i] = *input;
1756 *out_total_count += 1;
1757 buf_num_inputs -= 1;
1758 #if DEBUG >= 3
1759 PRINT_OUTPUT(" input", out_free_inputs[i]);
1760 #endif
1761 if (buf_num_inputs == 0)
1762 break;
1763 i++;
1766 MediaRosterEx(this)->PublishInputs(node, &list);
1767 return B_OK;
1771 status_t
1772 BMediaRoster::GetConnectedInputsFor(const media_node& node,
1773 media_input* out_active_inputs, int32 buf_num_inputs,
1774 int32* out_total_count)
1776 CALLED();
1777 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1778 return B_MEDIA_BAD_NODE;
1779 if (out_active_inputs == NULL || out_total_count == NULL)
1780 return B_BAD_VALUE;
1782 List<media_input> list;
1783 media_input *input;
1784 status_t rv;
1786 *out_total_count = 0;
1788 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1789 if (B_OK != rv)
1790 return rv;
1792 PRINT(4, "BMediaRoster::GetConnectedInputsFor node %" B_PRId32 ", max %"
1793 B_PRId32 "\n", node.node, buf_num_inputs);
1795 int32 i;
1796 for (i = 0, list.Rewind(); list.GetNext(&input);) {
1797 if (input->source == media_source::null)
1798 continue; // consumer source not connected
1799 out_active_inputs[i] = *input;
1800 *out_total_count += 1;
1801 buf_num_inputs -= 1;
1802 #if DEBUG >= 3
1803 PRINT_OUTPUT(" input ", out_active_inputs[i]);
1804 #endif
1805 if (buf_num_inputs == 0)
1806 break;
1807 i++;
1810 MediaRosterEx(this)->PublishInputs(node, &list);
1811 return B_OK;
1815 status_t
1816 BMediaRoster::GetAllInputsFor(const media_node& node, media_input* out_inputs,
1817 int32 buf_num_inputs, int32* out_total_count)
1819 CALLED();
1820 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0)
1821 return B_MEDIA_BAD_NODE;
1822 if (out_inputs == NULL || out_total_count == NULL)
1823 return B_BAD_VALUE;
1825 List<media_input> list;
1826 media_input *input;
1827 status_t rv;
1829 *out_total_count = 0;
1831 rv = MediaRosterEx(this)->GetAllInputs(node, &list);
1832 if (B_OK != rv)
1833 return rv;
1835 PRINT(4, "BMediaRoster::GetAllInputsFor node %" B_PRId32 ", max %" B_PRId32
1836 "\n", node.node, buf_num_inputs);
1838 int32 i;
1839 for (i = 0, list.Rewind(); list.GetNext(&input); i++) {
1840 out_inputs[i] = *input;
1841 *out_total_count += 1;
1842 buf_num_inputs -= 1;
1843 #if DEBUG >= 3
1844 PRINT_OUTPUT(" input ", out_inputs[i]);
1845 #endif
1846 if (buf_num_inputs == 0)
1847 break;
1850 MediaRosterEx(this)->PublishInputs(node, &list);
1851 return B_OK;
1855 status_t
1856 BMediaRoster::GetFreeOutputsFor(const media_node& node,
1857 media_output* out_free_outputs, int32 buf_num_outputs,
1858 int32* out_total_count, media_type filter_type)
1860 CALLED();
1861 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1862 return B_MEDIA_BAD_NODE;
1863 if (out_free_outputs == NULL || out_total_count == NULL)
1864 return B_BAD_VALUE;
1866 List<media_output> list;
1867 media_output *output;
1868 status_t rv;
1870 *out_total_count = 0;
1872 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1873 if (B_OK != rv)
1874 return rv;
1876 PRINT(4, "BMediaRoster::GetFreeOutputsFor node %" B_PRId32 ", max %"
1877 B_PRId32 ", filter-type %" B_PRId32 "\n", node.node, buf_num_outputs,
1878 filter_type);
1880 int32 i;
1881 for (i = 0, list.Rewind(); list.GetNext(&output);) {
1882 if (filter_type != B_MEDIA_UNKNOWN_TYPE
1883 && filter_type != output->format.type) {
1884 // media_type used, but doesn't match
1885 continue;
1887 if (output->destination != media_destination::null) {
1888 // producer destination already connected
1889 continue;
1892 out_free_outputs[i] = *output;
1893 *out_total_count += 1;
1894 buf_num_outputs -= 1;
1895 #if DEBUG >= 3
1896 PRINT_OUTPUT(" output ", out_free_outputs[i]);
1897 #endif
1898 if (buf_num_outputs == 0)
1899 break;
1900 i++;
1903 MediaRosterEx(this)->PublishOutputs(node, &list);
1904 return B_OK;
1908 status_t
1909 BMediaRoster::GetConnectedOutputsFor(const media_node& node,
1910 media_output* out_active_outputs, int32 buf_num_outputs,
1911 int32* out_total_count)
1913 CALLED();
1914 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1915 return B_MEDIA_BAD_NODE;
1916 if (out_active_outputs == NULL || out_total_count == NULL)
1917 return B_BAD_VALUE;
1919 List<media_output> list;
1920 media_output *output;
1921 status_t rv;
1923 *out_total_count = 0;
1925 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1926 if (B_OK != rv)
1927 return rv;
1929 PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %" B_PRId32 ", max %"
1930 B_PRId32 "\n", node.node, buf_num_outputs);
1932 int32 i;
1933 for (i = 0, list.Rewind(); list.GetNext(&output);) {
1934 if (output->destination == media_destination::null) {
1935 // producer destination not connected
1936 continue;
1938 out_active_outputs[i] = *output;
1939 *out_total_count += 1;
1940 buf_num_outputs -= 1;
1941 #if DEBUG >= 3
1942 PRINT_OUTPUT(" output ", out_active_outputs[i]);
1943 #endif
1944 if (buf_num_outputs == 0)
1945 break;
1946 i++;
1949 MediaRosterEx(this)->PublishOutputs(node, &list);
1950 return B_OK;
1954 status_t
1955 BMediaRoster::GetAllOutputsFor(const media_node& node,
1956 media_output* out_outputs, int32 buf_num_outputs, int32* out_total_count)
1958 CALLED();
1959 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0)
1960 return B_MEDIA_BAD_NODE;
1961 if (out_outputs == NULL || out_total_count == NULL)
1962 return B_BAD_VALUE;
1964 List<media_output> list;
1965 media_output *output;
1966 status_t rv;
1968 *out_total_count = 0;
1970 rv = MediaRosterEx(this)->GetAllOutputs(node, &list);
1971 if (B_OK != rv)
1972 return rv;
1974 PRINT(4, "BMediaRoster::GetAllOutputsFor node %" B_PRId32 ", max %" B_PRId32
1975 "\n", node.node, buf_num_outputs);
1977 int32 i;
1978 for (i = 0, list.Rewind(); list.GetNext(&output); i++) {
1979 out_outputs[i] = *output;
1980 *out_total_count += 1;
1981 buf_num_outputs -= 1;
1982 #if DEBUG >= 3
1983 PRINT_OUTPUT(" output ", out_outputs[i]);
1984 #endif
1985 if (buf_num_outputs == 0)
1986 break;
1989 MediaRosterEx(this)->PublishOutputs(node, &list);
1990 return B_OK;
1994 status_t
1995 BMediaRoster::StartWatching(const BMessenger& where)
1997 CALLED();
1998 if (!where.IsValid()) {
1999 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
2000 return B_BAD_VALUE;
2002 return BPrivate::media::notifications::Register(where, media_node::null,
2003 B_MEDIA_WILDCARD);
2007 status_t
2008 BMediaRoster::StartWatching(const BMessenger & where, int32 notificationType)
2010 CALLED();
2011 if (!where.IsValid()) {
2012 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
2013 return B_BAD_VALUE;
2015 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
2016 notificationType)) {
2017 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
2018 return B_BAD_VALUE;
2021 // NOTE: we support only explicitly B_MEDIA_SERVER_STARTED/QUIT
2022 // notifications. This should be cleared in documentation.
2024 return BPrivate::media::notifications::Register(where, media_node::null,
2025 notificationType);
2029 status_t
2030 BMediaRoster::StartWatching(const BMessenger& where, const media_node& node,
2031 int32 notificationType)
2033 CALLED();
2034 if (!where.IsValid()) {
2035 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
2036 return B_BAD_VALUE;
2038 if (IS_INVALID_NODE(node)) {
2039 ERROR("BMediaRoster::StartWatching: node invalid!\n");
2040 return B_MEDIA_BAD_NODE;
2042 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
2043 notificationType)) {
2044 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
2045 return B_BAD_VALUE;
2047 return BPrivate::media::notifications::Register(where, node,
2048 notificationType);
2052 status_t
2053 BMediaRoster::StopWatching(const BMessenger& where)
2055 CALLED();
2056 // messenger may already be invalid, so we don't check this
2057 return BPrivate::media::notifications::Unregister(where, media_node::null,
2058 B_MEDIA_WILDCARD);
2062 status_t
2063 BMediaRoster::StopWatching(const BMessenger& where, int32 notificationType)
2065 CALLED();
2066 // messenger may already be invalid, so we don't check this
2067 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
2068 notificationType)) {
2069 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
2070 return B_BAD_VALUE;
2072 return BPrivate::media::notifications::Unregister(where, media_node::null,
2073 notificationType);
2077 status_t
2078 BMediaRoster::StopWatching(const BMessenger& where, const media_node& node,
2079 int32 notificationType)
2081 CALLED();
2082 // messenger may already be invalid, so we don't check this
2083 if (IS_INVALID_NODE(node)) {
2084 ERROR("BMediaRoster::StopWatching: node invalid!\n");
2085 return B_MEDIA_BAD_NODE;
2087 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
2088 notificationType)) {
2089 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
2090 return B_BAD_VALUE;
2092 return BPrivate::media::notifications::Unregister(where, node,
2093 notificationType);
2097 status_t
2098 BMediaRoster::RegisterNode(BMediaNode* node)
2100 CALLED();
2101 // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too)
2102 return MediaRosterEx(this)->RegisterNode(node, -1, 0);
2106 status_t
2107 BMediaRosterEx::RegisterNode(BMediaNode* node, media_addon_id addOnID,
2108 int32 flavorID)
2110 CALLED();
2111 if (node == NULL)
2112 return B_BAD_VALUE;
2114 // some sanity check
2115 // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here.
2116 // Perhaps we don't need it.
2117 DEBUG_ONLY(
2118 int32 testFlavorID;
2119 BMediaAddOn* addon = node->AddOn(&testFlavorID);
2121 ASSERT(addOnID == (addon != NULL ? addon->AddonID() : -1));
2122 // ASSERT(flavorID == testFlavorID);
2125 server_register_node_request request;
2126 server_register_node_reply reply;
2128 request.add_on_id = addOnID;
2129 request.flavor_id = flavorID;
2130 strcpy(request.name, node->Name());
2131 request.kinds = node->Kinds();
2132 request.port = node->ControlPort();
2133 request.team = BPrivate::current_team();
2134 request.timesource_id = node->fTimeSourceID;
2136 TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port "
2137 "%" B_PRId32 ", kinds 0x%" B_PRIx64 ", team %" B_PRId32 ", name '%s'\n",
2138 request.port, request.kinds, request.team, request.name);
2140 status_t status = QueryServer(SERVER_REGISTER_NODE, &request,
2141 sizeof(request), &reply, sizeof(reply));
2142 if (status != B_OK) {
2143 ERROR("BMediaRoster::RegisterNode: failed to register node %s: %s\n",
2144 node->Name(), strerror(status));
2145 return status;
2148 TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE "
2149 "finished\n");
2151 // we are a friend class of BMediaNode and initialize this member variable
2152 node->fNodeID = reply.node_id;
2153 ASSERT(reply.node_id == node->Node().node);
2154 ASSERT(reply.node_id == node->ID());
2156 // if the BMediaNode also inherits from BTimeSource, we need to call
2157 // BTimeSource::FinishCreate()
2158 if ((node->Kinds() & B_TIME_SOURCE) != 0) {
2159 if (BTimeSource* timeSource = dynamic_cast<BTimeSource*>(node))
2160 timeSource->FinishCreate();
2163 // call the callback
2164 node->NodeRegistered();
2166 TRACE("BMediaRoster::RegisterNode: NodeRegistered callback finished\n");
2168 TRACE("BMediaRoster::RegisterNode: publishing inputs/outputs\n");
2170 // register existing inputs and outputs with the
2171 // media_server, this allows GetLiveNodes() to work
2172 // with created, but unconnected nodes.
2173 // The node control loop might not be running, or might deadlock
2174 // if we send a message and wait for a reply here.
2175 // We have a pointer to the node, and thus call the functions directly
2177 if ((node->Kinds() & B_BUFFER_PRODUCER) != 0) {
2178 if (BBufferProducer* producer = dynamic_cast<BBufferProducer*>(node)) {
2179 List<media_output> list;
2180 if (GetAllOutputs(producer, &list) == B_OK)
2181 PublishOutputs(node->Node(), &list);
2184 if ((node->Kinds() & B_BUFFER_CONSUMER) != 0) {
2185 if (BBufferConsumer* consumer = dynamic_cast<BBufferConsumer*>(node)) {
2186 List<media_input> list;
2187 if (GetAllInputs(consumer, &list) == B_OK)
2188 PublishInputs(node->Node(), &list);
2192 TRACE("BMediaRoster::RegisterNode: sending NodesCreated\n");
2194 BPrivate::media::notifications::NodesCreated(&reply.node_id, 1);
2196 TRACE("BMediaRoster::RegisterNode: finished\n");
2199 TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld,
2200 addon %ld, flavor %ld\n", node->Name(), node->ID(), addOnID, flavorID);
2201 TRACE("BMediaRoster::RegisterNode: node this %p\n", node);
2202 TRACE("BMediaRoster::RegisterNode: node fConsumerThis %p\n",
2203 node->fConsumerThis);
2204 TRACE("BMediaRoster::RegisterNode: node fProducerThis %p\n",
2205 node->fProducerThis);
2206 TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n",
2207 node->fFileInterfaceThis);
2208 TRACE("BMediaRoster::RegisterNode: node fControllableThis %p\n",
2209 node->fControllableThis);
2210 TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis %p\n",
2211 node->fTimeSourceThis);
2213 return B_OK;
2217 status_t
2218 BMediaRoster::UnregisterNode(BMediaNode* node)
2220 CALLED();
2221 if (node == NULL)
2222 return B_BAD_VALUE;
2224 TRACE("BMediaRoster::UnregisterNode %"
2225 B_PRId32 " (%p)\n", node->ID(), node);
2227 if ((node->fKinds & NODE_KIND_NO_REFCOUNTING) !=0) {
2228 TRACE("BMediaRoster::UnregisterNode, trying to unregister reference "
2229 "counting disabled timesource, node %"
2230 B_PRId32 " , port %" B_PRId32 " , team %" B_PRId32 "\n",
2231 node->ID(), node->ControlPort(), BPrivate::current_team());
2232 return B_OK;
2234 if (node->ID() == NODE_UNREGISTERED_ID) {
2235 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2236 "'%s' already unregistered\n", node->ID(), node->Name());
2237 return B_OK;
2239 if (node->fRefCount != 0) {
2240 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2241 "'%s' has local reference count of %ld\n", node->ID(), node->Name(),
2242 node->fRefCount);
2243 // no return here, we continue and unregister!
2246 // Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node,
2247 // BMessage *config) if this node was instanciated by an add-on needs to
2248 // be done *somewhere*
2249 // We can't do it here because it is already to late (destructor of the node
2250 // might have been called).
2252 server_unregister_node_request request;
2253 request.node_id = node->ID();
2254 request.team = BPrivate::current_team();
2256 // send a notification
2257 BPrivate::media::notifications::NodesDeleted(&request.node_id, 1);
2259 server_unregister_node_reply reply;
2260 reply.add_on_id = -1;
2261 status_t status = QueryServer(SERVER_UNREGISTER_NODE, &request,
2262 sizeof(request), &reply, sizeof(reply));
2263 if (status != B_OK) {
2264 ERROR("BMediaRoster::UnregisterNode: failed to unregister node id %"
2265 B_PRId32 ", name '%s': %s\n", node->ID(), node->Name(),
2266 strerror(status));
2267 BMediaAddOn *addon = node->AddOn(&reply.flavor_id);
2268 if (addon != NULL)
2269 reply.add_on_id = addon->AddonID();
2272 if (reply.add_on_id != -1) {
2273 // TODO: this doesn't look right
2274 // Small problem here, we can't use DormantNodeManager::PutAddOn(), as
2275 // UnregisterNode() is called by a dormant node itself (by the
2276 // destructor).
2277 // The add-on that contains the node needs to remain in memory until the
2278 // destructor execution is finished.
2279 // DormantNodeManager::PutAddOnDelayed() will delay unloading.
2280 gDormantNodeManager->PutAddOnDelayed(reply.add_on_id);
2282 status = MediaRosterEx(this)->DecrementAddonFlavorInstancesCount(
2283 reply.add_on_id, reply.flavor_id);
2284 if (status != B_OK) {
2285 ERROR("BMediaRoster::UnregisterNode: "
2286 "DecrementAddonFlavorInstancesCount() failed\n");
2287 // this is really a problem, but we can't fail now
2291 // we are a friend class of BMediaNode and invalidate this member variable
2292 node->fNodeID = NODE_UNREGISTERED_ID;
2294 return status;
2298 //! Thread safe for multiple calls to Roster()
2299 /*static*/ BMediaRoster*
2300 BMediaRoster::Roster(status_t* out_error)
2302 BAutolock lock(sInitLocker);
2304 if (be_app == NULL)
2305 TRACE("Warning! You should have a valid BApplication.");
2307 if (!lock.IsLocked())
2308 return NULL;
2310 if (out_error)
2311 *out_error = B_OK;
2313 if (sDefaultInstance == NULL) {
2314 status_t err;
2315 sDefaultInstance = new (std::nothrow) BMediaRosterEx(&err);
2316 if (sDefaultInstance == NULL)
2317 err = B_NO_MEMORY;
2318 else if (err != B_OK) {
2319 if (sDefaultInstance) {
2320 sDefaultInstance->Lock();
2321 sDefaultInstance->Quit();
2322 sDefaultInstance = NULL;
2324 if (out_error)
2325 *out_error = err;
2326 } else if (be_app != NULL) {
2327 be_app->RegisterLooper(sDefaultInstance);
2331 return sDefaultInstance;
2335 /*static*/ BMediaRoster*
2336 BMediaRoster::CurrentRoster()
2338 return sDefaultInstance;
2342 status_t
2343 BMediaRoster::SetTimeSourceFor(media_node_id node, media_node_id time_source)
2345 CALLED();
2346 if (IS_INVALID_NODEID(node) || IS_INVALID_NODEID(time_source))
2347 return B_BAD_VALUE;
2349 media_node clone;
2350 // We need to get a clone of the node to have a port id
2351 status_t result = GetNodeFor(node, &clone);
2352 if (result == B_OK) {
2353 // We just send the request to set time_source-id as
2354 // timesource to the node, the NODE_SET_TIMESOURCE handler
2355 // code will do the real assignment.
2356 result = B_OK;
2357 node_set_timesource_command cmd;
2358 cmd.timesource_id = time_source;
2359 result = SendToPort(clone.port, NODE_SET_TIMESOURCE,
2360 &cmd, sizeof(cmd));
2361 if (result != B_OK) {
2362 ERROR("BMediaRoster::SetTimeSourceFor"
2363 "sending NODE_SET_TIMESOURCE failed, node id %"
2364 B_PRId32 "\n", clone.node);
2366 // We release the clone
2367 result = ReleaseNode(clone);
2368 if (result != B_OK) {
2369 ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed,"
2370 " node id %" B_PRId32 "\n", clone.node);
2372 } else {
2373 ERROR("BMediaRoster::SetTimeSourceFor GetCloneForID failed, "
2374 "node id %" B_PRId32 "\n", node);
2377 if (result == B_OK) {
2378 // Notify the server
2379 server_set_node_timesource_request request;
2380 server_set_node_timesource_reply reply;
2382 request.node_id = node;
2383 request.timesource_id = time_source;
2385 result = QueryServer(SERVER_SET_NODE_TIMESOURCE, &request,
2386 sizeof(request), &reply, sizeof(reply));
2387 if (result != B_OK) {
2388 ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE "
2389 "failed, node id %" B_PRId32 "\n", node);
2390 } else {
2391 TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %"
2392 B_PRId32 " OK\n", node, time_source);
2395 return result;
2399 status_t
2400 BMediaRoster::GetParameterWebFor(const media_node& node, BParameterWeb** _web)
2402 CALLED();
2403 if (_web == NULL)
2404 return B_BAD_VALUE;
2405 if (IS_INVALID_NODE(node))
2406 return B_MEDIA_BAD_NODE;
2407 if ((node.kind & B_CONTROLLABLE) == 0)
2408 return B_MEDIA_BAD_NODE;
2410 controllable_get_parameter_web_request request;
2411 controllable_get_parameter_web_reply reply;
2412 int32 requestsize[] = {B_PAGE_SIZE, 4 * B_PAGE_SIZE, 16 * B_PAGE_SIZE,
2413 64 * B_PAGE_SIZE, 128 * B_PAGE_SIZE, 256 * B_PAGE_SIZE, 0};
2414 int32 size;
2416 // TODO: it might be better to query the node for the (current) parameter
2417 // size first
2418 for (int i = 0; (size = requestsize[i]) != 0; i++) {
2419 status_t rv;
2420 area_id area;
2421 void *data;
2422 area = create_area("parameter web data", &data, B_ANY_ADDRESS, size,
2423 B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
2424 if (area < B_OK) {
2425 ERROR("BMediaRoster::GetParameterWebFor couldn't create area of "
2426 "size %" B_PRId32 "\n", size);
2427 return B_ERROR;
2429 request.max_size = size;
2430 request.area = area;
2431 rv = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_WEB, &request,
2432 sizeof(request), &reply, sizeof(reply));
2433 if (rv != B_OK) {
2434 ERROR("BMediaRoster::GetParameterWebFor "
2435 "CONTROLLABLE_GET_PARAMETER_WEB failed\n");
2436 delete_area(area);
2437 return B_ERROR;
2439 if (reply.size == 0) {
2440 // no parameter web available
2441 // TODO: should we return an error?
2442 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32
2443 " has no parameter web\n", node.node);
2444 *_web = new (std::nothrow) BParameterWeb();
2445 delete_area(area);
2446 return *_web != NULL ? B_OK : B_NO_MEMORY;
2448 if (reply.size > 0) {
2449 // we got a flattened parameter web!
2450 BParameterWeb* web = new (std::nothrow) BParameterWeb();
2451 if (web == NULL)
2452 rv = B_NO_MEMORY;
2453 else {
2454 rv = web->Unflatten(reply.code, data, reply.size);
2455 if (rv != B_OK) {
2456 ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, "
2457 "%s\n", strerror(rv));
2458 delete web;
2459 } else
2460 *_web = web;
2463 delete_area(area);
2464 return rv;
2466 delete_area(area);
2467 ASSERT(reply.size == -1);
2468 // parameter web data was too large
2469 // loop and try a larger size
2471 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32 " has no "
2472 "parameter web larger than %" B_PRId32 "\n", node.node, size);
2473 return B_ERROR;
2477 status_t
2478 BMediaRoster::StartControlPanel(const media_node& node, BMessenger* _messenger)
2480 CALLED();
2482 controllable_start_control_panel_request request;
2483 controllable_start_control_panel_reply reply;
2485 request.node = node;
2487 status_t rv;
2488 rv = QueryPort(node.port, CONTROLLABLE_START_CONTROL_PANEL, &request,
2489 sizeof(request), &reply, sizeof(reply));
2490 if (rv != B_OK)
2491 return rv;
2493 if (reply.team != -1 && _messenger != NULL)
2494 *_messenger = BMessenger(NULL, reply.team);
2496 return B_OK;
2500 status_t
2501 BMediaRoster::GetDormantNodes(dormant_node_info* _info, int32* _count,
2502 const media_format* hasInput, const media_format* hasOutput,
2503 const char* name, uint64 requireKinds, uint64 denyKinds)
2505 CALLED();
2506 if (_info == NULL || _count == NULL || *_count <= 0)
2507 return B_BAD_VALUE;
2509 server_get_dormant_nodes_request request;
2510 request.max_count = *_count;
2511 request.has_input = hasInput != NULL;
2512 if (hasInput != NULL) {
2513 // TODO: we should not make a flat copy of media_format
2514 request.input_format = *hasInput;
2516 request.has_output = hasOutput != NULL;
2517 if (hasOutput != NULL) {
2518 // TODO: we should not make a flat copy of media_format
2519 request.output_format = *hasOutput;
2522 request.has_name = name != NULL;
2523 if (name != NULL)
2524 strlcpy(request.name, name, sizeof(request.name));
2526 request.require_kinds = requireKinds;
2527 request.deny_kinds = denyKinds;
2529 server_get_dormant_nodes_reply reply;
2530 status_t status = QueryServer(SERVER_GET_DORMANT_NODES, &request,
2531 sizeof(request), &reply, sizeof(reply));
2532 if (status != B_OK)
2533 return status;
2535 *_count = reply.count;
2537 if (reply.count > 0) {
2538 int32 code;
2539 status = read_port(request.reply_port, &code, _info,
2540 reply.count * sizeof(dormant_node_info));
2541 if (status < B_OK)
2542 reply.result = status;
2545 return reply.result;
2549 /*! This function is used to do the real work of instantiating a dormant node.
2550 It is either called by the media_addon_server to instantiate a global node,
2551 or it gets called from BMediaRoster::InstantiateDormantNode() to create a
2552 local one.
2554 Checks concerning global/local are not done here.
2556 status_t
2557 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonID, int32 flavorID,
2558 team_id creator, media_node *_node)
2560 // This function is always called from the correct context, if the node
2561 // is supposed to be global, it is called from the media_addon_server.
2563 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
2564 // resides in the media_addon_server
2566 // RegisterNode() must be called for nodes instantiated from add-ons,
2567 // since the media kit warrants that it's done automatically.
2569 // addonID Indicates the ID number of the media add-on in which the
2570 // node resides.
2571 // flavorID Indicates the internal ID number that the add-on uses to
2572 // identify the flavor, this is the number that was published
2573 // by BMediaAddOn::GetFlavorAt() in the
2574 // flavor_info::internal_id field.
2575 // creator The creator team is -1 if nodes are created locally. If
2576 // created globally, it will contain (while called in
2577 // media_addon_server context) the team-id of the team that
2578 // requested the instantiation.
2580 TRACE("BMediaRosterEx::InstantiateDormantNode: addonID %" B_PRId32
2581 ", flavorID %" B_PRId32 "\n", addonID, flavorID);
2583 // Get flavor_info from the server
2584 dormant_flavor_info info;
2585 status_t rv;
2586 rv = GetDormantFlavorInfo(addonID, flavorID, &info);
2587 if (rv != B_OK) {
2588 ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get "
2589 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2590 B_PRId32 "\n", addonID, flavorID);
2591 return B_ERROR;
2594 ASSERT(info.internal_id == flavorID);
2596 // load the BMediaAddOn object
2597 BMediaAddOn* addon = gDormantNodeManager->GetAddOn(addonID);
2598 if (addon == NULL) {
2599 ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n");
2600 return B_ERROR;
2603 // Now we need to try to increment the use count of this addon flavor
2604 // in the server. This can fail if the total number instances of this
2605 // flavor is limited.
2606 rv = IncrementAddonFlavorInstancesCount(addonID, flavorID);
2607 if (rv != B_OK) {
2608 ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create "
2609 "more nodes for addon-id %" B_PRId32 ", flavor-id %" B_PRId32 "\n",
2610 addonID, flavorID);
2611 // Put the addon back into the pool
2612 gDormantNodeManager->PutAddOn(addonID);
2613 return B_ERROR;
2616 BMessage config;
2617 rv = LoadNodeConfiguration(addonID, flavorID, &config);
2618 if (rv != B_OK) {
2619 ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load "
2620 "configuration for addon-id %" B_PRId32 ", flavor-id %" B_PRId32
2621 "\n", addonID, flavorID);
2622 // do not return, this is a minor problem, not a reason to fail
2625 status_t status = B_OK;
2626 BMediaNode* node = addon->InstantiateNodeFor(&info, &config, &status);
2627 if (node == NULL) {
2628 ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor "
2629 "failed\n");
2631 // Put the addon back into the pool
2632 gDormantNodeManager->PutAddOn(addonID);
2634 // We must decrement the use count of this addon flavor in the
2635 // server to compensate the increment done in the beginning.
2636 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2637 if (rv != B_OK) {
2638 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2639 "FlavorInstancesCount failed\n");
2641 return status != B_OK ? status : B_ERROR;
2644 rv = RegisterNode(node, addonID, flavorID);
2645 if (rv != B_OK) {
2646 ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
2647 delete node;
2648 // Put the addon back into the pool
2649 gDormantNodeManager->PutAddOn(addonID);
2650 // We must decrement the use count of this addon flavor in the
2651 // server to compensate the increment done in the beginning.
2652 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID);
2653 if (rv != B_OK) {
2654 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2655 "FlavorInstancesCount failed\n");
2657 return B_ERROR;
2660 if (creator != -1) {
2661 // send a message to the server to assign team "creator" as creator
2662 // of node "node->ID()"
2663 printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %"
2664 B_PRId32 " as creator of node %" B_PRId32 "\n", creator,
2665 node->ID());
2667 rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator);
2668 if (rv != B_OK) {
2669 ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign "
2670 "team %" B_PRId32 " as creator of node %" B_PRId32 "\n",
2671 creator, node->ID());
2672 // do not return, this is a minor problem, not a reason to fail
2676 // RegisterNode() does remember the add-on id in the server
2677 // and UnregisterNode() will call DormantNodeManager::PutAddon()
2678 // when the node is unregistered.
2680 *_node = node->Node();
2682 TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %" B_PRId32
2683 ", flavor_id %" B_PRId32 " instanciated as node %" B_PRId32 ", port %"
2684 B_PRId32 " in team %" B_PRId32 "\n", addonID, flavorID, _node->node,
2685 _node->port, BPrivate::current_team());
2687 return B_OK;
2691 status_t
2692 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2693 media_node* _node, uint32 flags)
2695 CALLED();
2696 if (_node == NULL)
2697 return B_BAD_VALUE;
2698 if (info.addon <= B_OK) {
2699 ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32
2700 " invalid.\n", info.addon);
2701 return B_BAD_VALUE;
2704 printf("BMediaRoster::InstantiateDormantNode: addon-id %" B_PRId32
2705 ", flavor_id %" B_PRId32 ", flags 0x%" B_PRIx32 "\n", info.addon,
2706 info.flavor_id, flags);
2708 // Get flavor_info from the server
2709 // TODO: this is a little overhead, as we get the full blown
2710 // dormant_flavor_info,
2711 // TODO: but only need the flags.
2712 dormant_flavor_info flavorInfo;
2713 status_t rv;
2714 rv = MediaRosterEx(this)->GetDormantFlavorInfo(info.addon, info.flavor_id,
2715 &flavorInfo);
2716 if (rv != B_OK) {
2717 ERROR("BMediaRoster::InstantiateDormantNode: failed to get "
2718 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %"
2719 B_PRId32 "\n", info.addon, info.flavor_id);
2720 return B_NAME_NOT_FOUND;
2723 ASSERT(flavorInfo.internal_id == info.flavor_id);
2725 #if DEBUG
2726 printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", "
2727 "flavor_flags 0x%" B_PRIx32 ", internal_id %" B_PRId32
2728 ", possible_count %" B_PRId32 "\n", flavorInfo.name, flavorInfo.info,
2729 flavorInfo.flavor_flags, flavorInfo.internal_id,
2730 flavorInfo.possible_count);
2732 if ((flags & B_FLAVOR_IS_LOCAL) != 0) {
2733 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2734 "B_FLAVOR_IS_LOCAL\n");
2736 if ((flags & B_FLAVOR_IS_GLOBAL) != 0) {
2737 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2738 "B_FLAVOR_IS_GLOBAL\n");
2740 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0) {
2741 printf("BMediaRoster::InstantiateDormantNode: node requires "
2742 "B_FLAVOR_IS_LOCAL\n");
2744 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0) {
2745 printf("BMediaRoster::InstantiateDormantNode: node requires "
2746 "B_FLAVOR_IS_GLOBAL\n");
2748 #endif
2750 // Make sure that flags demanded by the dormant node and those requested
2751 // by the caller are not incompatible.
2752 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2753 && (flags & B_FLAVOR_IS_LOCAL) != 0) {
2754 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2755 "B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n");
2756 return B_NAME_NOT_FOUND;
2758 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0
2759 && (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2760 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2761 "B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
2762 return B_NAME_NOT_FOUND;
2765 // If either the node, or the caller requested to make the instance global
2766 // we will do it by forwarding this request into the media_addon_server,
2767 // which in turn will call BMediaRosterEx::InstantiateDormantNode to create
2768 // the node there and make it globally available.
2769 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0
2770 || (flags & B_FLAVOR_IS_GLOBAL) != 0) {
2771 TRACE("BMediaRoster::InstantiateDormantNode: creating global object "
2772 "in media_addon_server\n");
2774 add_on_server_instantiate_dormant_node_request request;
2775 add_on_server_instantiate_dormant_node_reply reply;
2776 request.add_on_id = info.addon;
2777 request.flavor_id = info.flavor_id;
2778 request.creator_team = BPrivate::current_team();
2779 // creator team is allowed to also release global nodes
2780 rv = QueryAddOnServer(ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE, &request,
2781 sizeof(request), &reply, sizeof(reply));
2782 if (rv == B_OK)
2783 *_node = reply.node;
2784 } else {
2785 // creator team = -1, as this is a local node
2786 rv = MediaRosterEx(this)->InstantiateDormantNode(info.addon,
2787 info.flavor_id, -1, _node);
2789 if (rv != B_OK) {
2790 *_node = media_node::null;
2791 return B_NAME_NOT_FOUND;
2793 return B_OK;
2797 status_t
2798 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info,
2799 media_node* _node)
2801 return InstantiateDormantNode(info, _node, 0);
2805 status_t
2806 BMediaRoster::GetDormantNodeFor(const media_node& node,
2807 dormant_node_info* _info)
2809 CALLED();
2810 if (_info == NULL)
2811 return B_BAD_VALUE;
2812 if (IS_INVALID_NODE(node))
2813 return B_MEDIA_BAD_NODE;
2815 server_get_dormant_node_for_request request;
2816 server_get_dormant_node_for_reply reply;
2817 status_t rv;
2819 request.node = node;
2821 rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request),
2822 &reply, sizeof(reply));
2823 if (rv != B_OK)
2824 return rv;
2826 *_info = reply.node_info;
2827 return B_OK;
2831 status_t
2832 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID, int32 flavorID,
2833 dormant_flavor_info* _flavor)
2835 CALLED();
2836 if (_flavor == NULL)
2837 return B_BAD_VALUE;
2839 // TODO: better use an area here as well!
2841 server_get_dormant_flavor_info_reply* reply
2842 = (server_get_dormant_flavor_info_reply*)malloc(16300);
2843 if (reply == NULL)
2844 return B_NO_MEMORY;
2846 server_get_dormant_flavor_info_request request;
2847 request.add_on_id = addonID;
2848 request.flavor_id = flavorID;
2850 status_t status = QueryServer(SERVER_GET_DORMANT_FLAVOR_INFO, &request,
2851 sizeof(request), reply, 16300);
2852 if (status != B_OK) {
2853 free(reply);
2854 return status;
2857 if (reply->result == B_OK) {
2858 status = _flavor->Unflatten(reply->type, &reply->flattened_data,
2859 reply->flattened_size);
2860 } else
2861 status = reply->result;
2863 free(reply);
2864 return status;
2868 status_t
2869 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info& dormant,
2870 dormant_flavor_info* _flavor)
2872 return MediaRosterEx(this)->GetDormantFlavorInfo(dormant.addon,
2873 dormant.flavor_id, _flavor);
2877 // Reports in outLatency the maximum latency found downstream from
2878 // the specified BBufferProducer, producer, given the current connections.
2879 status_t
2880 BMediaRoster::GetLatencyFor(const media_node& producer, bigtime_t* _latency)
2882 CALLED();
2883 if (_latency == NULL)
2884 return B_BAD_VALUE;
2885 if (IS_INVALID_NODE(producer)
2886 || (producer.kind & B_BUFFER_PRODUCER) == 0)
2887 return B_MEDIA_BAD_NODE;
2889 producer_get_latency_request request;
2890 producer_get_latency_reply reply;
2891 status_t rv;
2893 rv = QueryPort(producer.port, PRODUCER_GET_LATENCY, &request,
2894 sizeof(request), &reply, sizeof(reply));
2895 if (rv != B_OK)
2896 return rv;
2898 *_latency = reply.latency;
2900 // printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2901 return B_OK;
2905 status_t
2906 BMediaRoster::GetInitialLatencyFor(const media_node& producer,
2907 bigtime_t* _latency, uint32* _flags)
2909 CALLED();
2910 if (_latency == NULL)
2911 return B_BAD_VALUE;
2912 if (IS_INVALID_NODE(producer)
2913 || (producer.kind & B_BUFFER_PRODUCER) == 0)
2914 return B_MEDIA_BAD_NODE;
2916 producer_get_initial_latency_request request;
2917 producer_get_initial_latency_reply reply;
2918 status_t rv;
2920 rv = QueryPort(producer.port, PRODUCER_GET_INITIAL_LATENCY, &request,
2921 sizeof(request), &reply, sizeof(reply));
2922 if (rv != B_OK)
2923 return rv;
2925 *_latency = reply.initial_latency;
2926 if (_flags != NULL)
2927 *_flags = reply.flags;
2929 TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32 " has "
2930 "maximum initial latency %" B_PRId64 "\n", producer.node, *_latency);
2931 return B_OK;
2935 status_t
2936 BMediaRoster::GetStartLatencyFor(const media_node& timeSource,
2937 bigtime_t* _latency)
2939 CALLED();
2940 if (_latency == NULL)
2941 return B_BAD_VALUE;
2942 if (IS_INVALID_NODE(timeSource)
2943 || (timeSource.kind & B_TIME_SOURCE) == 0)
2944 return B_MEDIA_BAD_NODE;
2946 timesource_get_start_latency_request request;
2947 timesource_get_start_latency_reply reply;
2948 status_t rv;
2950 rv = QueryPort(timeSource.port, TIMESOURCE_GET_START_LATENCY, &request,
2951 sizeof(request), &reply, sizeof(reply));
2952 if (rv != B_OK)
2953 return rv;
2955 *_latency = reply.start_latency;
2957 TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32 " has "
2958 "maximum initial latency %" B_PRId64 "\n", timeSource.node, *_latency);
2959 return B_OK;
2963 status_t
2964 BMediaRoster::GetFileFormatsFor(const media_node& fileInterface,
2965 media_file_format* _formats, int32* _numFormats)
2967 CALLED();
2969 if (IS_INVALID_NODE(fileInterface)
2970 || (fileInterface.kind & B_FILE_INTERFACE) == 0)
2971 return B_MEDIA_BAD_NODE;
2973 if (_numFormats == NULL || *_numFormats < 1)
2974 return B_BAD_VALUE;
2976 fileinterface_get_formats_request request;
2977 fileinterface_get_formats_reply reply;
2979 media_file_format* formats;
2980 size_t needSize = sizeof(media_file_format) * *_numFormats;
2981 size_t size = (needSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
2983 area_id area = create_area("formats area", (void**)&formats,
2984 B_ANY_ADDRESS, size, B_NO_LOCK,
2985 B_READ_AREA | B_WRITE_AREA);
2987 if (area < 0)
2988 return B_NO_MEMORY;
2990 request.num_formats = *_numFormats;
2991 request.data_area = area;
2993 status_t status = QueryPort(fileInterface.port,
2994 FILEINTERFACE_GET_FORMATS, &request,
2995 sizeof(request), &reply, sizeof(reply));
2997 if (status == B_OK) {
2998 memcpy(_formats, formats, sizeof(media_file_format)*reply.filled_slots);
2999 *_numFormats = reply.filled_slots;
3001 delete_area(area);
3002 return status;
3006 status_t
3007 BMediaRoster::SetRefFor(const media_node& file_interface, const entry_ref& file,
3008 bool createAndTruncate, bigtime_t* _length)
3010 CALLED();
3012 if (IS_INVALID_NODE(file_interface)
3013 || (file_interface.kind & B_FILE_INTERFACE) == 0)
3014 return B_MEDIA_BAD_NODE;
3016 fileinterface_set_ref_request request;
3017 fileinterface_set_ref_reply reply;
3018 status_t rv;
3020 request.device = file.device;
3021 request.directory = file.directory;
3022 strcpy(request.name, file.name);
3023 request.create = createAndTruncate;
3024 if (_length != NULL)
3025 request.duration = *_length;
3027 rv = QueryPort(file_interface.port, FILEINTERFACE_SET_REF, &request,
3028 sizeof(request), &reply, sizeof(reply));
3029 if (rv != B_OK)
3030 return rv;
3032 if (!createAndTruncate && _length)
3033 *_length = reply.duration;
3035 return B_OK;
3039 status_t
3040 BMediaRoster::GetRefFor(const media_node& node, entry_ref* _file,
3041 BMimeType* mimeType)
3043 CALLED();
3045 if (IS_INVALID_NODE(node)
3046 || (node.kind & B_FILE_INTERFACE) == 0)
3047 return B_MEDIA_BAD_NODE;
3049 if (!_file)
3050 return B_BAD_VALUE;
3052 fileinterface_get_ref_request request;
3053 fileinterface_get_ref_reply reply;
3054 status_t rv;
3056 rv = QueryPort(node.port, FILEINTERFACE_GET_REF, &request, sizeof(request),
3057 &reply, sizeof(reply));
3058 if (rv != B_OK)
3059 return rv;
3061 *_file = entry_ref(reply.device, reply.directory, reply.name);
3063 if (mimeType)
3064 mimeType->SetTo(reply.mimetype);
3066 return B_OK;
3070 status_t
3071 BMediaRoster::SniffRefFor(const media_node& file_interface,
3072 const entry_ref& file, BMimeType* mimeType, float* _capability)
3074 CALLED();
3076 if (IS_INVALID_NODE(file_interface)
3077 || (file_interface.kind & B_FILE_INTERFACE) == 0)
3078 return B_MEDIA_BAD_NODE;
3080 if (mimeType == NULL || _capability == NULL)
3081 return B_BAD_VALUE;
3083 fileinterface_sniff_ref_request request;
3084 fileinterface_sniff_ref_reply reply;
3085 status_t rv;
3087 request.device = file.device;
3088 request.directory = file.directory;
3089 strcpy(request.name, file.name);
3091 rv = QueryPort(file_interface.port, FILEINTERFACE_SNIFF_REF, &request,
3092 sizeof(request), &reply, sizeof(reply));
3093 if (rv != B_OK)
3094 return rv;
3096 mimeType->SetTo(reply.mimetype);
3097 *_capability = reply.capability;
3099 return B_OK;
3103 /*! This is the generic "here's a file, now can someone please play it"
3104 interface.
3106 status_t
3107 BMediaRoster::SniffRef(const entry_ref& file, uint64 requireNodeKinds,
3108 dormant_node_info* _node, BMimeType* mimeType)
3110 CALLED();
3112 TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64
3113 "\n", file.name, requireNodeKinds);
3115 if (_node == NULL)
3116 return B_BAD_VALUE;
3118 BMimeType aMimeType;
3120 dormant_node_info nodes[30];
3121 int32 count = 30;
3122 int32 highestCapability = -1;
3123 float capability;
3125 media_node node;
3127 // Get all dormant nodes using GetDormantNodes
3128 if (GetDormantNodes(nodes, &count, NULL, NULL, NULL, requireNodeKinds | B_FILE_INTERFACE, 0) == B_OK) {
3129 // Call SniffRefFor on each node that matches requireNodeKinds
3130 for (int32 i=0;i<count;i++) {
3131 if (InstantiateDormantNode(nodes[i], &node) == B_OK) {
3133 if (SniffRefFor(node, file, &aMimeType, &capability) == B_OK) {
3134 // find the first node that has 100% capability
3135 TRACE("%s has a %f%% chance of playing file\n",nodes[i].name, capability * 100.0);
3136 if (capability == 1.0) {
3137 highestCapability = i;
3138 break;
3141 ReleaseNode(node);
3145 if (highestCapability != -1) {
3146 *_node = nodes[highestCapability];
3148 TRACE("BMediaRoster::SniffRef: found a node %s addon-id %" B_PRId32
3149 ", flavor_id %" B_PRId32 "\n",
3150 nodes[highestCapability].name, nodes[highestCapability].addon,
3151 nodes[highestCapability].flavor_id);
3153 if (mimeType != NULL) {
3154 //*mimeType = aMimeType; -- need a copy constructor
3157 return B_OK;
3162 return B_ERROR;
3166 status_t
3167 BMediaRoster::GetDormantNodeForType(const BMimeType& type,
3168 uint64 requireNodeKinds, dormant_node_info* _node)
3170 UNIMPLEMENTED();
3171 return B_ERROR;
3175 status_t
3176 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info& node,
3177 media_file_format* _readFormats, int32 readCount, int32* _readCount)
3179 UNIMPLEMENTED();
3180 return B_ERROR;
3184 status_t
3185 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info& node,
3186 media_file_format* _write_formats, int32 writeCount, int32* _writeCount)
3188 UNIMPLEMENTED();
3189 return B_ERROR;
3193 status_t
3194 BMediaRoster::GetFormatFor(const media_output& output, media_format* _format,
3195 uint32 flags)
3197 CALLED();
3198 if (_format == NULL)
3199 return B_BAD_VALUE;
3200 if ((output.node.kind & B_BUFFER_PRODUCER) == 0)
3201 return B_MEDIA_BAD_NODE;
3202 if (IS_INVALID_SOURCE(output.source))
3203 return B_MEDIA_BAD_SOURCE;
3205 producer_format_suggestion_requested_request request;
3206 producer_format_suggestion_requested_reply reply;
3207 status_t rv;
3209 request.type = B_MEDIA_UNKNOWN_TYPE;
3210 request.quality = 0; // TODO: what should this be?
3212 rv = QueryPort(output.source.port, PRODUCER_FORMAT_SUGGESTION_REQUESTED,
3213 &request, sizeof(request), &reply, sizeof(reply));
3214 if (rv != B_OK)
3215 return rv;
3217 *_format = reply.format;
3218 return B_OK;
3222 status_t
3223 BMediaRoster::GetFormatFor(const media_input& input, media_format* _format,
3224 uint32 flags)
3226 CALLED();
3227 if (_format == NULL)
3228 return B_BAD_VALUE;
3229 if ((input.node.kind & B_BUFFER_CONSUMER) == 0)
3230 return B_MEDIA_BAD_NODE;
3231 if (IS_INVALID_DESTINATION(input.destination))
3232 return B_MEDIA_BAD_DESTINATION;
3234 consumer_accept_format_request request;
3235 consumer_accept_format_reply reply;
3236 status_t rv;
3238 request.dest = input.destination;
3239 memset(&request.format, 0, sizeof(request.format)); // wildcard
3241 rv = QueryPort(input.destination.port, CONSUMER_ACCEPT_FORMAT, &request,
3242 sizeof(request), &reply, sizeof(reply));
3243 if (rv != B_OK)
3244 return rv;
3246 *_format = reply.format;
3247 return B_OK;
3251 status_t
3252 BMediaRoster::GetFormatFor(const media_node& node, media_format* _format,
3253 float quality)
3255 UNIMPLEMENTED();
3256 if (_format == NULL)
3257 return B_BAD_VALUE;
3258 if (IS_INVALID_NODE(node))
3259 return B_MEDIA_BAD_NODE;
3260 if ((node.kind & (B_BUFFER_CONSUMER | B_BUFFER_PRODUCER)) == 0)
3261 return B_MEDIA_BAD_NODE;
3263 return B_ERROR;
3267 ssize_t
3268 BMediaRoster::GetNodeAttributesFor(const media_node& node,
3269 media_node_attribute* _array, size_t maxCount)
3271 CALLED();
3273 if (IS_INVALID_NODE(node))
3274 return B_MEDIA_BAD_NODE;
3276 node_get_attributes_for_request request;
3277 node_get_attributes_for_reply reply;
3278 status_t status;
3280 media_node_attribute* addr = NULL;
3281 size_t totalSize = maxCount*sizeof(media_node_attribute);
3282 size_t size = (totalSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
3284 area_id dataArea = create_area("attributes area", (void**)&addr,
3285 B_ANY_ADDRESS, size, B_NO_LOCK,
3286 B_READ_AREA | B_WRITE_AREA);
3287 // No need to memset the padding
3288 memset(addr, 0, totalSize);
3290 if (dataArea < 0)
3291 return B_NO_MEMORY;
3293 request.count = maxCount;
3294 request.area = dataArea;
3296 status = QueryPort(node.port, NODE_GET_ATTRIBUTES_FOR, &request,
3297 sizeof(request), &reply, sizeof(reply));
3298 if (status != B_OK)
3299 return status;
3301 memcpy(_array, addr, reply.filled_count
3302 * sizeof(media_node_attribute));
3304 delete_area(dataArea);
3305 return reply.filled_count;
3309 media_node_id
3310 BMediaRoster::NodeIDFor(port_id port)
3312 CALLED();
3314 server_node_id_for_request request;
3315 server_node_id_for_reply reply;
3316 status_t rv;
3318 request.port = port;
3320 rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply,
3321 sizeof(reply));
3322 if (rv != B_OK) {
3323 ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32 ")\n", rv);
3324 return -1;
3327 return reply.node_id;
3331 status_t
3332 BMediaRoster::GetInstancesFor(media_addon_id addon, int32 flavor,
3333 media_node_id* _id, int32* _count)
3335 CALLED();
3336 if (_id == NULL)
3337 return B_BAD_VALUE;
3338 if (_count && *_count <= 0)
3339 return B_BAD_VALUE;
3341 server_get_instances_for_request request;
3342 server_get_instances_for_reply reply;
3343 status_t rv;
3345 request.max_count = (_count ? *_count : 1);
3346 request.add_on_id = addon;
3347 request.flavor_id = flavor;
3349 rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request),
3350 &reply, sizeof(reply));
3351 if (rv != B_OK) {
3352 ERROR("BMediaRoster::GetLiveNodes failed\n");
3353 return rv;
3356 if (_count)
3357 *_count = reply.count;
3358 if (reply.count > 0)
3359 memcpy(_id, reply.node_id, sizeof(media_node_id) * reply.count);
3361 return B_OK;
3365 bool
3366 BMediaRoster::IsRunning()
3368 return be_roster->IsRunning(B_MEDIA_SERVER_SIGNATURE)
3369 && be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE);
3373 ssize_t
3374 BMediaRoster::AudioBufferSizeFor(int32 channelCount, uint32 sampleFormat,
3375 float frameRate, bus_type busKind)
3377 bigtime_t bufferDuration;
3378 ssize_t bufferSize;
3380 if (busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS)
3381 bufferDuration = 25000;
3382 else
3383 bufferDuration = 10000;
3385 bufferSize = (sampleFormat & 0xf) * channelCount
3386 * (ssize_t)((frameRate * bufferDuration) / 1000000.0);
3388 printf("Suggested buffer duration %" B_PRId64 ", size %" B_PRIdSSIZE "\n",
3389 bufferDuration, bufferSize);
3391 return bufferSize;
3395 /*! Use MediaFlags to inquire about specific features of the Media Kit.
3396 Returns < 0 for "not present", positive size for output data size.
3397 0 means that the capability is present, but no data about it.
3399 /*static*/ ssize_t
3400 BMediaRoster::MediaFlags(media_flags cap, void* buffer, size_t maxSize)
3402 UNIMPLEMENTED();
3403 return 0;
3407 // #pragma mark - BLooper overrides
3410 void
3411 BMediaRoster::MessageReceived(BMessage* message)
3413 switch (message->what) {
3414 case MEDIA_ROSTER_REQUEST_NOTIFICATIONS:
3416 RosterNotification notification;
3417 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, &notification.what)
3418 != B_OK) {
3419 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3420 "find what parameter");
3421 return;
3423 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER,
3424 &notification.messenger) != B_OK) {
3425 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3426 "find messenger");
3427 return;
3429 sNotificationList.Insert(notification);
3430 return;
3433 case MEDIA_ROSTER_CANCEL_NOTIFICATIONS:
3435 RosterNotification notification;
3436 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, &notification.what)
3437 != B_OK) {
3438 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3439 "find what parameter");
3440 return;
3442 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER,
3443 &notification.messenger) != B_OK) {
3444 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3445 "find messenger");
3446 return;
3448 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3449 RosterNotification* current;
3450 if (sNotificationList.Get(i, &current) != true)
3451 return;
3452 if (current->what == notification.what
3453 && current->messenger == notification.messenger) {
3454 sNotificationList.Remove(i);
3455 return;
3458 return;
3461 case B_SOME_APP_LAUNCHED:
3463 BString mimeSig;
3464 if (message->FindString("be:signature", &mimeSig) != B_OK)
3465 return;
3466 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE
3467 && mimeSig != B_MEDIA_SERVER_SIGNATURE)
3468 return;
3470 TRACE("BMediaRoster::MessageReceived media services are going up.");
3472 if (BMediaRoster::IsRunning()) {
3473 // Wait for media services to wake up and restore our friendship
3474 if (MediaRosterEx(this)->BuildConnections() != B_OK) {
3475 TRACE("BMediaRoster::MessageReceived can't reconnect"
3476 "to media_server.");
3479 return;
3482 case B_SOME_APP_QUIT:
3484 BString mimeSig;
3485 if (message->FindString("be:signature", &mimeSig) != B_OK)
3486 return;
3487 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE
3488 && mimeSig != B_MEDIA_SERVER_SIGNATURE)
3489 return;
3491 TRACE("BMediaRoster::MessageReceived media services are down.");
3493 // Send the notification to our subscribers
3494 if (!BMediaRoster::IsRunning() && sServerIsUp == true) {
3495 sServerIsUp = false;
3496 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3497 RosterNotification* current;
3498 if (sNotificationList.Get(i, &current) != true)
3499 return;
3500 if (current->what == B_MEDIA_SERVER_QUIT) {
3501 if (current->messenger.SendMessage(
3502 B_MEDIA_SERVER_QUIT) != B_OK) {
3503 if(!current->messenger.IsValid())
3504 sNotificationList.Remove(i);
3509 return;
3512 case MEDIA_SERVER_ALIVE:
3514 if (!BMediaRoster::IsRunning())
3515 return;
3517 sServerIsUp = true;
3519 TRACE("BMediaRoster::MessageReceived media services are"
3520 " finally up.");
3522 if (MediaRosterEx(this)->fLaunchNotification) {
3523 progress_startup(100, NULL, NULL);
3524 if (MediaRosterEx(this)->fAutoExit)
3525 MediaRosterEx(this)->fLaunchNotification = false;
3528 // Send the notification to our subscribers
3529 for (int32 i = 0; i < sNotificationList.CountItems(); i++) {
3530 RosterNotification* current;
3531 if (sNotificationList.Get(i, &current) != true)
3532 return;
3533 if (current->what == B_MEDIA_SERVER_STARTED) {
3534 if (current->messenger.SendMessage(
3535 B_MEDIA_SERVER_STARTED) != B_OK) {
3536 if(!current->messenger.IsValid())
3537 sNotificationList.Remove(i);
3541 return;
3544 case NODE_FINAL_RELEASE:
3546 // This function is called by a BMediaNode to delete
3547 // itself, as this needs to be done from another thread
3548 // context, it is done here.
3550 BMediaNode* node = NULL;
3551 status_t err = message->FindPointer("node",
3552 reinterpret_cast<void **>(&node));
3553 if (err == B_OK && node != NULL)
3554 node->Release();
3555 else {
3556 TRACE("BMediaRoster::MessageReceived: CRITICAL! received"
3557 "a release request but the node can't be found.");
3559 return;
3562 default:
3563 BLooper::MessageReceived(message);
3564 break;
3569 bool
3570 BMediaRoster::QuitRequested()
3572 CALLED();
3573 return true;
3577 BHandler*
3578 BMediaRoster::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
3579 int32 form, const char* property)
3581 return BLooper::ResolveSpecifier(msg, index, specifier, form, property);
3585 status_t
3586 BMediaRoster::GetSupportedSuites(BMessage* data)
3588 return BLooper::GetSupportedSuites(data);
3592 BMediaRoster::~BMediaRoster()
3594 CALLED();
3596 // Unset the global instance pointer, the destructor is also called
3597 // if a client app calls Lock(); and Quit(); directly.
3598 sDefaultInstance = NULL;
3601 // #pragma mark - private BMediaRoster
3603 // FBC reserved virtuals
3604 status_t BMediaRoster::_Reserved_MediaRoster_0(void*) { return B_ERROR; }
3605 status_t BMediaRoster::_Reserved_MediaRoster_1(void*) { return B_ERROR; }
3606 status_t BMediaRoster::_Reserved_MediaRoster_2(void*) { return B_ERROR; }
3607 status_t BMediaRoster::_Reserved_MediaRoster_3(void*) { return B_ERROR; }
3608 status_t BMediaRoster::_Reserved_MediaRoster_4(void*) { return B_ERROR; }
3609 status_t BMediaRoster::_Reserved_MediaRoster_5(void*) { return B_ERROR; }
3610 status_t BMediaRoster::_Reserved_MediaRoster_6(void*) { return B_ERROR; }
3611 status_t BMediaRoster::_Reserved_MediaRoster_7(void*) { return B_ERROR; }
3614 BMediaRoster::BMediaRoster()
3616 BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY,
3617 B_LOOPER_PORT_DEFAULT_CAPACITY)
3619 CALLED();
3621 // start the looper
3622 Run();
3625 // #pragma mark - static variables
3627 BMediaRoster* BMediaRoster::sDefaultInstance = NULL;