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.
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
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
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>
47 #include <BufferConsumer.h>
48 #include <BufferProducer.h>
51 #include <Messenger.h>
54 #include <ParameterWeb.h>
56 #include <StopWatch.h>
58 #include <TimeSource.h>
63 #include <DataExchange.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>
73 #include "TimeSourceObjectManager.h"
80 struct RosterNotification
{
86 struct SyncedMessage
{
92 LocalNode(BMediaNode
* local_node
)
100 bool operator==(const LocalNode
& a
)
102 if (a
.node
== this->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
{
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
);
130 ERROR("BMediaRoster: Node with ID %" B_PRId32
131 " was not released correctly\n", node
->node
->ID());
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
);
146 ERROR("BMediaRoster: wait_for_thread returned error");
152 static MediaRosterUndertaker sMediaRosterUndertaker
;
155 } // namespace BPrivate
157 using namespace BPrivate::media
;
160 BMediaRosterEx::BMediaRosterEx(status_t
* _error
)
163 fLaunchNotification(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
) {
177 sServerIsUp
= BMediaRoster::IsRunning();
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();
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
));
206 return B_MEDIA_SYSTEM_FAILURE
;
212 BMediaRosterEx::~BMediaRosterEx()
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
,
226 BPrivate::SharedBufferList::Invalidate();
231 BMediaRosterEx::RegisterLocalNode(BMediaNode
* node
)
233 sRegisteredNodes
.Insert(LocalNode(node
));
238 BMediaRosterEx::UnregisterLocalNode(BMediaNode
* node
)
240 int32 index
= sRegisteredNodes
.Find(LocalNode(node
));
242 sRegisteredNodes
.Remove(index
);
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
;
258 BMediaRosterEx::SaveNodeConfiguration(BMediaNode
* node
)
261 BMediaAddOn
* addon
= node
->AddOn(&flavorID
);
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());
271 media_addon_id addonID
= addon
->AddonID();
274 printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id "
275 "%" B_PRId32
", flavor-id %" B_PRId32
" config NOW!\n", addonID
,
282 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonID
, int32 flavorID
,
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
,
295 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonID
,
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
;
304 request
.team
= BPrivate::current_team();
305 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT
, &request
,
306 sizeof(request
), &reply
, sizeof(reply
));
311 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonID
,
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
;
320 request
.team
= BPrivate::current_team();
321 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT
, &request
,
322 sizeof(request
), &reply
, sizeof(reply
));
327 BMediaRosterEx::ReleaseNodeAll(const media_node
& node
)
330 if (IS_INVALID_NODE(node
))
331 return B_MEDIA_BAD_NODE
;
333 if (node
.kind
& NODE_KIND_NO_REFCOUNTING
)
336 server_release_node_request request
;
337 server_release_node_reply reply
;
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
,
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
,
358 ERROR("BMediaRoster::ReleaseNodeAll FAILED, node %" B_PRId32
", port %"
359 B_PRId32
", team %" B_PRId32
"!\n", node
.node
, node
.port
,
360 BPrivate::current_team());
368 BMediaRosterEx::SetNodeCreator(media_node_id node
, team_id creator
)
370 server_set_node_creator_request request
;
371 server_set_node_creator_reply reply
;
374 request
.creator
= creator
;
375 return QueryServer(SERVER_SET_NODE_CREATOR
, &request
, sizeof(request
),
376 &reply
, sizeof(reply
));
381 BMediaRosterEx::GetNode(node_type type
, media_node
* out_node
,
382 int32
* out_input_id
, BString
* out_input_name
)
384 if (out_node
== NULL
)
387 server_get_node_request request
;
388 server_get_node_reply reply
;
392 request
.team
= BPrivate::current_team();
393 rv
= QueryServer(SERVER_GET_NODE
, &request
, sizeof(request
), &reply
,
398 *out_node
= reply
.node
;
400 *out_input_id
= reply
.input_id
;
402 *out_input_name
= reply
.input_name
;
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
;
415 request
.use_node
= node
!= NULL
;
417 request
.node
= *node
;
418 request
.use_dni
= info
!= NULL
;
421 request
.use_input
= input
!= NULL
;
423 request
.input
= *input
;
425 return QueryServer(SERVER_SET_NODE
, &request
, sizeof(request
), &reply
,
431 BMediaRosterEx::GetAllOutputs(const media_node
& node
, List
<media_output
>* list
)
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
;
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
));
457 cookie
= reply
.cookie
;
458 if (!list
->Insert(reply
.output
)) {
459 ERROR("GetAllOutputs: list->Insert failed\n");
463 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
464 PRINT_OUTPUT("output ", reply
.output
);
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
));
478 BMediaRosterEx::GetAllOutputs(BBufferProducer
* node
, List
<media_output
>* list
)
483 PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %" B_PRId32
484 ", port %" B_PRId32
"\n", node
->ID(), node
->ControlPort());
491 if (B_OK
!= node
->GetNextOutput(&cookie
, &output
))
493 if (!list
->Insert(output
)) {
494 ERROR("GetAllOutputs: list->Insert failed\n");
498 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
499 PRINT_OUTPUT("output ", output
);
502 node
->DisposeOutputCookie(cookie
);
508 BMediaRosterEx::GetAllInputs(const media_node
& node
, List
<media_input
>* list
)
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
;
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
));
534 cookie
= reply
.cookie
;
535 if (!list
->Insert(reply
.input
)) {
536 ERROR("GetAllInputs: list->Insert failed\n");
540 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
541 PRINT_OUTPUT("input ", reply
.input
);
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
));
555 BMediaRosterEx::GetAllInputs(BBufferConsumer
* node
, List
<media_input
>* list
)
560 PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %" B_PRId32
561 ", port %" B_PRId32
"\n", node
->ID(), node
->ControlPort());
568 if (B_OK
!= node
->GetNextInput(&cookie
, &input
))
570 if (!list
->Insert(input
)) {
571 ERROR("GetAllInputs: list->Insert failed\n");
575 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
576 PRINT_INPUT("input ", input
);
579 node
->DisposeInputCookie(cookie
);
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
;
594 count
= list
->CountItems();
595 TRACE("PublishOutputs: publishing %" B_PRId32
"\n", count
);
598 request
.count
= count
;
599 if (count
> MAX_OUTPUTS
) {
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",
608 return (status_t
)request
.area
;
610 outputs
= static_cast<media_output
*>(start_addr
);
613 outputs
= request
.outputs
;
615 TRACE("PublishOutputs: area %" B_PRId32
"\n", request
.area
);
618 for (i
= 0, list
->Rewind(); list
->GetNext(&output
); i
++) {
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
);
634 BMediaRosterEx::PublishInputs(const media_node
& node
, List
<media_input
>* list
)
636 server_publish_inputs_request request
;
637 server_publish_inputs_reply reply
;
643 count
= list
->CountItems();
644 TRACE("PublishInputs: publishing %" B_PRId32
"\n", count
);
647 request
.count
= count
;
648 if (count
> MAX_INPUTS
) {
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",
657 return (status_t
)request
.area
;
659 inputs
= static_cast<media_input
*>(start_addr
);
662 inputs
= request
.inputs
;
664 TRACE("PublishInputs: area %" B_PRId32
"\n", request
.area
);
667 for (i
= 0, list
->Rewind(); list
->GetNext(&input
); i
++) {
672 rv
= QueryServer(SERVER_PUBLISH_INPUTS
, &request
, sizeof(request
),
673 &reply
, sizeof(reply
));
675 if (request
.area
!= -1)
676 delete_area(request
.area
);
683 BMediaRosterEx::MakeTimeSourceObject(media_node_id timeSourceID
)
686 status_t status
= GetNodeFor(timeSourceID
, &clone
);
687 if (status
!= B_OK
) {
688 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed: %s\n",
693 BTimeSource
* source
= gTimeSourceObjectManager
->GetTimeSource(clone
);
694 if (source
== NULL
) {
695 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n");
706 // #pragma mark - public BMediaRoster
710 BMediaRoster::GetVideoInput(media_node
* _node
)
713 return MediaRosterEx(this)->GetNode(VIDEO_INPUT
, _node
);
718 BMediaRoster::GetAudioInput(media_node
* _node
)
721 return MediaRosterEx(this)->GetNode(AUDIO_INPUT
, _node
);
726 BMediaRoster::GetVideoOutput(media_node
* _node
)
729 return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT
, _node
);
734 BMediaRoster::GetAudioMixer(media_node
* _node
)
737 return MediaRosterEx(this)->GetNode(AUDIO_MIXER
, _node
);
742 BMediaRoster::GetAudioOutput(media_node
* _node
)
745 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT
, _node
);
750 BMediaRoster::GetAudioOutput(media_node
* _node
, int32
* _inputID
,
754 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX
, _node
, _inputID
,
760 BMediaRoster::GetTimeSource(media_node
* _node
)
765 // TODO: need to do this in a nicer way.
767 rv
= MediaRosterEx(this)->GetNode(TIME_SOURCE
, _node
);
771 // We don't do reference counting for timesources, that's why we
772 // release the node immediately.
775 // we need to remember to not use this node with server side reference counting
776 _node
->kind
|= NODE_KIND_NO_REFCOUNTING
;
782 BMediaRoster::SetVideoInput(const media_node
& producer
)
785 return MediaRosterEx(this)->SetNode(VIDEO_INPUT
, &producer
);
790 BMediaRoster::SetVideoInput(const dormant_node_info
& producer
)
793 return MediaRosterEx(this)->SetNode(VIDEO_INPUT
, NULL
, &producer
);
798 BMediaRoster::SetAudioInput(const media_node
& producer
)
801 return MediaRosterEx(this)->SetNode(AUDIO_INPUT
, &producer
);
806 BMediaRoster::SetAudioInput(const dormant_node_info
& producer
)
809 return MediaRosterEx(this)->SetNode(AUDIO_INPUT
, NULL
, &producer
);
814 BMediaRoster::SetVideoOutput(const media_node
& consumer
)
817 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT
, &consumer
);
822 BMediaRoster::SetVideoOutput(const dormant_node_info
& consumer
)
825 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT
, NULL
, &consumer
);
830 BMediaRoster::SetAudioOutput(const media_node
& consumer
)
833 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, &consumer
);
838 BMediaRoster::SetAudioOutput(const media_input
& input
)
841 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, NULL
, NULL
, &input
);
846 BMediaRoster::SetAudioOutput(const dormant_node_info
& consumer
)
849 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, NULL
, &consumer
);
854 BMediaRoster::GetNodeFor(media_node_id node
, media_node
* clone
)
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
;
866 request
.node_id
= node
;
867 request
.team
= BPrivate::current_team();
869 rv
= QueryServer(SERVER_GET_NODE_FOR
, &request
, sizeof(request
), &reply
,
874 *clone
= reply
.clone
;
880 BMediaRoster::GetSystemTimeSource(media_node
* clone
)
885 // TODO: need to do this in a nicer way.
887 rv
= MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE
, clone
);
891 // We don't do reference counting for timesources, that's why we
892 // release the node immediately.
895 // we need to remember to not use this node with server side reference
897 clone
->kind
|= NODE_KIND_NO_REFCOUNTING
;
904 BMediaRoster::ReleaseNode(const media_node
& node
)
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());
918 server_release_node_request request
;
919 server_release_node_reply reply
;
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
,
932 ERROR("BMediaRoster::ReleaseNode FAILED, node %" B_PRId32
", port %"
933 B_PRId32
", team %" B_PRId32
"!\n", node
.node
, node
.port
,
934 BPrivate::current_team());
941 BMediaRoster::MakeTimeSourceFor(const media_node
& forNode
)
943 // MakeTimeSourceFor() returns a BTimeSource object
944 // corresponding to the specified node's time source.
948 if (IS_SYSTEM_TIMESOURCE(forNode
)) {
949 // special handling for the system time source
950 TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time "
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
);
963 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32
" enter\n",
966 node_get_timesource_request request
;
967 node_get_timesource_reply reply
;
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
));
975 ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n");
979 source
= MediaRosterEx(this)->MakeTimeSourceObject(reply
.timesource_id
);
981 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32
" leave\n",
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);
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
)
1002 if (io_format
== NULL
|| out_output
== NULL
|| out_input
== NULL
)
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
;
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
);
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
);
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
));
1057 ERROR("BMediaRoster::Connect: aborted after "
1058 "BBufferProducer::FormatProposal, status = %#" B_PRIx32
"\n",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
1071 request2
.format
= reply1
.format
;
1072 rv
= QueryPort(to
.port
, CONSUMER_ACCEPT_FORMAT
, &request2
,
1073 sizeof(request2
), &reply2
, sizeof(reply2
));
1075 ERROR("BMediaRoster::Connect: aborted after "
1076 "BBufferConsumer::AcceptFormat, status = %#" B_PRIx32
"\n",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
));
1095 ERROR("BMediaRoster::Connect: aborted after "
1096 "BBufferProducer::PrepareToConnect, status = %#" B_PRIx32
"\n", 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",
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");
1150 ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect()"
1151 ", status = %#" B_PRIx32
"\n", 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
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
,
1193 BMediaRoster::Disconnect(media_node_id source_nodeid
,
1194 const media_source
& source
, media_node_id destination_nodeid
,
1195 const media_destination
& destination
)
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
;
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
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
);
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
);
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
;
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
,
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
,
1326 BMediaRoster::StartNode(const media_node
& node
, bigtime_t atPerformanceTime
)
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
));
1343 BMediaRoster::StopNode(const media_node
& node
, bigtime_t atPerformanceTime
,
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
));
1362 BMediaRoster::SeekNode(const media_node
& node
, bigtime_t toMediaTime
,
1363 bigtime_t atPerformanceTime
)
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
));
1381 BMediaRoster::StartTimeSource(const media_node
& node
, bigtime_t atRealTime
)
1384 if (IS_SYSTEM_TIMESOURCE(node
)) {
1386 //ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is system timesource\n", node.node);
1389 // if (IS_SHADOW_TIMESOURCE(node)) {
1390 // // TODO: debug this
1391 // ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is shadow timesource\n", node.node);
1394 if (IS_INVALID_NODE(node
)) {
1395 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32
" invalid\n",
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
));
1417 BMediaRoster::StopTimeSource(const media_node
& node
, bigtime_t atRealTime
,
1421 if (IS_SYSTEM_TIMESOURCE(node
)) {
1423 //ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node);
1426 // if (IS_SHADOW_TIMESOURCE(node)) {
1427 // // TODO: debug this
1428 // ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node);
1431 if (IS_INVALID_NODE(node
)) {
1432 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32
" invalid\n",
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
));
1455 BMediaRoster::SeekTimeSource(const media_node
& node
,
1456 bigtime_t toPerformanceTime
, bigtime_t atRealTime
)
1459 if (IS_SYSTEM_TIMESOURCE(node
)) {
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
1466 // if (IS_SHADOW_TIMESOURCE(node)) {
1467 // // TODO: debug this
1468 // ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node);
1471 if (IS_INVALID_NODE(node
)) {
1472 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32
" invalid\n",
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
));
1495 BMediaRoster::SyncToNode(const media_node
& node
, bigtime_t atTime
,
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
)
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
);
1521 close_port(waitPort
);
1522 delete_port(waitPort
);
1528 BMediaRoster::SetRunModeNode(const media_node
& node
, BMediaNode::run_mode mode
)
1530 TRACE("BMediaRoster::SetRunModeNode, node %" B_PRId32
", mode %d\n",
1532 if (IS_INVALID_NODE(node
))
1533 return B_MEDIA_BAD_NODE
;
1535 node_set_run_mode_command msg
;
1538 return write_port(node
.port
, NODE_SET_RUN_MODE
, &msg
, sizeof(msg
));
1543 BMediaRoster::PrerollNode(const media_node
& node
)
1546 if (IS_INVALID_NODE(node
))
1547 return B_MEDIA_BAD_NODE
;
1550 return write_port(node
.port
, NODE_PREROLL
, &dummy
, sizeof(dummy
));
1555 BMediaRoster::RollNode(const media_node
& node
, bigtime_t startPerformance
,
1556 bigtime_t stopPerformance
, bigtime_t atMediaTime
)
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
));
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
,
1597 BMediaRoster::SetProducerRate(const media_node
& producer
, int32 numer
,
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
));
1614 producer_set_play_rate_reply reply
;
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.
1627 BMediaRoster::GetLiveNodeInfo(const media_node
& node
,
1628 live_node_info
* out_live_info
)
1631 if (out_live_info
== NULL
)
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
;
1640 request
.node
= node
;
1642 rv
= QueryServer(SERVER_GET_LIVE_NODE_INFO
, &request
, sizeof(request
),
1643 &reply
, sizeof(reply
));
1647 *out_live_info
= reply
.live_info
;
1653 BMediaRoster::GetLiveNodes(live_node_info
* liveNodes
, int32
* _totalCount
,
1654 const media_format
* hasInput
, const media_format
* hasOutput
,
1655 const char* name
, uint64 nodeKinds
)
1658 if (liveNodes
== NULL
|| _totalCount
== NULL
|| *_totalCount
<= 0)
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
;
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",
1693 const live_node_info
* info
;
1694 if (reply
.area
>= 0)
1695 info
= (live_node_info
*)reply
.address
;
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
;
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
)
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
)
1729 List
<media_input
> list
;
1733 *out_total_count
= 0;
1735 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1739 PRINT(4, "BMediaRoster::GetFreeInputsFor node %" B_PRId32
", max %" B_PRId32
1740 ", filter-type %" B_PRId32
"\n", node
.node
, buf_num_inputs
,
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
1750 if (input
->source
!= media_source::null
) {
1751 // consumer source already connected
1755 out_free_inputs
[i
] = *input
;
1756 *out_total_count
+= 1;
1757 buf_num_inputs
-= 1;
1759 PRINT_OUTPUT(" input", out_free_inputs
[i
]);
1761 if (buf_num_inputs
== 0)
1766 MediaRosterEx(this)->PublishInputs(node
, &list
);
1772 BMediaRoster::GetConnectedInputsFor(const media_node
& node
,
1773 media_input
* out_active_inputs
, int32 buf_num_inputs
,
1774 int32
* out_total_count
)
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
)
1782 List
<media_input
> list
;
1786 *out_total_count
= 0;
1788 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1792 PRINT(4, "BMediaRoster::GetConnectedInputsFor node %" B_PRId32
", max %"
1793 B_PRId32
"\n", node
.node
, buf_num_inputs
);
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;
1803 PRINT_OUTPUT(" input ", out_active_inputs
[i
]);
1805 if (buf_num_inputs
== 0)
1810 MediaRosterEx(this)->PublishInputs(node
, &list
);
1816 BMediaRoster::GetAllInputsFor(const media_node
& node
, media_input
* out_inputs
,
1817 int32 buf_num_inputs
, int32
* out_total_count
)
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
)
1825 List
<media_input
> list
;
1829 *out_total_count
= 0;
1831 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1835 PRINT(4, "BMediaRoster::GetAllInputsFor node %" B_PRId32
", max %" B_PRId32
1836 "\n", node
.node
, buf_num_inputs
);
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;
1844 PRINT_OUTPUT(" input ", out_inputs
[i
]);
1846 if (buf_num_inputs
== 0)
1850 MediaRosterEx(this)->PublishInputs(node
, &list
);
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
)
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
)
1866 List
<media_output
> list
;
1867 media_output
*output
;
1870 *out_total_count
= 0;
1872 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1876 PRINT(4, "BMediaRoster::GetFreeOutputsFor node %" B_PRId32
", max %"
1877 B_PRId32
", filter-type %" B_PRId32
"\n", node
.node
, buf_num_outputs
,
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
1887 if (output
->destination
!= media_destination::null
) {
1888 // producer destination already connected
1892 out_free_outputs
[i
] = *output
;
1893 *out_total_count
+= 1;
1894 buf_num_outputs
-= 1;
1896 PRINT_OUTPUT(" output ", out_free_outputs
[i
]);
1898 if (buf_num_outputs
== 0)
1903 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1909 BMediaRoster::GetConnectedOutputsFor(const media_node
& node
,
1910 media_output
* out_active_outputs
, int32 buf_num_outputs
,
1911 int32
* out_total_count
)
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
)
1919 List
<media_output
> list
;
1920 media_output
*output
;
1923 *out_total_count
= 0;
1925 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1929 PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %" B_PRId32
", max %"
1930 B_PRId32
"\n", node
.node
, buf_num_outputs
);
1933 for (i
= 0, list
.Rewind(); list
.GetNext(&output
);) {
1934 if (output
->destination
== media_destination::null
) {
1935 // producer destination not connected
1938 out_active_outputs
[i
] = *output
;
1939 *out_total_count
+= 1;
1940 buf_num_outputs
-= 1;
1942 PRINT_OUTPUT(" output ", out_active_outputs
[i
]);
1944 if (buf_num_outputs
== 0)
1949 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1955 BMediaRoster::GetAllOutputsFor(const media_node
& node
,
1956 media_output
* out_outputs
, int32 buf_num_outputs
, int32
* out_total_count
)
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
)
1964 List
<media_output
> list
;
1965 media_output
*output
;
1968 *out_total_count
= 0;
1970 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1974 PRINT(4, "BMediaRoster::GetAllOutputsFor node %" B_PRId32
", max %" B_PRId32
1975 "\n", node
.node
, buf_num_outputs
);
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;
1983 PRINT_OUTPUT(" output ", out_outputs
[i
]);
1985 if (buf_num_outputs
== 0)
1989 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1995 BMediaRoster::StartWatching(const BMessenger
& where
)
1998 if (!where
.IsValid()) {
1999 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
2002 return BPrivate::media::notifications::Register(where
, media_node::null
,
2008 BMediaRoster::StartWatching(const BMessenger
& where
, int32 notificationType
)
2011 if (!where
.IsValid()) {
2012 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
2015 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
2016 notificationType
)) {
2017 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
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
,
2030 BMediaRoster::StartWatching(const BMessenger
& where
, const media_node
& node
,
2031 int32 notificationType
)
2034 if (!where
.IsValid()) {
2035 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
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");
2047 return BPrivate::media::notifications::Register(where
, node
,
2053 BMediaRoster::StopWatching(const BMessenger
& where
)
2056 // messenger may already be invalid, so we don't check this
2057 return BPrivate::media::notifications::Unregister(where
, media_node::null
,
2063 BMediaRoster::StopWatching(const BMessenger
& where
, int32 notificationType
)
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");
2072 return BPrivate::media::notifications::Unregister(where
, media_node::null
,
2078 BMediaRoster::StopWatching(const BMessenger
& where
, const media_node
& node
,
2079 int32 notificationType
)
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");
2092 return BPrivate::media::notifications::Unregister(where
, node
,
2098 BMediaRoster::RegisterNode(BMediaNode
* node
)
2101 // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too)
2102 return MediaRosterEx(this)->RegisterNode(node
, -1, 0);
2107 BMediaRosterEx::RegisterNode(BMediaNode
* node
, media_addon_id addOnID
,
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.
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
));
2148 TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE "
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);
2218 BMediaRoster::UnregisterNode(BMediaNode
* node
)
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());
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());
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(),
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(),
2267 BMediaAddOn
*addon
= node
->AddOn(&reply
.flavor_id
);
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
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
;
2298 //! Thread safe for multiple calls to Roster()
2299 /*static*/ BMediaRoster
*
2300 BMediaRoster::Roster(status_t
* out_error
)
2302 BAutolock
lock(sInitLocker
);
2305 TRACE("Warning! You should have a valid BApplication.");
2307 if (!lock
.IsLocked())
2313 if (sDefaultInstance
== NULL
) {
2315 sDefaultInstance
= new (std::nothrow
) BMediaRosterEx(&err
);
2316 if (sDefaultInstance
== NULL
)
2318 else if (err
!= B_OK
) {
2319 if (sDefaultInstance
) {
2320 sDefaultInstance
->Lock();
2321 sDefaultInstance
->Quit();
2322 sDefaultInstance
= NULL
;
2326 } else if (be_app
!= NULL
) {
2327 be_app
->RegisterLooper(sDefaultInstance
);
2331 return sDefaultInstance
;
2335 /*static*/ BMediaRoster
*
2336 BMediaRoster::CurrentRoster()
2338 return sDefaultInstance
;
2343 BMediaRoster::SetTimeSourceFor(media_node_id node
, media_node_id time_source
)
2346 if (IS_INVALID_NODEID(node
) || IS_INVALID_NODEID(time_source
))
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.
2357 node_set_timesource_command cmd
;
2358 cmd
.timesource_id
= time_source
;
2359 result
= SendToPort(clone
.port
, NODE_SET_TIMESOURCE
,
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
);
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
);
2391 TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32
" time source %"
2392 B_PRId32
" OK\n", node
, time_source
);
2400 BMediaRoster::GetParameterWebFor(const media_node
& node
, BParameterWeb
** _web
)
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};
2416 // TODO: it might be better to query the node for the (current) parameter
2418 for (int i
= 0; (size
= requestsize
[i
]) != 0; i
++) {
2422 area
= create_area("parameter web data", &data
, B_ANY_ADDRESS
, size
,
2423 B_NO_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
2425 ERROR("BMediaRoster::GetParameterWebFor couldn't create area of "
2426 "size %" B_PRId32
"\n", size
);
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
));
2434 ERROR("BMediaRoster::GetParameterWebFor "
2435 "CONTROLLABLE_GET_PARAMETER_WEB failed\n");
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();
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();
2454 rv
= web
->Unflatten(reply
.code
, data
, reply
.size
);
2456 ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, "
2457 "%s\n", strerror(rv
));
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
);
2478 BMediaRoster::StartControlPanel(const media_node
& node
, BMessenger
* _messenger
)
2482 controllable_start_control_panel_request request
;
2483 controllable_start_control_panel_reply reply
;
2485 request
.node
= node
;
2488 rv
= QueryPort(node
.port
, CONTROLLABLE_START_CONTROL_PANEL
, &request
,
2489 sizeof(request
), &reply
, sizeof(reply
));
2493 if (reply
.team
!= -1 && _messenger
!= NULL
)
2494 *_messenger
= BMessenger(NULL
, reply
.team
);
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
)
2506 if (_info
== NULL
|| _count
== NULL
|| *_count
<= 0)
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
;
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
));
2535 *_count
= reply
.count
;
2537 if (reply
.count
> 0) {
2539 status
= read_port(request
.reply_port
, &code
, _info
,
2540 reply
.count
* sizeof(dormant_node_info
));
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
2554 Checks concerning global/local are not done here.
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
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
;
2586 rv
= GetDormantFlavorInfo(addonID
, flavorID
, &info
);
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
);
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");
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
);
2608 ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create "
2609 "more nodes for addon-id %" B_PRId32
", flavor-id %" B_PRId32
"\n",
2611 // Put the addon back into the pool
2612 gDormantNodeManager
->PutAddOn(addonID
);
2617 rv
= LoadNodeConfiguration(addonID
, flavorID
, &config
);
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
);
2628 ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor "
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
);
2638 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2639 "FlavorInstancesCount failed\n");
2641 return status
!= B_OK
? status
: B_ERROR
;
2644 rv
= RegisterNode(node
, addonID
, flavorID
);
2646 ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
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
);
2654 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2655 "FlavorInstancesCount failed\n");
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
,
2667 rv
= MediaRosterEx(this)->SetNodeCreator(node
->ID(), creator
);
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());
2692 BMediaRoster::InstantiateDormantNode(const dormant_node_info
& info
,
2693 media_node
* _node
, uint32 flags
)
2698 if (info
.addon
<= B_OK
) {
2699 ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32
2700 " invalid.\n", info
.addon
);
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
;
2714 rv
= MediaRosterEx(this)->GetDormantFlavorInfo(info
.addon
, info
.flavor_id
,
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
);
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");
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
));
2783 *_node
= reply
.node
;
2785 // creator team = -1, as this is a local node
2786 rv
= MediaRosterEx(this)->InstantiateDormantNode(info
.addon
,
2787 info
.flavor_id
, -1, _node
);
2790 *_node
= media_node::null
;
2791 return B_NAME_NOT_FOUND
;
2798 BMediaRoster::InstantiateDormantNode(const dormant_node_info
& info
,
2801 return InstantiateDormantNode(info
, _node
, 0);
2806 BMediaRoster::GetDormantNodeFor(const media_node
& node
,
2807 dormant_node_info
* _info
)
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
;
2819 request
.node
= node
;
2821 rv
= QueryServer(SERVER_GET_DORMANT_NODE_FOR
, &request
, sizeof(request
),
2822 &reply
, sizeof(reply
));
2826 *_info
= reply
.node_info
;
2832 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID
, int32 flavorID
,
2833 dormant_flavor_info
* _flavor
)
2836 if (_flavor
== NULL
)
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);
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
) {
2857 if (reply
->result
== B_OK
) {
2858 status
= _flavor
->Unflatten(reply
->type
, &reply
->flattened_data
,
2859 reply
->flattened_size
);
2861 status
= reply
->result
;
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.
2880 BMediaRoster::GetLatencyFor(const media_node
& producer
, bigtime_t
* _latency
)
2883 if (_latency
== NULL
)
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
;
2893 rv
= QueryPort(producer
.port
, PRODUCER_GET_LATENCY
, &request
,
2894 sizeof(request
), &reply
, sizeof(reply
));
2898 *_latency
= reply
.latency
;
2900 // printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2906 BMediaRoster::GetInitialLatencyFor(const media_node
& producer
,
2907 bigtime_t
* _latency
, uint32
* _flags
)
2910 if (_latency
== NULL
)
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
;
2920 rv
= QueryPort(producer
.port
, PRODUCER_GET_INITIAL_LATENCY
, &request
,
2921 sizeof(request
), &reply
, sizeof(reply
));
2925 *_latency
= reply
.initial_latency
;
2927 *_flags
= reply
.flags
;
2929 TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32
" has "
2930 "maximum initial latency %" B_PRId64
"\n", producer
.node
, *_latency
);
2936 BMediaRoster::GetStartLatencyFor(const media_node
& timeSource
,
2937 bigtime_t
* _latency
)
2940 if (_latency
== NULL
)
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
;
2950 rv
= QueryPort(timeSource
.port
, TIMESOURCE_GET_START_LATENCY
, &request
,
2951 sizeof(request
), &reply
, sizeof(reply
));
2955 *_latency
= reply
.start_latency
;
2957 TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32
" has "
2958 "maximum initial latency %" B_PRId64
"\n", timeSource
.node
, *_latency
);
2964 BMediaRoster::GetFileFormatsFor(const media_node
& fileInterface
,
2965 media_file_format
* _formats
, int32
* _numFormats
)
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)
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
);
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
;
3007 BMediaRoster::SetRefFor(const media_node
& file_interface
, const entry_ref
& file
,
3008 bool createAndTruncate
, bigtime_t
* _length
)
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
;
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
));
3032 if (!createAndTruncate
&& _length
)
3033 *_length
= reply
.duration
;
3040 BMediaRoster::GetRefFor(const media_node
& node
, entry_ref
* _file
,
3041 BMimeType
* mimeType
)
3045 if (IS_INVALID_NODE(node
)
3046 || (node
.kind
& B_FILE_INTERFACE
) == 0)
3047 return B_MEDIA_BAD_NODE
;
3052 fileinterface_get_ref_request request
;
3053 fileinterface_get_ref_reply reply
;
3056 rv
= QueryPort(node
.port
, FILEINTERFACE_GET_REF
, &request
, sizeof(request
),
3057 &reply
, sizeof(reply
));
3061 *_file
= entry_ref(reply
.device
, reply
.directory
, reply
.name
);
3064 mimeType
->SetTo(reply
.mimetype
);
3071 BMediaRoster::SniffRefFor(const media_node
& file_interface
,
3072 const entry_ref
& file
, BMimeType
* mimeType
, float* _capability
)
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
)
3083 fileinterface_sniff_ref_request request
;
3084 fileinterface_sniff_ref_reply reply
;
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
));
3096 mimeType
->SetTo(reply
.mimetype
);
3097 *_capability
= reply
.capability
;
3103 /*! This is the generic "here's a file, now can someone please play it"
3107 BMediaRoster::SniffRef(const entry_ref
& file
, uint64 requireNodeKinds
,
3108 dormant_node_info
* _node
, BMimeType
* mimeType
)
3112 TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64
3113 "\n", file
.name
, requireNodeKinds
);
3118 BMimeType aMimeType
;
3120 dormant_node_info nodes
[30];
3122 int32 highestCapability
= -1;
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
;
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
3167 BMediaRoster::GetDormantNodeForType(const BMimeType
& type
,
3168 uint64 requireNodeKinds
, dormant_node_info
* _node
)
3176 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info
& node
,
3177 media_file_format
* _readFormats
, int32 readCount
, int32
* _readCount
)
3185 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info
& node
,
3186 media_file_format
* _write_formats
, int32 writeCount
, int32
* _writeCount
)
3194 BMediaRoster::GetFormatFor(const media_output
& output
, media_format
* _format
,
3198 if (_format
== NULL
)
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
;
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
));
3217 *_format
= reply
.format
;
3223 BMediaRoster::GetFormatFor(const media_input
& input
, media_format
* _format
,
3227 if (_format
== NULL
)
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
;
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
));
3246 *_format
= reply
.format
;
3252 BMediaRoster::GetFormatFor(const media_node
& node
, media_format
* _format
,
3256 if (_format
== NULL
)
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
;
3268 BMediaRoster::GetNodeAttributesFor(const media_node
& node
,
3269 media_node_attribute
* _array
, size_t maxCount
)
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
;
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
);
3293 request
.count
= maxCount
;
3294 request
.area
= dataArea
;
3296 status
= QueryPort(node
.port
, NODE_GET_ATTRIBUTES_FOR
, &request
,
3297 sizeof(request
), &reply
, sizeof(reply
));
3301 memcpy(_array
, addr
, reply
.filled_count
3302 * sizeof(media_node_attribute
));
3304 delete_area(dataArea
);
3305 return reply
.filled_count
;
3310 BMediaRoster::NodeIDFor(port_id port
)
3314 server_node_id_for_request request
;
3315 server_node_id_for_reply reply
;
3318 request
.port
= port
;
3320 rv
= QueryServer(SERVER_NODE_ID_FOR
, &request
, sizeof(request
), &reply
,
3323 ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32
")\n", rv
);
3327 return reply
.node_id
;
3332 BMediaRoster::GetInstancesFor(media_addon_id addon
, int32 flavor
,
3333 media_node_id
* _id
, int32
* _count
)
3338 if (_count
&& *_count
<= 0)
3341 server_get_instances_for_request request
;
3342 server_get_instances_for_reply reply
;
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
));
3352 ERROR("BMediaRoster::GetLiveNodes failed\n");
3357 *_count
= reply
.count
;
3358 if (reply
.count
> 0)
3359 memcpy(_id
, reply
.node_id
, sizeof(media_node_id
) * reply
.count
);
3366 BMediaRoster::IsRunning()
3368 return be_roster
->IsRunning(B_MEDIA_SERVER_SIGNATURE
)
3369 && be_roster
->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE
);
3374 BMediaRoster::AudioBufferSizeFor(int32 channelCount
, uint32 sampleFormat
,
3375 float frameRate
, bus_type busKind
)
3377 bigtime_t bufferDuration
;
3380 if (busKind
== B_ISA_BUS
|| busKind
== B_PCMCIA_BUS
)
3381 bufferDuration
= 25000;
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
);
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.
3400 BMediaRoster::MediaFlags(media_flags cap
, void* buffer
, size_t maxSize
)
3407 // #pragma mark - BLooper overrides
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
, ¬ification
.what
)
3419 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3420 "find what parameter");
3423 if (message
->FindMessenger(NOTIFICATION_PARAM_MESSENGER
,
3424 ¬ification
.messenger
) != B_OK
) {
3425 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3429 sNotificationList
.Insert(notification
);
3433 case MEDIA_ROSTER_CANCEL_NOTIFICATIONS
:
3435 RosterNotification notification
;
3436 if (message
->FindInt32(NOTIFICATION_PARAM_WHAT
, ¬ification
.what
)
3438 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3439 "find what parameter");
3442 if (message
->FindMessenger(NOTIFICATION_PARAM_MESSENGER
,
3443 ¬ification
.messenger
) != B_OK
) {
3444 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3448 for (int32 i
= 0; i
< sNotificationList
.CountItems(); i
++) {
3449 RosterNotification
* current
;
3450 if (sNotificationList
.Get(i
, ¤t
) != true)
3452 if (current
->what
== notification
.what
3453 && current
->messenger
== notification
.messenger
) {
3454 sNotificationList
.Remove(i
);
3461 case B_SOME_APP_LAUNCHED
:
3464 if (message
->FindString("be:signature", &mimeSig
) != B_OK
)
3466 if (mimeSig
!= B_MEDIA_ADDON_SERVER_SIGNATURE
3467 && mimeSig
!= B_MEDIA_SERVER_SIGNATURE
)
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.");
3482 case B_SOME_APP_QUIT
:
3485 if (message
->FindString("be:signature", &mimeSig
) != B_OK
)
3487 if (mimeSig
!= B_MEDIA_ADDON_SERVER_SIGNATURE
3488 && mimeSig
!= B_MEDIA_SERVER_SIGNATURE
)
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
, ¤t
) != true)
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
);
3512 case MEDIA_SERVER_ALIVE
:
3514 if (!BMediaRoster::IsRunning())
3519 TRACE("BMediaRoster::MessageReceived media services are"
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
, ¤t
) != true)
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
);
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
)
3556 TRACE("BMediaRoster::MessageReceived: CRITICAL! received"
3557 "a release request but the node can't be found.");
3563 BLooper::MessageReceived(message
);
3570 BMediaRoster::QuitRequested()
3578 BMediaRoster::ResolveSpecifier(BMessage
* msg
, int32 index
, BMessage
* specifier
,
3579 int32 form
, const char* property
)
3581 return BLooper::ResolveSpecifier(msg
, index
, specifier
, form
, property
);
3586 BMediaRoster::GetSupportedSuites(BMessage
* data
)
3588 return BLooper::GetSupportedSuites(data
);
3592 BMediaRoster::~BMediaRoster()
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
)
3625 // #pragma mark - static variables
3627 BMediaRoster
* BMediaRoster::sDefaultInstance
= NULL
;