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>
47 #include <BufferConsumer.h>
48 #include <BufferProducer.h>
51 #include <Messenger.h>
54 #include <ParameterWeb.h>
56 #include <StopWatch.h>
58 #include <TimeSource.h>
62 #include <DataExchange.h>
64 #include <DormantNodeManager.h>
65 #include <MediaMisc.h>
66 #include <MediaRosterEx.h>
67 #include <Notifications.h>
68 #include <ServerInterface.h>
69 #include <SharedBufferList.h>
72 #include "TimeSourceObjectManager.h"
79 struct RosterNotification
{
84 static bool sServerIsUp
= false;
85 static List
<RosterNotification
> sNotificationList
;
88 } // namespace BPrivate
90 using namespace BPrivate::media
;
93 BMediaRosterEx::BMediaRosterEx(status_t
* _error
)
97 gDormantNodeManager
= new DormantNodeManager
;
98 gTimeSourceObjectManager
= new TimeSourceObjectManager
;
100 *_error
= BuildConnections();
102 InitRosterDataExchange(BMessenger(this, this));
104 if (be_roster
->StartWatching(BMessenger(this, this),
105 B_REQUEST_LAUNCHED
| B_REQUEST_QUIT
) != B_OK
) {
108 sServerIsUp
= BMediaRoster::IsRunning();
113 BMediaRosterEx::BuildConnections()
115 InitServerDataExchange();
116 // register this application with the media server
117 server_register_app_request request
;
118 server_register_app_reply reply
;
119 request
.team
= BPrivate::current_team();
120 request
.messenger
= BMessenger(NULL
, this);
121 status_t status
= QueryServer(SERVER_REGISTER_APP
, &request
,
122 sizeof(request
), &reply
, sizeof(reply
));
124 return B_MEDIA_SYSTEM_FAILURE
;
130 BMediaRosterEx::~BMediaRosterEx()
134 delete gTimeSourceObjectManager
;
135 delete gDormantNodeManager
;
137 // unregister this application with the media server
138 server_unregister_app_request request
;
139 server_unregister_app_reply reply
;
140 request
.team
= BPrivate::current_team();
141 QueryServer(SERVER_UNREGISTER_APP
, &request
, sizeof(request
), &reply
,
144 BPrivate::SharedBufferList::Invalidate();
149 BMediaRosterEx::SaveNodeConfiguration(BMediaNode
* node
)
152 BMediaAddOn
* addon
= node
->AddOn(&flavorID
);
154 // NOTE: This node could have been created by an application,
155 // it does not mean there is an error.
156 // TODO: this check incorrectly triggers on BeOS R5 BT848 node
157 TRACE("BMediaRosterEx::SaveNodeConfiguration node %" B_PRId32
" not "
158 "instantiated from BMediaAddOn!\n", node
->ID());
162 media_addon_id addonID
= addon
->AddonID();
165 printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id "
166 "%" B_PRId32
", flavor-id %" B_PRId32
" config NOW!\n", addonID
,
173 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonID
, int32 flavorID
,
177 _msg
->MakeEmpty(); // to be fully R5 compliant
178 printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id "
179 "%" B_PRId32
", flavor-id %" B_PRId32
" config NOW!\n", addonID
,
186 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonID
,
189 server_change_flavor_instances_count_request request
;
190 server_change_flavor_instances_count_reply reply
;
192 request
.add_on_id
= addonID
;
193 request
.flavor_id
= flavorID
;
195 request
.team
= BPrivate::current_team();
196 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT
, &request
,
197 sizeof(request
), &reply
, sizeof(reply
));
202 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonID
,
205 server_change_flavor_instances_count_request request
;
206 server_change_flavor_instances_count_reply reply
;
208 request
.add_on_id
= addonID
;
209 request
.flavor_id
= flavorID
;
211 request
.team
= BPrivate::current_team();
212 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT
, &request
,
213 sizeof(request
), &reply
, sizeof(reply
));
218 BMediaRosterEx::ReleaseNodeAll(const media_node
& node
)
221 if (IS_INVALID_NODE(node
))
222 return B_MEDIA_BAD_NODE
;
224 if (node
.kind
& NODE_KIND_NO_REFCOUNTING
)
227 server_release_node_request request
;
228 server_release_node_reply reply
;
232 request
.team
= BPrivate::current_team();
234 TRACE("BMediaRoster::ReleaseNodeAll, node %" B_PRId32
", port %" B_PRId32
235 ", team %" B_PRId32
"\n",
236 node
.node
, node
.port
, BPrivate::current_team());
238 rv
= QueryServer(SERVER_RELEASE_NODE_ALL
, &request
, sizeof(request
), &reply
,
241 ERROR("BMediaRoster::ReleaseNodeAll failed to query media_server, "
242 "retrying local, node %" B_PRId32
", port %"
243 B_PRId32
", team %" B_PRId32
"!\n", node
.node
, node
.port
,
244 BPrivate::current_team());
245 node_final_release_command command
;
246 rv
= SendToPort(node
.port
, NODE_FINAL_RELEASE
, &command
,
249 ERROR("BMediaRoster::ReleaseNodeAll FAILED, node %" B_PRId32
", port %"
250 B_PRId32
", team %" B_PRId32
"!\n", node
.node
, node
.port
,
251 BPrivate::current_team());
259 BMediaRosterEx::SetNodeCreator(media_node_id node
, team_id creator
)
261 server_set_node_creator_request request
;
262 server_set_node_creator_reply reply
;
265 request
.creator
= creator
;
266 return QueryServer(SERVER_SET_NODE_CREATOR
, &request
, sizeof(request
),
267 &reply
, sizeof(reply
));
272 BMediaRosterEx::GetNode(node_type type
, media_node
* out_node
,
273 int32
* out_input_id
, BString
* out_input_name
)
275 if (out_node
== NULL
)
278 server_get_node_request request
;
279 server_get_node_reply reply
;
283 request
.team
= BPrivate::current_team();
284 rv
= QueryServer(SERVER_GET_NODE
, &request
, sizeof(request
), &reply
,
289 *out_node
= reply
.node
;
291 *out_input_id
= reply
.input_id
;
293 *out_input_name
= reply
.input_name
;
299 BMediaRosterEx::SetNode(node_type type
, const media_node
* node
,
300 const dormant_node_info
* info
, const media_input
* input
)
302 server_set_node_request request
;
303 server_set_node_reply reply
;
306 request
.use_node
= node
!= NULL
;
308 request
.node
= *node
;
309 request
.use_dni
= info
!= NULL
;
312 request
.use_input
= input
!= NULL
;
314 request
.input
= *input
;
316 return QueryServer(SERVER_SET_NODE
, &request
, sizeof(request
), &reply
,
322 BMediaRosterEx::GetAllOutputs(const media_node
& node
, List
<media_output
>* list
)
328 PRINT(4, "BMediaRosterEx::GetAllOutputs() node %" B_PRId32
", port %"
329 B_PRId32
"\n", node
.node
, node
.port
);
331 if (!(node
.kind
& B_BUFFER_PRODUCER
)) {
332 ERROR("BMediaRosterEx::GetAllOutputs: node %" B_PRId32
" is not a "
333 "B_BUFFER_PRODUCER\n", node
.node
);
334 return B_MEDIA_BAD_NODE
;
341 producer_get_next_output_request request
;
342 producer_get_next_output_reply reply
;
343 request
.cookie
= cookie
;
344 rv
= QueryPort(node
.port
, PRODUCER_GET_NEXT_OUTPUT
, &request
,
345 sizeof(request
), &reply
, sizeof(reply
));
348 cookie
= reply
.cookie
;
349 if (!list
->Insert(reply
.output
)) {
350 ERROR("GetAllOutputs: list->Insert failed\n");
354 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
355 PRINT_OUTPUT("output ", reply
.output
);
359 producer_dispose_output_cookie_request request
;
360 producer_dispose_output_cookie_reply reply
;
361 QueryPort(node
.port
, PRODUCER_DISPOSE_OUTPUT_COOKIE
, &request
,
362 sizeof(request
), &reply
, sizeof(reply
));
369 BMediaRosterEx::GetAllOutputs(BBufferProducer
* node
, List
<media_output
>* list
)
374 PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %" B_PRId32
375 ", port %" B_PRId32
"\n", node
->ID(), node
->ControlPort());
382 if (B_OK
!= node
->GetNextOutput(&cookie
, &output
))
384 if (!list
->Insert(output
)) {
385 ERROR("GetAllOutputs: list->Insert failed\n");
389 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
390 PRINT_OUTPUT("output ", output
);
393 node
->DisposeOutputCookie(cookie
);
399 BMediaRosterEx::GetAllInputs(const media_node
& node
, List
<media_input
>* list
)
405 PRINT(4, "BMediaRosterEx::GetAllInputs() node %" B_PRId32
", port %"
406 B_PRId32
"\n", node
.node
, node
.port
);
408 if (!(node
.kind
& B_BUFFER_CONSUMER
)) {
409 ERROR("BMediaRosterEx::GetAllInputs: node %" B_PRId32
" is not a "
410 "B_BUFFER_CONSUMER\n", node
.node
);
411 return B_MEDIA_BAD_NODE
;
418 consumer_get_next_input_request request
;
419 consumer_get_next_input_reply reply
;
420 request
.cookie
= cookie
;
421 rv
= QueryPort(node
.port
, CONSUMER_GET_NEXT_INPUT
, &request
,
422 sizeof(request
), &reply
, sizeof(reply
));
425 cookie
= reply
.cookie
;
426 if (!list
->Insert(reply
.input
)) {
427 ERROR("GetAllInputs: list->Insert failed\n");
431 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
432 PRINT_OUTPUT("input ", reply
.input
);
436 consumer_dispose_input_cookie_request request
;
437 consumer_dispose_input_cookie_reply reply
;
438 QueryPort(node
.port
, CONSUMER_DISPOSE_INPUT_COOKIE
, &request
,
439 sizeof(request
), &reply
, sizeof(reply
));
446 BMediaRosterEx::GetAllInputs(BBufferConsumer
* node
, List
<media_input
>* list
)
451 PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %" B_PRId32
452 ", port %" B_PRId32
"\n", node
->ID(), node
->ControlPort());
459 if (B_OK
!= node
->GetNextInput(&cookie
, &input
))
461 if (!list
->Insert(input
)) {
462 ERROR("GetAllInputs: list->Insert failed\n");
466 PRINT(3," next cookie %" B_PRId32
", ", cookie
);
467 PRINT_INPUT("input ", input
);
470 node
->DisposeInputCookie(cookie
);
476 BMediaRosterEx::PublishOutputs(const media_node
& node
, List
<media_output
>* list
)
478 server_publish_outputs_request request
;
479 server_publish_outputs_reply reply
;
480 media_output
* output
;
481 media_output
* outputs
;
485 count
= list
->CountItems();
486 TRACE("PublishOutputs: publishing %" B_PRId32
"\n", count
);
489 request
.count
= count
;
490 if (count
> MAX_OUTPUTS
) {
493 size
= ROUND_UP_TO_PAGE(count
* sizeof(media_output
));
494 request
.area
= create_area("publish outputs", &start_addr
,
495 B_ANY_ADDRESS
, size
, B_NO_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
496 if (request
.area
< B_OK
) {
497 ERROR("PublishOutputs: failed to create area, %#" B_PRIx32
"\n",
499 return (status_t
)request
.area
;
501 outputs
= static_cast<media_output
*>(start_addr
);
504 outputs
= request
.outputs
;
506 TRACE("PublishOutputs: area %" B_PRId32
"\n", request
.area
);
509 for (i
= 0, list
->Rewind(); list
->GetNext(&output
); i
++) {
511 outputs
[i
] = *output
;
514 rv
= QueryServer(SERVER_PUBLISH_OUTPUTS
, &request
, sizeof(request
),
515 &reply
, sizeof(reply
));
517 if (request
.area
!= -1)
518 delete_area(request
.area
);
525 BMediaRosterEx::PublishInputs(const media_node
& node
, List
<media_input
>* list
)
527 server_publish_inputs_request request
;
528 server_publish_inputs_reply reply
;
534 count
= list
->CountItems();
535 TRACE("PublishInputs: publishing %" B_PRId32
"\n", count
);
538 request
.count
= count
;
539 if (count
> MAX_INPUTS
) {
542 size
= ROUND_UP_TO_PAGE(count
* sizeof(media_input
));
543 request
.area
= create_area("publish inputs", &start_addr
,
544 B_ANY_ADDRESS
, size
, B_NO_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
545 if (request
.area
< B_OK
) {
546 ERROR("PublishInputs: failed to create area, %#" B_PRIx32
"\n",
548 return (status_t
)request
.area
;
550 inputs
= static_cast<media_input
*>(start_addr
);
553 inputs
= request
.inputs
;
555 TRACE("PublishInputs: area %" B_PRId32
"\n", request
.area
);
558 for (i
= 0, list
->Rewind(); list
->GetNext(&input
); i
++) {
563 rv
= QueryServer(SERVER_PUBLISH_INPUTS
, &request
, sizeof(request
),
564 &reply
, sizeof(reply
));
566 if (request
.area
!= -1)
567 delete_area(request
.area
);
574 BMediaRosterEx::MakeTimeSourceObject(media_node_id timeSourceID
)
577 status_t status
= GetNodeFor(timeSourceID
, &clone
);
578 if (status
!= B_OK
) {
579 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed: %s\n",
584 BTimeSource
* source
= gTimeSourceObjectManager
->GetTimeSource(clone
);
585 if (source
== NULL
) {
586 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n");
597 // #pragma mark - public BMediaRoster
601 BMediaRoster::GetVideoInput(media_node
* _node
)
604 return MediaRosterEx(this)->GetNode(VIDEO_INPUT
, _node
);
609 BMediaRoster::GetAudioInput(media_node
* _node
)
612 return MediaRosterEx(this)->GetNode(AUDIO_INPUT
, _node
);
617 BMediaRoster::GetVideoOutput(media_node
* _node
)
620 return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT
, _node
);
625 BMediaRoster::GetAudioMixer(media_node
* _node
)
628 return MediaRosterEx(this)->GetNode(AUDIO_MIXER
, _node
);
633 BMediaRoster::GetAudioOutput(media_node
* _node
)
636 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT
, _node
);
641 BMediaRoster::GetAudioOutput(media_node
* _node
, int32
* _inputID
,
645 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX
, _node
, _inputID
,
651 BMediaRoster::GetTimeSource(media_node
* _node
)
656 // TODO: need to do this in a nicer way.
658 rv
= MediaRosterEx(this)->GetNode(TIME_SOURCE
, _node
);
662 // We don't do reference counting for timesources, that's why we
663 // release the node immediately.
666 // we need to remember to not use this node with server side reference counting
667 _node
->kind
|= NODE_KIND_NO_REFCOUNTING
;
673 BMediaRoster::SetVideoInput(const media_node
& producer
)
676 return MediaRosterEx(this)->SetNode(VIDEO_INPUT
, &producer
);
681 BMediaRoster::SetVideoInput(const dormant_node_info
& producer
)
684 return MediaRosterEx(this)->SetNode(VIDEO_INPUT
, NULL
, &producer
);
689 BMediaRoster::SetAudioInput(const media_node
& producer
)
692 return MediaRosterEx(this)->SetNode(AUDIO_INPUT
, &producer
);
697 BMediaRoster::SetAudioInput(const dormant_node_info
& producer
)
700 return MediaRosterEx(this)->SetNode(AUDIO_INPUT
, NULL
, &producer
);
705 BMediaRoster::SetVideoOutput(const media_node
& consumer
)
708 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT
, &consumer
);
713 BMediaRoster::SetVideoOutput(const dormant_node_info
& consumer
)
716 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT
, NULL
, &consumer
);
721 BMediaRoster::SetAudioOutput(const media_node
& consumer
)
724 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, &consumer
);
729 BMediaRoster::SetAudioOutput(const media_input
& input
)
732 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, NULL
, NULL
, &input
);
737 BMediaRoster::SetAudioOutput(const dormant_node_info
& consumer
)
740 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT
, NULL
, &consumer
);
745 BMediaRoster::GetNodeFor(media_node_id node
, media_node
* clone
)
750 if (IS_INVALID_NODEID(node
))
751 return B_MEDIA_BAD_NODE
;
753 server_get_node_for_request request
;
754 server_get_node_for_reply reply
;
757 request
.node_id
= node
;
758 request
.team
= BPrivate::current_team();
760 rv
= QueryServer(SERVER_GET_NODE_FOR
, &request
, sizeof(request
), &reply
,
765 *clone
= reply
.clone
;
771 BMediaRoster::GetSystemTimeSource(media_node
* clone
)
776 // TODO: need to do this in a nicer way.
778 rv
= MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE
, clone
);
782 // We don't do reference counting for timesources, that's why we
783 // release the node immediately.
786 // we need to remember to not use this node with server side reference
788 clone
->kind
|= NODE_KIND_NO_REFCOUNTING
;
795 BMediaRoster::ReleaseNode(const media_node
& node
)
798 if (IS_INVALID_NODE(node
))
799 return B_MEDIA_BAD_NODE
;
801 if (node
.kind
& NODE_KIND_NO_REFCOUNTING
) {
802 TRACE("BMediaRoster::ReleaseNode, trying to release reference "
803 "counting disabled timesource, node %" B_PRId32
", port %" B_PRId32
804 ", team %" B_PRId32
"\n", node
.node
, node
.port
,
805 BPrivate::current_team());
809 server_release_node_request request
;
810 server_release_node_reply reply
;
814 request
.team
= BPrivate::current_team();
816 TRACE("BMediaRoster::ReleaseNode, node %" B_PRId32
", port %" B_PRId32
817 ", team %" B_PRId32
"\n", node
.node
, node
.port
,
818 BPrivate::current_team());
820 rv
= QueryServer(SERVER_RELEASE_NODE
, &request
, sizeof(request
), &reply
,
823 ERROR("BMediaRoster::ReleaseNode FAILED, node %" B_PRId32
", port %"
824 B_PRId32
", team %" B_PRId32
"!\n", node
.node
, node
.port
,
825 BPrivate::current_team());
832 BMediaRoster::MakeTimeSourceFor(const media_node
& forNode
)
834 // MakeTimeSourceFor() returns a BTimeSource object
835 // corresponding to the specified node's time source.
839 if (IS_SYSTEM_TIMESOURCE(forNode
)) {
840 // special handling for the system time source
841 TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time "
843 return MediaRosterEx(this)->MakeTimeSourceObject(
844 NODE_SYSTEM_TIMESOURCE_ID
);
847 if (IS_INVALID_NODE(forNode
)) {
848 ERROR("BMediaRoster::MakeTimeSourceFor: for_node invalid, node %"
849 B_PRId32
", port %" B_PRId32
", kinds 0x%" B_PRIx32
"\n",
850 forNode
.node
, forNode
.port
, forNode
.kind
);
854 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32
" enter\n",
857 node_get_timesource_request request
;
858 node_get_timesource_reply reply
;
862 // ask the node to get it's current timesource id
863 rv
= QueryPort(forNode
.port
, NODE_GET_TIMESOURCE
, &request
,
864 sizeof(request
), &reply
, sizeof(reply
));
866 ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n");
870 source
= MediaRosterEx(this)->MakeTimeSourceObject(reply
.timesource_id
);
872 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32
" leave\n",
880 BMediaRoster::Connect(const media_source
& from
, const media_destination
& to
,
881 media_format
* _format
, media_output
* _output
, media_input
* _input
)
883 return BMediaRoster::Connect(from
, to
, _format
, _output
, _input
, 0);
888 BMediaRoster::Connect(const media_source
& from
, const media_destination
& to
,
889 media_format
* io_format
, media_output
* out_output
, media_input
* out_input
,
890 uint32 in_flags
, void* _reserved
)
893 if (io_format
== NULL
|| out_output
== NULL
|| out_input
== NULL
)
895 if (IS_INVALID_SOURCE(from
)) {
896 ERROR("BMediaRoster::Connect: media_source invalid\n");
897 return B_MEDIA_BAD_SOURCE
;
899 if (IS_INVALID_DESTINATION(to
)) {
900 ERROR("BMediaRoster::Connect: media_destination invalid\n");
901 return B_MEDIA_BAD_DESTINATION
;
906 // find the output and input nodes
907 // TODO: isn't there a easier way?
908 media_node sourcenode
;
910 rv
= GetNodeFor(NodeIDFor(from
.port
), &sourcenode
);
912 ERROR("BMediaRoster::Connect: Can't find source node for port %"
913 B_PRId32
"\n", from
.port
);
914 return B_MEDIA_BAD_SOURCE
;
916 ReleaseNode(sourcenode
);
917 rv
= GetNodeFor(NodeIDFor(to
.port
), &destnode
);
919 ERROR("BMediaRoster::Connect: Can't find destination node for port "
920 "%" B_PRId32
"\n", to
.port
);
921 return B_MEDIA_BAD_DESTINATION
;
923 ReleaseNode(destnode
);
925 if (!(sourcenode
.kind
& B_BUFFER_PRODUCER
)) {
926 ERROR("BMediaRoster::Connect: source node %" B_PRId32
" is not a "
927 "B_BUFFER_PRODUCER\n", sourcenode
.node
);
928 return B_MEDIA_BAD_SOURCE
;
930 if (!(destnode
.kind
& B_BUFFER_CONSUMER
)) {
931 ERROR("BMediaRoster::Connect: destination node %" B_PRId32
" is not a "
932 "B_BUFFER_CONSUMER\n", destnode
.node
);
933 return B_MEDIA_BAD_DESTINATION
;
936 producer_format_proposal_request request1
;
937 producer_format_proposal_reply reply1
;
939 PRINT_FORMAT("BMediaRoster::Connect calling "
940 "BBufferProducer::FormatProposal with format ", *io_format
);
942 // BBufferProducer::FormatProposal
943 request1
.output
= from
;
944 request1
.format
= *io_format
;
945 rv
= QueryPort(from
.port
, PRODUCER_FORMAT_PROPOSAL
, &request1
,
946 sizeof(request1
), &reply1
, sizeof(reply1
));
948 ERROR("BMediaRoster::Connect: aborted after "
949 "BBufferProducer::FormatProposal, status = %#" B_PRIx32
"\n",rv
);
952 // reply1.format now contains the format proposed by the producer
954 consumer_accept_format_request request2
;
955 consumer_accept_format_reply reply2
;
957 PRINT_FORMAT("BMediaRoster::Connect calling "
958 "BBufferConsumer::AcceptFormat with format ", reply1
.format
);
960 // BBufferConsumer::AcceptFormat
962 request2
.format
= reply1
.format
;
963 rv
= QueryPort(to
.port
, CONSUMER_ACCEPT_FORMAT
, &request2
,
964 sizeof(request2
), &reply2
, sizeof(reply2
));
966 ERROR("BMediaRoster::Connect: aborted after "
967 "BBufferConsumer::AcceptFormat, status = %#" B_PRIx32
"\n",rv
);
970 // reply2.format now contains the format accepted by the consumer
972 // BBufferProducer::PrepareToConnect
973 producer_prepare_to_connect_request request3
;
974 producer_prepare_to_connect_reply reply3
;
976 PRINT_FORMAT("BMediaRoster::Connect calling "
977 "BBufferProducer::PrepareToConnect with format", reply2
.format
);
979 request3
.source
= from
;
980 request3
.destination
= to
;
981 request3
.format
= reply2
.format
;
982 strcpy(request3
.name
, "XXX some default name"); // TODO: fix this
983 rv
= QueryPort(from
.port
, PRODUCER_PREPARE_TO_CONNECT
, &request3
,
984 sizeof(request3
), &reply3
, sizeof(reply3
));
986 ERROR("BMediaRoster::Connect: aborted after "
987 "BBufferProducer::PrepareToConnect, status = %#" B_PRIx32
"\n", rv
);
990 // reply3.format is still our pretty media format
991 // reply3.out_source the real source to be used for the connection
992 // reply3.name the name BBufferConsumer::Connected will see in the
993 // outInput->name argument
995 // BBufferConsumer::Connected
996 consumer_connected_request request4
;
997 consumer_connected_reply reply4
;
1000 PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::Connected() "
1001 "with format ", reply3
.format
);
1003 request4
.input
.node
= destnode
;
1004 request4
.input
.source
= reply3
.out_source
;
1005 request4
.input
.destination
= to
;
1006 request4
.input
.format
= reply3
.format
;
1007 strcpy(request4
.input
.name
, reply3
.name
);
1009 con_status
= QueryPort(to
.port
, CONSUMER_CONNECTED
, &request4
,
1010 sizeof(request4
), &reply4
, sizeof(reply4
));
1011 if (con_status
!= B_OK
) {
1012 ERROR("BMediaRoster::Connect: aborting after "
1013 "BBufferConsumer::Connected, status = %#" B_PRIx32
"\n",
1015 // we do NOT return here!
1017 // con_status contains the status code to be supplied to
1018 // BBufferProducer::Connect's status argument
1019 // reply4.input contains the media_input that describes the connection
1020 // from the consumer point of view
1022 // BBufferProducer::Connect
1023 producer_connect_request request5
;
1024 producer_connect_reply reply5
;
1026 PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::Connect with "
1027 "format ", reply4
.input
.format
);
1029 request5
.error
= con_status
;
1030 request5
.source
= reply3
.out_source
;
1031 request5
.destination
= reply4
.input
.destination
;
1032 request5
.format
= reply4
.input
.format
;
1033 strcpy(request5
.name
, reply4
.input
.name
);
1034 rv
= QueryPort(reply4
.input
.source
.port
, PRODUCER_CONNECT
, &request5
,
1035 sizeof(request5
), &reply5
, sizeof(reply5
));
1036 if (con_status
!= B_OK
) {
1037 ERROR("BMediaRoster::Connect: aborted\n");
1041 ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect()"
1042 ", status = %#" B_PRIx32
"\n", rv
);
1045 // reply5.name contains the name assigned to the connection by the producer
1047 // initilize connection info
1048 *io_format
= reply4
.input
.format
;
1049 *out_input
= reply4
.input
;
1050 out_output
->node
= sourcenode
;
1051 out_output
->source
= reply4
.input
.source
;
1052 out_output
->destination
= reply4
.input
.destination
;
1053 out_output
->format
= reply4
.input
.format
;
1054 strcpy(out_output
->name
, reply5
.name
);
1056 // the connection is now made
1057 PRINT_FORMAT(" format", *io_format
);
1058 PRINT_INPUT(" input", *out_input
);
1059 PRINT_OUTPUT(" output", *out_output
);
1061 // TODO: register connection with server
1062 // TODO: we should just send a notification, instead of republishing all
1064 List
<media_output
> outlist
;
1065 List
<media_input
> inlist
;
1066 if (MediaRosterEx(this)->GetAllOutputs(out_output
->node
, &outlist
) == B_OK
)
1067 MediaRosterEx(this)->PublishOutputs(out_output
->node
, &outlist
);
1068 if (MediaRosterEx(this)->GetAllInputs(out_input
->node
, &inlist
) == B_OK
)
1069 MediaRosterEx(this)->PublishInputs(out_input
->node
, &inlist
);
1071 // TODO: if (mute) BBufferProducer::EnableOutput(false)
1072 if (in_flags
& B_CONNECT_MUTED
) {
1075 // send a notification
1076 BPrivate::media::notifications::ConnectionMade(*out_input
, *out_output
,
1084 BMediaRoster::Disconnect(media_node_id source_nodeid
,
1085 const media_source
& source
, media_node_id destination_nodeid
,
1086 const media_destination
& destination
)
1089 if (IS_INVALID_NODEID(source_nodeid
)) {
1090 ERROR("BMediaRoster::Disconnect: source media_node_id invalid\n");
1091 return B_MEDIA_BAD_SOURCE
;
1093 if (IS_INVALID_NODEID(destination_nodeid
)) {
1094 ERROR("BMediaRoster::Disconnect: destination media_node_id invalid\n");
1095 return B_MEDIA_BAD_DESTINATION
;
1097 if (IS_INVALID_SOURCE(source
)) {
1098 ERROR("BMediaRoster::Disconnect: media_source invalid\n");
1099 return B_MEDIA_BAD_SOURCE
;
1101 if (IS_INVALID_DESTINATION(destination
)) {
1102 ERROR("BMediaRoster::Disconnect: media_destination invalid\n");
1103 return B_MEDIA_BAD_DESTINATION
;
1106 producer_disconnect_request request2
;
1107 producer_disconnect_reply reply2
;
1108 consumer_disconnected_request request1
;
1109 consumer_disconnected_reply reply1
;
1112 // TODO: we should ask the server if this connection really exists
1114 request1
.source
= source
;
1115 request1
.destination
= destination
;
1116 request2
.source
= source
;
1117 request2
.destination
= destination
;
1119 rv1
= QueryPort(source
.port
, PRODUCER_DISCONNECT
, &request1
,
1120 sizeof(request1
), &reply1
, sizeof(reply1
));
1121 rv2
= QueryPort(destination
.port
, CONSUMER_DISCONNECTED
, &request2
,
1122 sizeof(request2
), &reply2
, sizeof(reply2
));
1124 // TODO: unregister connection with server
1125 // TODO: we should just send a notification, instead of republishing all
1127 List
<media_output
> outlist
;
1128 List
<media_input
> inlist
;
1129 media_node sourcenode
;
1130 media_node destnode
;
1131 if (GetNodeFor(source_nodeid
, &sourcenode
) == B_OK
) {
1132 if (!(sourcenode
.kind
& B_BUFFER_PRODUCER
)) {
1133 ERROR("BMediaRoster::Disconnect: source_nodeid %" B_PRId32
1134 " is not a B_BUFFER_PRODUCER\n", source_nodeid
);
1136 if (MediaRosterEx(this)->GetAllOutputs(sourcenode
, &outlist
) == B_OK
)
1137 MediaRosterEx(this)->PublishOutputs(sourcenode
, &outlist
);
1138 ReleaseNode(sourcenode
);
1140 ERROR("BMediaRoster::Disconnect: GetNodeFor source_nodeid %" B_PRId32
1141 " failed\n", source_nodeid
);
1143 if (GetNodeFor(destination_nodeid
, &destnode
) == B_OK
) {
1144 if (!(destnode
.kind
& B_BUFFER_CONSUMER
)) {
1145 ERROR("BMediaRoster::Disconnect: destination_nodeid %" B_PRId32
1146 " is not a B_BUFFER_CONSUMER\n", destination_nodeid
);
1148 if (MediaRosterEx(this)->GetAllInputs(destnode
, &inlist
) == B_OK
)
1149 MediaRosterEx(this)->PublishInputs(destnode
, &inlist
);
1150 ReleaseNode(destnode
);
1152 ERROR("BMediaRoster::Disconnect: GetNodeFor destination_nodeid %"
1153 B_PRId32
" failed\n", destination_nodeid
);
1156 // send a notification
1157 BPrivate::media::notifications::ConnectionBroken(source
, destination
);
1159 return rv1
!= B_OK
|| rv2
!= B_OK
? B_ERROR
: B_OK
;
1164 BMediaRoster::Disconnect(const media_output
& output
, const media_input
& input
)
1166 if (IS_INVALID_NODEID(output
.node
.node
)) {
1167 printf("BMediaRoster::Disconnect: output.node.node %" B_PRId32
1168 " invalid\n", output
.node
.node
);
1169 return B_MEDIA_BAD_SOURCE
;
1171 if (IS_INVALID_NODEID(input
.node
.node
)) {
1172 printf("BMediaRoster::Disconnect: input.node.node %" B_PRId32
1173 " invalid\n", input
.node
.node
);
1174 return B_MEDIA_BAD_DESTINATION
;
1176 if (!(output
.node
.kind
& B_BUFFER_PRODUCER
)) {
1177 printf("BMediaRoster::Disconnect: output.node.kind 0x%" B_PRIx32
1178 " is no B_BUFFER_PRODUCER\n", output
.node
.kind
);
1179 return B_MEDIA_BAD_SOURCE
;
1181 if (!(input
.node
.kind
& B_BUFFER_CONSUMER
)) {
1182 printf("BMediaRoster::Disconnect: input.node.kind 0x%" B_PRIx32
1183 " is no B_BUFFER_PRODUCER\n", input
.node
.kind
);
1184 return B_MEDIA_BAD_DESTINATION
;
1186 if (input
.source
.port
!= output
.source
.port
) {
1187 printf("BMediaRoster::Disconnect: input.source.port %" B_PRId32
1188 " doesn't match output.source.port %" B_PRId32
"\n",
1189 input
.source
.port
, output
.source
.port
);
1190 return B_MEDIA_BAD_SOURCE
;
1192 if (input
.source
.id
!= output
.source
.id
) {
1193 printf("BMediaRoster::Disconnect: input.source.id %" B_PRId32
1194 " doesn't match output.source.id %" B_PRId32
"\n", input
.source
.id
,
1196 return B_MEDIA_BAD_SOURCE
;
1198 if (input
.destination
.port
!= output
.destination
.port
) {
1199 printf("BMediaRoster::Disconnect: input.destination.port %" B_PRId32
1200 " doesn't match output.destination.port %" B_PRId32
"\n",
1201 input
.destination
.port
, output
.destination
.port
);
1202 return B_MEDIA_BAD_DESTINATION
;
1204 if (input
.destination
.id
!= output
.destination
.id
) {
1205 printf("BMediaRoster::Disconnect: input.destination.id %" B_PRId32
1206 " doesn't match output.destination.id %" B_PRId32
"\n",
1207 input
.destination
.id
, output
.destination
.id
);
1208 return B_MEDIA_BAD_DESTINATION
;
1211 return Disconnect(output
.node
.node
, output
.source
, input
.node
.node
,
1217 BMediaRoster::StartNode(const media_node
& node
, bigtime_t atPerformanceTime
)
1221 return B_MEDIA_BAD_NODE
;
1223 TRACE("BMediaRoster::StartNode, node %" B_PRId32
", at perf %" B_PRId64
1224 "\n", node
.node
, atPerformanceTime
);
1226 node_start_command command
;
1227 command
.performance_time
= atPerformanceTime
;
1229 return SendToPort(node
.port
, NODE_START
, &command
, sizeof(command
));
1234 BMediaRoster::StopNode(const media_node
& node
, bigtime_t atPerformanceTime
,
1238 if (IS_INVALID_NODE(node
))
1239 return B_MEDIA_BAD_NODE
;
1241 TRACE("BMediaRoster::StopNode, node %" B_PRId32
", at perf %" B_PRId64
1242 " %s\n", node
.node
, atPerformanceTime
, immediate
? "NOW" : "");
1244 node_stop_command command
;
1245 command
.performance_time
= atPerformanceTime
;
1246 command
.immediate
= immediate
;
1248 return SendToPort(node
.port
, NODE_STOP
, &command
, sizeof(command
));
1253 BMediaRoster::SeekNode(const media_node
& node
, bigtime_t toMediaTime
,
1254 bigtime_t atPerformanceTime
)
1257 if (IS_INVALID_NODE(node
))
1258 return B_MEDIA_BAD_NODE
;
1260 TRACE("BMediaRoster::SeekNode, node %" B_PRId32
", at perf %" B_PRId64
1261 ", to perf %" B_PRId64
"\n", node
.node
, atPerformanceTime
, toMediaTime
);
1263 node_seek_command command
;
1264 command
.media_time
= toMediaTime
;
1265 command
.performance_time
= atPerformanceTime
;
1267 return SendToPort(node
.port
, NODE_SEEK
, &command
, sizeof(command
));
1272 BMediaRoster::StartTimeSource(const media_node
& node
, bigtime_t atRealTime
)
1275 if (IS_SYSTEM_TIMESOURCE(node
)) {
1277 //ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is system timesource\n", node.node);
1280 // if (IS_SHADOW_TIMESOURCE(node)) {
1281 // // TODO: debug this
1282 // ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is shadow timesource\n", node.node);
1285 if (IS_INVALID_NODE(node
)) {
1286 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32
" invalid\n",
1288 return B_MEDIA_BAD_NODE
;
1290 if ((node
.kind
& B_TIME_SOURCE
) == 0) {
1291 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32
1292 " is no timesource\n", node
.node
);
1293 return B_MEDIA_BAD_NODE
;
1296 TRACE("BMediaRoster::StartTimeSource, node %" B_PRId32
", at real %"
1297 B_PRId64
"\n", node
.node
, atRealTime
);
1299 BTimeSource::time_source_op_info msg
;
1300 msg
.op
= BTimeSource::B_TIMESOURCE_START
;
1301 msg
.real_time
= atRealTime
;
1303 return write_port(node
.port
, TIMESOURCE_OP
, &msg
, sizeof(msg
));
1308 BMediaRoster::StopTimeSource(const media_node
& node
, bigtime_t atRealTime
,
1312 if (IS_SYSTEM_TIMESOURCE(node
)) {
1314 //ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node);
1317 // if (IS_SHADOW_TIMESOURCE(node)) {
1318 // // TODO: debug this
1319 // ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node);
1322 if (IS_INVALID_NODE(node
)) {
1323 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32
" invalid\n",
1325 return B_MEDIA_BAD_NODE
;
1327 if ((node
.kind
& B_TIME_SOURCE
) == 0) {
1328 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32
" is no "
1329 "timesource\n", node
.node
);
1330 return B_MEDIA_BAD_NODE
;
1333 TRACE("BMediaRoster::StopTimeSource, node %" B_PRId32
", at real %" B_PRId64
1334 " %s\n", node
.node
, atRealTime
, immediate
? "NOW" : "");
1336 BTimeSource::time_source_op_info msg
;
1337 msg
.op
= immediate
? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY
1338 : BTimeSource::B_TIMESOURCE_STOP
;
1339 msg
.real_time
= atRealTime
;
1341 return write_port(node
.port
, TIMESOURCE_OP
, &msg
, sizeof(msg
));
1346 BMediaRoster::SeekTimeSource(const media_node
& node
,
1347 bigtime_t toPerformanceTime
, bigtime_t atRealTime
)
1350 if (IS_SYSTEM_TIMESOURCE(node
)) {
1352 // ERROR("BMediaRoster::SeekTimeSource node %ld is system timesource\n", node.node);
1353 // you can't seek the system time source, but
1354 // returning B_ERROR would break StampTV
1357 // if (IS_SHADOW_TIMESOURCE(node)) {
1358 // // TODO: debug this
1359 // ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node);
1362 if (IS_INVALID_NODE(node
)) {
1363 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32
" invalid\n",
1365 return B_MEDIA_BAD_NODE
;
1367 if ((node
.kind
& B_TIME_SOURCE
) == 0) {
1368 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32
1369 " is no timesource\n", node
.node
);
1370 return B_MEDIA_BAD_NODE
;
1373 TRACE("BMediaRoster::SeekTimeSource, node %" B_PRId32
", at real %" B_PRId64
1374 ", to perf %" B_PRId64
"\n", node
.node
, atRealTime
, toPerformanceTime
);
1376 BTimeSource::time_source_op_info msg
;
1377 msg
.op
= BTimeSource::B_TIMESOURCE_SEEK
;
1378 msg
.real_time
= atRealTime
;
1379 msg
.performance_time
= toPerformanceTime
;
1381 return write_port(node
.port
, TIMESOURCE_OP
, &msg
, sizeof(msg
));
1386 BMediaRoster::SyncToNode(const media_node
& node
, bigtime_t atTime
,
1389 TRACE("BMediaRoster::SyncToNode, node %" B_PRId32
", at real %" B_PRId64
1390 ", at timeout %" B_PRId64
"\n", node
.node
, atTime
, timeout
);
1391 if (IS_INVALID_NODE(node
))
1392 return B_MEDIA_BAD_NODE
;
1394 port_id waitPort
= create_port(1, "SyncToNode wait port");
1395 if (waitPort
< B_OK
)
1398 node_sync_to_request request
;
1399 node_sync_to_reply reply
;
1400 request
.performance_time
= atTime
;
1401 request
.port
= waitPort
;
1403 status_t status
= QueryPort(node
.port
, NODE_SYNC_TO
, &request
,
1404 sizeof(request
), &reply
, sizeof(reply
));
1406 if (status
== B_OK
) {
1407 ssize_t readSize
= read_port_etc(waitPort
, NULL
, &status
,
1408 sizeof(status
), B_TIMEOUT
, timeout
);
1412 close_port(waitPort
);
1413 delete_port(waitPort
);
1419 BMediaRoster::SetRunModeNode(const media_node
& node
, BMediaNode::run_mode mode
)
1421 TRACE("BMediaRoster::SetRunModeNode, node %" B_PRId32
", mode %d\n",
1423 if (IS_INVALID_NODE(node
))
1424 return B_MEDIA_BAD_NODE
;
1426 node_set_run_mode_command msg
;
1429 return write_port(node
.port
, NODE_SET_RUN_MODE
, &msg
, sizeof(msg
));
1434 BMediaRoster::PrerollNode(const media_node
& node
)
1437 if (IS_INVALID_NODE(node
))
1438 return B_MEDIA_BAD_NODE
;
1441 return write_port(node
.port
, NODE_PREROLL
, &dummy
, sizeof(dummy
));
1446 BMediaRoster::RollNode(const media_node
& node
, bigtime_t startPerformance
,
1447 bigtime_t stopPerformance
, bigtime_t atMediaTime
)
1450 if (IS_INVALID_NODE(node
))
1451 return B_MEDIA_BAD_NODE
;
1453 TRACE("BMediaRoster::RollNode, node %" B_PRId32
", at start perf %"
1454 B_PRId64
", at stop perf %" B_PRId64
", at media time %"
1455 B_PRId64
"\n", node
.node
, startPerformance
,
1456 stopPerformance
, atMediaTime
);
1458 node_roll_command command
;
1459 command
.start_performance_time
= startPerformance
;
1460 command
.stop_performance_time
= stopPerformance
;
1461 command
.seek_media_time
= atMediaTime
;
1463 return write_port(node
.port
, NODE_ROLL
, &command
, sizeof(command
));
1468 BMediaRoster::SetProducerRunModeDelay(const media_node
& node
,
1469 bigtime_t delay
, BMediaNode::run_mode mode
)
1471 TRACE("BMediaRoster::SetProducerRunModeDelay, node %" B_PRId32
", delay %"
1472 B_PRId64
", mode %d\n", node
.node
, delay
, mode
);
1473 if (IS_INVALID_NODE(node
))
1474 return B_MEDIA_BAD_NODE
;
1475 if ((node
.kind
& B_BUFFER_PRODUCER
) == 0)
1476 return B_MEDIA_BAD_NODE
;
1478 producer_set_run_mode_delay_command command
;
1479 command
.mode
= mode
;
1480 command
.delay
= delay
;
1482 return SendToPort(node
.port
, PRODUCER_SET_RUN_MODE_DELAY
, &command
,
1488 BMediaRoster::SetProducerRate(const media_node
& producer
, int32 numer
,
1492 if (IS_INVALID_NODE(producer
))
1493 return B_MEDIA_BAD_NODE
;
1494 if ((producer
.kind
& B_BUFFER_PRODUCER
) == 0)
1495 return B_MEDIA_BAD_NODE
;
1497 producer_set_play_rate_request request
;
1498 request
.numer
= numer
;
1499 request
.denom
= denom
;
1500 status_t status
= write_port(producer
.node
, PRODUCER_SET_PLAY_RATE
,
1501 &request
, sizeof(request
));
1505 producer_set_play_rate_reply reply
;
1507 status
= read_port(request
.reply_port
, &code
, &reply
, sizeof(reply
));
1509 return status
< B_OK
? status
: reply
.result
;
1513 /*! Nodes will have available inputs/outputs as long as they are capable
1514 of accepting more connections. The node may create an additional
1515 output or input as the currently available is taken into usage.
1518 BMediaRoster::GetLiveNodeInfo(const media_node
& node
,
1519 live_node_info
* out_live_info
)
1522 if (out_live_info
== NULL
)
1524 if (IS_INVALID_NODE(node
))
1525 return B_MEDIA_BAD_NODE
;
1527 server_get_live_node_info_request request
;
1528 server_get_live_node_info_reply reply
;
1531 request
.node
= node
;
1533 rv
= QueryServer(SERVER_GET_LIVE_NODE_INFO
, &request
, sizeof(request
),
1534 &reply
, sizeof(reply
));
1538 *out_live_info
= reply
.live_info
;
1544 BMediaRoster::GetLiveNodes(live_node_info
* liveNodes
, int32
* _totalCount
,
1545 const media_format
* hasInput
, const media_format
* hasOutput
,
1546 const char* name
, uint64 nodeKinds
)
1549 if (liveNodes
== NULL
|| _totalCount
== NULL
|| *_totalCount
<= 0)
1552 // TODO: we also support the wildcard search as GetDormantNodes does.
1553 // This needs to be documented
1555 server_get_live_nodes_request request
;
1556 request
.team
= BPrivate::current_team();
1558 request
.max_count
= *_totalCount
;
1559 request
.has_input
= hasInput
!= NULL
;
1560 if (hasInput
!= NULL
) {
1561 // TODO: we should not make a flat copy of media_format
1562 request
.input_format
= *hasInput
;
1564 request
.has_output
= hasOutput
!= NULL
;
1565 if (hasOutput
!= NULL
) {
1566 // TODO: we should not make a flat copy of media_format
1567 request
.output_format
= *hasOutput
;
1569 request
.has_name
= name
!= NULL
;
1571 strlcpy(request
.name
, name
, sizeof(request
.name
));
1572 request
.require_kinds
= nodeKinds
;
1574 server_get_live_nodes_reply reply
;
1575 status_t status
= QueryServer(SERVER_GET_LIVE_NODES
, &request
,
1576 sizeof(request
), &reply
, sizeof(reply
));
1577 if (status
!= B_OK
) {
1578 ERROR("BMediaRoster::GetLiveNodes failed querying server: %s\n",
1584 const live_node_info
* info
;
1585 if (reply
.area
>= 0)
1586 info
= (live_node_info
*)reply
.address
;
1588 info
= reply
.live_info
;
1590 for (int32 i
= 0; i
< reply
.count
; i
++)
1591 liveNodes
[i
] = info
[i
];
1593 if (reply
.area
>= 0)
1594 delete_area(reply
.area
);
1596 *_totalCount
= reply
.count
;
1602 BMediaRoster::GetFreeInputsFor(const media_node
& node
,
1603 media_input
* out_free_inputs
, int32 buf_num_inputs
,
1604 int32
* out_total_count
, media_type filter_type
)
1607 if (IS_INVALID_NODE(node
)) {
1608 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32
", port %"
1609 B_PRId32
" invalid\n", node
.node
, node
.port
);
1610 return B_MEDIA_BAD_NODE
;
1612 if ((node
.kind
& B_BUFFER_CONSUMER
) == 0) {
1613 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32
", port %"
1614 B_PRId32
" is not a consumer\n", node
.node
, node
.port
);
1615 return B_MEDIA_BAD_NODE
;
1617 if (out_free_inputs
== NULL
|| out_total_count
== NULL
)
1620 List
<media_input
> list
;
1624 *out_total_count
= 0;
1626 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1630 PRINT(4, "BMediaRoster::GetFreeInputsFor node %" B_PRId32
", max %" B_PRId32
1631 ", filter-type %" B_PRId32
"\n", node
.node
, buf_num_inputs
,
1635 for (i
= 0, list
.Rewind(); list
.GetNext(&input
);) {
1636 if (filter_type
!= B_MEDIA_UNKNOWN_TYPE
1637 && filter_type
!= input
->format
.type
) {
1638 // media_type used, but doesn't match
1641 if (input
->source
!= media_source::null
) {
1642 // consumer source already connected
1646 out_free_inputs
[i
] = *input
;
1647 *out_total_count
+= 1;
1648 buf_num_inputs
-= 1;
1650 PRINT_OUTPUT(" input", out_free_inputs
[i
]);
1652 if (buf_num_inputs
== 0)
1657 MediaRosterEx(this)->PublishInputs(node
, &list
);
1663 BMediaRoster::GetConnectedInputsFor(const media_node
& node
,
1664 media_input
* out_active_inputs
, int32 buf_num_inputs
,
1665 int32
* out_total_count
)
1668 if (IS_INVALID_NODE(node
) || (node
.kind
& B_BUFFER_CONSUMER
) == 0)
1669 return B_MEDIA_BAD_NODE
;
1670 if (out_active_inputs
== NULL
|| out_total_count
== NULL
)
1673 List
<media_input
> list
;
1677 *out_total_count
= 0;
1679 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1683 PRINT(4, "BMediaRoster::GetConnectedInputsFor node %" B_PRId32
", max %"
1684 B_PRId32
"\n", node
.node
, buf_num_inputs
);
1687 for (i
= 0, list
.Rewind(); list
.GetNext(&input
);) {
1688 if (input
->source
== media_source::null
)
1689 continue; // consumer source not connected
1690 out_active_inputs
[i
] = *input
;
1691 *out_total_count
+= 1;
1692 buf_num_inputs
-= 1;
1694 PRINT_OUTPUT(" input ", out_active_inputs
[i
]);
1696 if (buf_num_inputs
== 0)
1701 MediaRosterEx(this)->PublishInputs(node
, &list
);
1707 BMediaRoster::GetAllInputsFor(const media_node
& node
, media_input
* out_inputs
,
1708 int32 buf_num_inputs
, int32
* out_total_count
)
1711 if (IS_INVALID_NODE(node
) || (node
.kind
& B_BUFFER_CONSUMER
) == 0)
1712 return B_MEDIA_BAD_NODE
;
1713 if (out_inputs
== NULL
|| out_total_count
== NULL
)
1716 List
<media_input
> list
;
1720 *out_total_count
= 0;
1722 rv
= MediaRosterEx(this)->GetAllInputs(node
, &list
);
1726 PRINT(4, "BMediaRoster::GetAllInputsFor node %" B_PRId32
", max %" B_PRId32
1727 "\n", node
.node
, buf_num_inputs
);
1730 for (i
= 0, list
.Rewind(); list
.GetNext(&input
); i
++) {
1731 out_inputs
[i
] = *input
;
1732 *out_total_count
+= 1;
1733 buf_num_inputs
-= 1;
1735 PRINT_OUTPUT(" input ", out_inputs
[i
]);
1737 if (buf_num_inputs
== 0)
1741 MediaRosterEx(this)->PublishInputs(node
, &list
);
1747 BMediaRoster::GetFreeOutputsFor(const media_node
& node
,
1748 media_output
* out_free_outputs
, int32 buf_num_outputs
,
1749 int32
* out_total_count
, media_type filter_type
)
1752 if (IS_INVALID_NODE(node
) || (node
.kind
& B_BUFFER_PRODUCER
) == 0)
1753 return B_MEDIA_BAD_NODE
;
1754 if (out_free_outputs
== NULL
|| out_total_count
== NULL
)
1757 List
<media_output
> list
;
1758 media_output
*output
;
1761 *out_total_count
= 0;
1763 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1767 PRINT(4, "BMediaRoster::GetFreeOutputsFor node %" B_PRId32
", max %"
1768 B_PRId32
", filter-type %" B_PRId32
"\n", node
.node
, buf_num_outputs
,
1772 for (i
= 0, list
.Rewind(); list
.GetNext(&output
);) {
1773 if (filter_type
!= B_MEDIA_UNKNOWN_TYPE
1774 && filter_type
!= output
->format
.type
) {
1775 // media_type used, but doesn't match
1778 if (output
->destination
!= media_destination::null
) {
1779 // producer destination already connected
1783 out_free_outputs
[i
] = *output
;
1784 *out_total_count
+= 1;
1785 buf_num_outputs
-= 1;
1787 PRINT_OUTPUT(" output ", out_free_outputs
[i
]);
1789 if (buf_num_outputs
== 0)
1794 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1800 BMediaRoster::GetConnectedOutputsFor(const media_node
& node
,
1801 media_output
* out_active_outputs
, int32 buf_num_outputs
,
1802 int32
* out_total_count
)
1805 if (IS_INVALID_NODE(node
) || (node
.kind
& B_BUFFER_PRODUCER
) == 0)
1806 return B_MEDIA_BAD_NODE
;
1807 if (out_active_outputs
== NULL
|| out_total_count
== NULL
)
1810 List
<media_output
> list
;
1811 media_output
*output
;
1814 *out_total_count
= 0;
1816 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1820 PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %" B_PRId32
", max %"
1821 B_PRId32
"\n", node
.node
, buf_num_outputs
);
1824 for (i
= 0, list
.Rewind(); list
.GetNext(&output
);) {
1825 if (output
->destination
== media_destination::null
) {
1826 // producer destination not connected
1829 out_active_outputs
[i
] = *output
;
1830 *out_total_count
+= 1;
1831 buf_num_outputs
-= 1;
1833 PRINT_OUTPUT(" output ", out_active_outputs
[i
]);
1835 if (buf_num_outputs
== 0)
1840 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1846 BMediaRoster::GetAllOutputsFor(const media_node
& node
,
1847 media_output
* out_outputs
, int32 buf_num_outputs
, int32
* out_total_count
)
1850 if (IS_INVALID_NODE(node
) || (node
.kind
& B_BUFFER_PRODUCER
) == 0)
1851 return B_MEDIA_BAD_NODE
;
1852 if (out_outputs
== NULL
|| out_total_count
== NULL
)
1855 List
<media_output
> list
;
1856 media_output
*output
;
1859 *out_total_count
= 0;
1861 rv
= MediaRosterEx(this)->GetAllOutputs(node
, &list
);
1865 PRINT(4, "BMediaRoster::GetAllOutputsFor node %" B_PRId32
", max %" B_PRId32
1866 "\n", node
.node
, buf_num_outputs
);
1869 for (i
= 0, list
.Rewind(); list
.GetNext(&output
); i
++) {
1870 out_outputs
[i
] = *output
;
1871 *out_total_count
+= 1;
1872 buf_num_outputs
-= 1;
1874 PRINT_OUTPUT(" output ", out_outputs
[i
]);
1876 if (buf_num_outputs
== 0)
1880 MediaRosterEx(this)->PublishOutputs(node
, &list
);
1886 BMediaRoster::StartWatching(const BMessenger
& where
)
1889 if (!where
.IsValid()) {
1890 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1893 return BPrivate::media::notifications::Register(where
, media_node::null
,
1899 BMediaRoster::StartWatching(const BMessenger
& where
, int32 notificationType
)
1902 if (!where
.IsValid()) {
1903 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1906 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
1907 notificationType
)) {
1908 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1912 // NOTE: we support only explicitly B_MEDIA_SERVER_STARTED/QUIT
1913 // notifications. This should be cleared in documentation.
1915 return BPrivate::media::notifications::Register(where
, media_node::null
,
1921 BMediaRoster::StartWatching(const BMessenger
& where
, const media_node
& node
,
1922 int32 notificationType
)
1925 if (!where
.IsValid()) {
1926 ERROR("BMediaRoster::StartWatching: messenger invalid!\n");
1929 if (IS_INVALID_NODE(node
)) {
1930 ERROR("BMediaRoster::StartWatching: node invalid!\n");
1931 return B_MEDIA_BAD_NODE
;
1933 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
1934 notificationType
)) {
1935 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n");
1938 return BPrivate::media::notifications::Register(where
, node
,
1944 BMediaRoster::StopWatching(const BMessenger
& where
)
1947 // messenger may already be invalid, so we don't check this
1948 return BPrivate::media::notifications::Unregister(where
, media_node::null
,
1954 BMediaRoster::StopWatching(const BMessenger
& where
, int32 notificationType
)
1957 // messenger may already be invalid, so we don't check this
1958 if (!BPrivate::media::notifications::IsValidNotificationRequest(false,
1959 notificationType
)) {
1960 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1963 return BPrivate::media::notifications::Unregister(where
, media_node::null
,
1969 BMediaRoster::StopWatching(const BMessenger
& where
, const media_node
& node
,
1970 int32 notificationType
)
1973 // messenger may already be invalid, so we don't check this
1974 if (IS_INVALID_NODE(node
)) {
1975 ERROR("BMediaRoster::StopWatching: node invalid!\n");
1976 return B_MEDIA_BAD_NODE
;
1978 if (!BPrivate::media::notifications::IsValidNotificationRequest(true,
1979 notificationType
)) {
1980 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n");
1983 return BPrivate::media::notifications::Unregister(where
, node
,
1989 BMediaRoster::RegisterNode(BMediaNode
* node
)
1992 // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too)
1993 return MediaRosterEx(this)->RegisterNode(node
, -1, 0);
1998 BMediaRosterEx::RegisterNode(BMediaNode
* node
, media_addon_id addOnID
,
2005 // some sanity check
2006 // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here.
2007 // Perhaps we don't need it.
2010 BMediaAddOn
* addon
= node
->AddOn(&testFlavorID
);
2012 ASSERT(addOnID
== (addon
!= NULL
? addon
->AddonID() : -1));
2013 // ASSERT(flavorID == testFlavorID);
2016 server_register_node_request request
;
2017 server_register_node_reply reply
;
2019 request
.add_on_id
= addOnID
;
2020 request
.flavor_id
= flavorID
;
2021 strcpy(request
.name
, node
->Name());
2022 request
.kinds
= node
->Kinds();
2023 request
.port
= node
->ControlPort();
2024 request
.team
= BPrivate::current_team();
2025 request
.timesource_id
= node
->fTimeSourceID
;
2027 TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port "
2028 "%" B_PRId32
", kinds 0x%" B_PRIx64
", team %" B_PRId32
", name '%s'\n",
2029 request
.port
, request
.kinds
, request
.team
, request
.name
);
2031 status_t status
= QueryServer(SERVER_REGISTER_NODE
, &request
,
2032 sizeof(request
), &reply
, sizeof(reply
));
2033 if (status
!= B_OK
) {
2034 ERROR("BMediaRoster::RegisterNode: failed to register node %s: %s\n",
2035 node
->Name(), strerror(status
));
2039 TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE "
2042 // we are a friend class of BMediaNode and initialize this member variable
2043 node
->fNodeID
= reply
.node_id
;
2044 ASSERT(reply
.node_id
== node
->Node().node
);
2045 ASSERT(reply
.node_id
== node
->ID());
2047 // call the callback
2048 node
->NodeRegistered();
2050 TRACE("BMediaRoster::RegisterNode: NodeRegistered callback finished\n");
2052 // if the BMediaNode also inherits from BTimeSource, we need to call
2053 // BTimeSource::FinishCreate()
2054 if ((node
->Kinds() & B_TIME_SOURCE
) != 0) {
2055 if (BTimeSource
* timeSource
= dynamic_cast<BTimeSource
*>(node
))
2056 timeSource
->FinishCreate();
2059 TRACE("BMediaRoster::RegisterNode: publishing inputs/outputs\n");
2061 // register existing inputs and outputs with the
2062 // media_server, this allows GetLiveNodes() to work
2063 // with created, but unconnected nodes.
2064 // The node control loop might not be running, or might deadlock
2065 // if we send a message and wait for a reply here.
2066 // We have a pointer to the node, and thus call the functions directly
2068 if ((node
->Kinds() & B_BUFFER_PRODUCER
) != 0) {
2069 if (BBufferProducer
* producer
= dynamic_cast<BBufferProducer
*>(node
)) {
2070 List
<media_output
> list
;
2071 if (GetAllOutputs(producer
, &list
) == B_OK
)
2072 PublishOutputs(node
->Node(), &list
);
2075 if ((node
->Kinds() & B_BUFFER_CONSUMER
) != 0) {
2076 if (BBufferConsumer
* consumer
= dynamic_cast<BBufferConsumer
*>(node
)) {
2077 List
<media_input
> list
;
2078 if (GetAllInputs(consumer
, &list
) == B_OK
)
2079 PublishInputs(node
->Node(), &list
);
2083 TRACE("BMediaRoster::RegisterNode: sending NodesCreated\n");
2085 BPrivate::media::notifications::NodesCreated(&reply
.node_id
, 1);
2087 TRACE("BMediaRoster::RegisterNode: finished\n");
2090 TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld,
2091 addon %ld, flavor %ld\n", node->Name(), node->ID(), addOnID, flavorID);
2092 TRACE("BMediaRoster::RegisterNode: node this %p\n", node);
2093 TRACE("BMediaRoster::RegisterNode: node fConsumerThis %p\n",
2094 node->fConsumerThis);
2095 TRACE("BMediaRoster::RegisterNode: node fProducerThis %p\n",
2096 node->fProducerThis);
2097 TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n",
2098 node->fFileInterfaceThis);
2099 TRACE("BMediaRoster::RegisterNode: node fControllableThis %p\n",
2100 node->fControllableThis);
2101 TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis %p\n",
2102 node->fTimeSourceThis);
2109 BMediaRoster::UnregisterNode(BMediaNode
* node
)
2115 TRACE("BMediaRoster::UnregisterNode %ld (%p)\n", node
->ID(), node
);
2117 if ((node
->fKinds
& NODE_KIND_NO_REFCOUNTING
) !=0) {
2118 TRACE("BMediaRoster::UnregisterNode, trying to unregister reference "
2119 "counting disabled timesource, node %ld, port %ld, team %ld\n",
2120 node
->ID(), node
->ControlPort(), BPrivate::current_team());
2123 if (node
->ID() == NODE_UNREGISTERED_ID
) {
2124 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2125 "'%s' already unregistered\n", node
->ID(), node
->Name());
2128 if (node
->fRefCount
!= 0) {
2129 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name "
2130 "'%s' has local reference count of %ld\n", node
->ID(), node
->Name(),
2132 // no return here, we continue and unregister!
2135 // Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node,
2136 // BMessage *config) if this node was instanciated by an add-on needs to
2137 // be done *somewhere*
2138 // We can't do it here because it is already to late (destructor of the node
2139 // might have been called).
2141 server_unregister_node_request request
;
2142 request
.node_id
= node
->ID();
2143 request
.team
= BPrivate::current_team();
2145 // send a notification
2146 BPrivate::media::notifications::NodesDeleted(&request
.node_id
, 1);
2148 server_unregister_node_reply reply
;
2149 reply
.add_on_id
= -1;
2150 status_t status
= QueryServer(SERVER_UNREGISTER_NODE
, &request
,
2151 sizeof(request
), &reply
, sizeof(reply
));
2152 if (status
!= B_OK
) {
2153 ERROR("BMediaRoster::UnregisterNode: failed to unregister node id %"
2154 B_PRId32
", name '%s': %s\n", node
->ID(), node
->Name(),
2156 BMediaAddOn
*addon
= node
->AddOn(&reply
.flavor_id
);
2158 reply
.add_on_id
= addon
->AddonID();
2161 if (reply
.add_on_id
!= -1) {
2162 // TODO: this doesn't look right
2163 // Small problem here, we can't use DormantNodeManager::PutAddOn(), as
2164 // UnregisterNode() is called by a dormant node itself (by the
2166 // The add-on that contains the node needs to remain in memory until the
2167 // destructor execution is finished.
2168 // DormantNodeManager::PutAddOnDelayed() will delay unloading.
2169 gDormantNodeManager
->PutAddOnDelayed(reply
.add_on_id
);
2171 status
= MediaRosterEx(this)->DecrementAddonFlavorInstancesCount(
2172 reply
.add_on_id
, reply
.flavor_id
);
2173 if (status
!= B_OK
) {
2174 ERROR("BMediaRoster::UnregisterNode: "
2175 "DecrementAddonFlavorInstancesCount() failed\n");
2176 // this is really a problem, but we can't fail now
2180 // we are a friend class of BMediaNode and invalidate this member variable
2181 node
->fNodeID
= NODE_UNREGISTERED_ID
;
2187 //! Thread safe for multiple calls to Roster()
2188 /*static*/ BMediaRoster
*
2189 BMediaRoster::Roster(status_t
* out_error
)
2191 static BLocker
locker("BMediaRoster::Roster locker");
2195 if (sDefaultInstance
== NULL
) {
2197 sDefaultInstance
= new (std::nothrow
) BMediaRosterEx(&err
);
2198 if (sDefaultInstance
== NULL
)
2200 else if (err
!= B_OK
) {
2201 if (sDefaultInstance
) {
2202 sDefaultInstance
->Lock();
2203 sDefaultInstance
->Quit();
2204 sDefaultInstance
= NULL
;
2211 return sDefaultInstance
;
2215 /*static*/ BMediaRoster
*
2216 BMediaRoster::CurrentRoster()
2218 return sDefaultInstance
;
2223 BMediaRoster::SetTimeSourceFor(media_node_id node
, media_node_id time_source
)
2226 if (IS_INVALID_NODEID(node
) || IS_INVALID_NODEID(time_source
))
2230 // We need to get a clone of the node to have a port id
2231 status_t result
= GetNodeFor(node
, &clone
);
2232 if (result
== B_OK
) {
2233 // We just send the request to set time_source-id as
2234 // timesource to the node, the NODE_SET_TIMESOURCE handler
2235 // code will do the real assignment.
2237 node_set_timesource_command cmd
;
2238 cmd
.timesource_id
= time_source
;
2239 result
= SendToPort(clone
.port
, NODE_SET_TIMESOURCE
,
2241 if (result
!= B_OK
) {
2242 ERROR("BMediaRoster::SetTimeSourceFor"
2243 "sending NODE_SET_TIMESOURCE failed, node id %"
2244 B_PRId32
"\n", clone
.node
);
2246 // We release the clone
2247 result
= ReleaseNode(clone
);
2248 if (result
!= B_OK
) {
2249 ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed,"
2250 " node id %" B_PRId32
"\n", clone
.node
);
2253 ERROR("BMediaRoster::SetTimeSourceFor GetCloneForID failed, "
2254 "node id %" B_PRId32
"\n", node
);
2257 if (result
== B_OK
) {
2258 // Notify the server
2259 server_set_node_timesource_request request
;
2260 server_set_node_timesource_reply reply
;
2262 request
.node_id
= node
;
2263 request
.timesource_id
= time_source
;
2265 result
= QueryServer(SERVER_SET_NODE_TIMESOURCE
, &request
,
2266 sizeof(request
), &reply
, sizeof(reply
));
2267 if (result
!= B_OK
) {
2268 ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE "
2269 "failed, node id %" B_PRId32
"\n", node
);
2271 TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32
" time source %"
2272 B_PRId32
" OK\n", node
, time_source
);
2280 BMediaRoster::GetParameterWebFor(const media_node
& node
, BParameterWeb
** _web
)
2285 if (IS_INVALID_NODE(node
))
2286 return B_MEDIA_BAD_NODE
;
2287 if ((node
.kind
& B_CONTROLLABLE
) == 0)
2288 return B_MEDIA_BAD_NODE
;
2290 controllable_get_parameter_web_request request
;
2291 controllable_get_parameter_web_reply reply
;
2292 int32 requestsize
[] = {B_PAGE_SIZE
, 4 * B_PAGE_SIZE
, 16 * B_PAGE_SIZE
,
2293 64 * B_PAGE_SIZE
, 128 * B_PAGE_SIZE
, 256 * B_PAGE_SIZE
, 0};
2296 // TODO: it might be better to query the node for the (current) parameter
2298 for (int i
= 0; (size
= requestsize
[i
]) != 0; i
++) {
2302 area
= create_area("parameter web data", &data
, B_ANY_ADDRESS
, size
,
2303 B_NO_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
2305 ERROR("BMediaRoster::GetParameterWebFor couldn't create area of "
2306 "size %" B_PRId32
"\n", size
);
2309 request
.max_size
= size
;
2310 request
.area
= area
;
2311 rv
= QueryPort(node
.port
, CONTROLLABLE_GET_PARAMETER_WEB
, &request
,
2312 sizeof(request
), &reply
, sizeof(reply
));
2314 ERROR("BMediaRoster::GetParameterWebFor "
2315 "CONTROLLABLE_GET_PARAMETER_WEB failed\n");
2319 if (reply
.size
== 0) {
2320 // no parameter web available
2321 // TODO: should we return an error?
2322 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32
2323 " has no parameter web\n", node
.node
);
2324 *_web
= new (std::nothrow
) BParameterWeb();
2326 return *_web
!= NULL
? B_OK
: B_NO_MEMORY
;
2328 if (reply
.size
> 0) {
2329 // we got a flattened parameter web!
2330 BParameterWeb
* web
= new (std::nothrow
) BParameterWeb();
2334 rv
= web
->Unflatten(reply
.code
, data
, reply
.size
);
2336 ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, "
2337 "%s\n", strerror(rv
));
2347 ASSERT(reply
.size
== -1);
2348 // parameter web data was too large
2349 // loop and try a larger size
2351 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32
" has no "
2352 "parameter web larger than %" B_PRId32
"\n", node
.node
, size
);
2358 BMediaRoster::StartControlPanel(const media_node
& node
, BMessenger
* _messenger
)
2362 controllable_start_control_panel_request request
;
2363 controllable_start_control_panel_reply reply
;
2365 request
.node
= node
;
2368 rv
= QueryPort(node
.port
, CONTROLLABLE_START_CONTROL_PANEL
, &request
,
2369 sizeof(request
), &reply
, sizeof(reply
));
2373 if (reply
.team
!= -1 && _messenger
!= NULL
)
2374 *_messenger
= BMessenger(NULL
, reply
.team
);
2381 BMediaRoster::GetDormantNodes(dormant_node_info
* _info
, int32
* _count
,
2382 const media_format
* hasInput
, const media_format
* hasOutput
,
2383 const char* name
, uint64 requireKinds
, uint64 denyKinds
)
2386 if (_info
== NULL
|| _count
== NULL
|| *_count
<= 0)
2389 server_get_dormant_nodes_request request
;
2390 request
.max_count
= *_count
;
2391 request
.has_input
= hasInput
!= NULL
;
2392 if (hasInput
!= NULL
) {
2393 // TODO: we should not make a flat copy of media_format
2394 request
.input_format
= *hasInput
;
2396 request
.has_output
= hasOutput
!= NULL
;
2397 if (hasOutput
!= NULL
) {
2398 // TODO: we should not make a flat copy of media_format
2399 request
.output_format
= *hasOutput
;
2402 request
.has_name
= name
!= NULL
;
2404 strlcpy(request
.name
, name
, sizeof(request
.name
));
2406 request
.require_kinds
= requireKinds
;
2407 request
.deny_kinds
= denyKinds
;
2409 server_get_dormant_nodes_reply reply
;
2410 status_t status
= QueryServer(SERVER_GET_DORMANT_NODES
, &request
,
2411 sizeof(request
), &reply
, sizeof(reply
));
2415 *_count
= reply
.count
;
2417 if (reply
.count
> 0) {
2419 status
= read_port(request
.reply_port
, &code
, _info
,
2420 reply
.count
* sizeof(dormant_node_info
));
2422 reply
.result
= status
;
2425 return reply
.result
;
2429 /*! This function is used to do the real work of instantiating a dormant node.
2430 It is either called by the media_addon_server to instantiate a global node,
2431 or it gets called from BMediaRoster::InstantiateDormantNode() to create a
2434 Checks concerning global/local are not done here.
2437 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonID
, int32 flavorID
,
2438 team_id creator
, media_node
*_node
)
2440 // This function is always called from the correct context, if the node
2441 // is supposed to be global, it is called from the media_addon_server.
2443 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
2444 // resides in the media_addon_server
2446 // RegisterNode() must be called for nodes instantiated from add-ons,
2447 // since the media kit warrants that it's done automatically.
2449 // addonID Indicates the ID number of the media add-on in which the
2451 // flavorID Indicates the internal ID number that the add-on uses to
2452 // identify the flavor, this is the number that was published
2453 // by BMediaAddOn::GetFlavorAt() in the
2454 // flavor_info::internal_id field.
2455 // creator The creator team is -1 if nodes are created locally. If
2456 // created globally, it will contain (while called in
2457 // media_addon_server context) the team-id of the team that
2458 // requested the instantiation.
2460 TRACE("BMediaRosterEx::InstantiateDormantNode: addonID %" B_PRId32
2461 ", flavorID %" B_PRId32
"\n", addonID
, flavorID
);
2463 // Get flavor_info from the server
2464 dormant_flavor_info info
;
2466 rv
= GetDormantFlavorInfo(addonID
, flavorID
, &info
);
2468 ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get "
2469 "dormant_flavor_info for addon-id %" B_PRId32
", flavor-id %"
2470 B_PRId32
"\n", addonID
, flavorID
);
2474 ASSERT(info
.internal_id
== flavorID
);
2476 // load the BMediaAddOn object
2477 BMediaAddOn
* addon
= gDormantNodeManager
->GetAddOn(addonID
);
2478 if (addon
== NULL
) {
2479 ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n");
2483 // Now we need to try to increment the use count of this addon flavor
2484 // in the server. This can fail if the total number instances of this
2485 // flavor is limited.
2486 rv
= IncrementAddonFlavorInstancesCount(addonID
, flavorID
);
2488 ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create "
2489 "more nodes for addon-id %" B_PRId32
", flavor-id %" B_PRId32
"\n",
2491 // Put the addon back into the pool
2492 gDormantNodeManager
->PutAddOn(addonID
);
2497 rv
= LoadNodeConfiguration(addonID
, flavorID
, &config
);
2499 ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load "
2500 "configuration for addon-id %" B_PRId32
", flavor-id %" B_PRId32
2501 "\n", addonID
, flavorID
);
2502 // do not return, this is a minor problem, not a reason to fail
2505 status_t status
= B_OK
;
2506 BMediaNode
* node
= addon
->InstantiateNodeFor(&info
, &config
, &status
);
2508 ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor "
2511 // Put the addon back into the pool
2512 gDormantNodeManager
->PutAddOn(addonID
);
2514 // We must decrement the use count of this addon flavor in the
2515 // server to compensate the increment done in the beginning.
2516 rv
= DecrementAddonFlavorInstancesCount(addonID
, flavorID
);
2518 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2519 "FlavorInstancesCount failed\n");
2521 return status
!= B_OK
? status
: B_ERROR
;
2524 rv
= RegisterNode(node
, addonID
, flavorID
);
2526 ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
2528 // Put the addon back into the pool
2529 gDormantNodeManager
->PutAddOn(addonID
);
2530 // We must decrement the use count of this addon flavor in the
2531 // server to compensate the increment done in the beginning.
2532 rv
= DecrementAddonFlavorInstancesCount(addonID
, flavorID
);
2534 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon"
2535 "FlavorInstancesCount failed\n");
2540 if (creator
!= -1) {
2541 // send a message to the server to assign team "creator" as creator
2542 // of node "node->ID()"
2543 printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %"
2544 B_PRId32
" as creator of node %" B_PRId32
"\n", creator
,
2547 rv
= MediaRosterEx(this)->SetNodeCreator(node
->ID(), creator
);
2549 ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign "
2550 "team %" B_PRId32
" as creator of node %" B_PRId32
"\n",
2551 creator
, node
->ID());
2552 // do not return, this is a minor problem, not a reason to fail
2556 // RegisterNode() does remember the add-on id in the server
2557 // and UnregisterNode() will call DormantNodeManager::PutAddon()
2558 // when the node is unregistered.
2560 *_node
= node
->Node();
2562 TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %" B_PRId32
2563 ", flavor_id %" B_PRId32
" instanciated as node %" B_PRId32
", port %"
2564 B_PRId32
" in team %" B_PRId32
"\n", addonID
, flavorID
, _node
->node
,
2565 _node
->port
, BPrivate::current_team());
2572 BMediaRoster::InstantiateDormantNode(const dormant_node_info
& info
,
2573 media_node
* _node
, uint32 flags
)
2578 if (info
.addon
<= B_OK
) {
2579 ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32
2580 " invalid.\n", info
.addon
);
2584 printf("BMediaRoster::InstantiateDormantNode: addon-id %" B_PRId32
2585 ", flavor_id %" B_PRId32
", flags 0x%" B_PRIx32
"\n", info
.addon
,
2586 info
.flavor_id
, flags
);
2588 // Get flavor_info from the server
2589 // TODO: this is a little overhead, as we get the full blown
2590 // dormant_flavor_info,
2591 // TODO: but only need the flags.
2592 dormant_flavor_info flavorInfo
;
2594 rv
= MediaRosterEx(this)->GetDormantFlavorInfo(info
.addon
, info
.flavor_id
,
2597 ERROR("BMediaRoster::InstantiateDormantNode: failed to get "
2598 "dormant_flavor_info for addon-id %" B_PRId32
", flavor-id %"
2599 B_PRId32
"\n", info
.addon
, info
.flavor_id
);
2600 return B_NAME_NOT_FOUND
;
2603 ASSERT(flavorInfo
.internal_id
== info
.flavor_id
);
2606 printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", "
2607 "flavor_flags 0x%" B_PRIx32
", internal_id %" B_PRId32
2608 ", possible_count %" B_PRId32
"\n", flavorInfo
.name
, flavorInfo
.info
,
2609 flavorInfo
.flavor_flags
, flavorInfo
.internal_id
,
2610 flavorInfo
.possible_count
);
2612 if ((flags
& B_FLAVOR_IS_LOCAL
) != 0) {
2613 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2614 "B_FLAVOR_IS_LOCAL\n");
2616 if ((flags
& B_FLAVOR_IS_GLOBAL
) != 0) {
2617 printf("BMediaRoster::InstantiateDormantNode: caller requested "
2618 "B_FLAVOR_IS_GLOBAL\n");
2620 if ((flavorInfo
.flavor_flags
& B_FLAVOR_IS_LOCAL
) != 0) {
2621 printf("BMediaRoster::InstantiateDormantNode: node requires "
2622 "B_FLAVOR_IS_LOCAL\n");
2624 if ((flavorInfo
.flavor_flags
& B_FLAVOR_IS_GLOBAL
) != 0) {
2625 printf("BMediaRoster::InstantiateDormantNode: node requires "
2626 "B_FLAVOR_IS_GLOBAL\n");
2630 // Make sure that flags demanded by the dormant node and those requested
2631 // by the caller are not incompatible.
2632 if ((flavorInfo
.flavor_flags
& B_FLAVOR_IS_GLOBAL
) != 0
2633 && (flags
& B_FLAVOR_IS_LOCAL
) != 0) {
2634 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2635 "B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n");
2636 return B_NAME_NOT_FOUND
;
2638 if ((flavorInfo
.flavor_flags
& B_FLAVOR_IS_LOCAL
) != 0
2639 && (flags
& B_FLAVOR_IS_GLOBAL
) != 0) {
2640 ERROR("BMediaRoster::InstantiateDormantNode: requested "
2641 "B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
2642 return B_NAME_NOT_FOUND
;
2645 // If either the node, or the caller requested to make the instance global
2646 // we will do it by forwarding this request into the media_addon_server,
2647 // which in turn will call BMediaRosterEx::InstantiateDormantNode to create
2648 // the node there and make it globally available.
2649 if ((flavorInfo
.flavor_flags
& B_FLAVOR_IS_GLOBAL
) != 0
2650 || (flags
& B_FLAVOR_IS_GLOBAL
) != 0) {
2651 TRACE("BMediaRoster::InstantiateDormantNode: creating global object "
2652 "in media_addon_server\n");
2654 add_on_server_instantiate_dormant_node_request request
;
2655 add_on_server_instantiate_dormant_node_reply reply
;
2656 request
.add_on_id
= info
.addon
;
2657 request
.flavor_id
= info
.flavor_id
;
2658 request
.creator_team
= BPrivate::current_team();
2659 // creator team is allowed to also release global nodes
2660 rv
= QueryAddOnServer(ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE
, &request
,
2661 sizeof(request
), &reply
, sizeof(reply
));
2663 *_node
= reply
.node
;
2665 // creator team = -1, as this is a local node
2666 rv
= MediaRosterEx(this)->InstantiateDormantNode(info
.addon
,
2667 info
.flavor_id
, -1, _node
);
2670 *_node
= media_node::null
;
2671 return B_NAME_NOT_FOUND
;
2678 BMediaRoster::InstantiateDormantNode(const dormant_node_info
& info
,
2681 return InstantiateDormantNode(info
, _node
, 0);
2686 BMediaRoster::GetDormantNodeFor(const media_node
& node
,
2687 dormant_node_info
* _info
)
2692 if (IS_INVALID_NODE(node
))
2693 return B_MEDIA_BAD_NODE
;
2695 server_get_dormant_node_for_request request
;
2696 server_get_dormant_node_for_reply reply
;
2699 request
.node
= node
;
2701 rv
= QueryServer(SERVER_GET_DORMANT_NODE_FOR
, &request
, sizeof(request
),
2702 &reply
, sizeof(reply
));
2706 *_info
= reply
.node_info
;
2712 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID
, int32 flavorID
,
2713 dormant_flavor_info
* _flavor
)
2716 if (_flavor
== NULL
)
2719 // TODO: better use an area here as well!
2721 server_get_dormant_flavor_info_reply
* reply
2722 = (server_get_dormant_flavor_info_reply
*)malloc(16300);
2726 server_get_dormant_flavor_info_request request
;
2727 request
.add_on_id
= addonID
;
2728 request
.flavor_id
= flavorID
;
2730 status_t status
= QueryServer(SERVER_GET_DORMANT_FLAVOR_INFO
, &request
,
2731 sizeof(request
), reply
, 16300);
2732 if (status
!= B_OK
) {
2737 if (reply
->result
== B_OK
) {
2738 status
= _flavor
->Unflatten(reply
->type
, &reply
->flattened_data
,
2739 reply
->flattened_size
);
2741 status
= reply
->result
;
2749 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info
& dormant
,
2750 dormant_flavor_info
* _flavor
)
2752 return MediaRosterEx(this)->GetDormantFlavorInfo(dormant
.addon
,
2753 dormant
.flavor_id
, _flavor
);
2757 // Reports in outLatency the maximum latency found downstream from
2758 // the specified BBufferProducer, producer, given the current connections.
2760 BMediaRoster::GetLatencyFor(const media_node
& producer
, bigtime_t
* _latency
)
2763 if (_latency
== NULL
)
2765 if (IS_INVALID_NODE(producer
)
2766 || (producer
.kind
& B_BUFFER_PRODUCER
) == 0)
2767 return B_MEDIA_BAD_NODE
;
2769 producer_get_latency_request request
;
2770 producer_get_latency_reply reply
;
2773 rv
= QueryPort(producer
.port
, PRODUCER_GET_LATENCY
, &request
,
2774 sizeof(request
), &reply
, sizeof(reply
));
2778 *_latency
= reply
.latency
;
2780 // printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency);
2786 BMediaRoster::GetInitialLatencyFor(const media_node
& producer
,
2787 bigtime_t
* _latency
, uint32
* _flags
)
2790 if (_latency
== NULL
)
2792 if (IS_INVALID_NODE(producer
)
2793 || (producer
.kind
& B_BUFFER_PRODUCER
) == 0)
2794 return B_MEDIA_BAD_NODE
;
2796 producer_get_initial_latency_request request
;
2797 producer_get_initial_latency_reply reply
;
2800 rv
= QueryPort(producer
.port
, PRODUCER_GET_INITIAL_LATENCY
, &request
,
2801 sizeof(request
), &reply
, sizeof(reply
));
2805 *_latency
= reply
.initial_latency
;
2807 *_flags
= reply
.flags
;
2809 TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32
" has "
2810 "maximum initial latency %" B_PRId64
"\n", producer
.node
, *_latency
);
2816 BMediaRoster::GetStartLatencyFor(const media_node
& timeSource
,
2817 bigtime_t
* _latency
)
2820 if (_latency
== NULL
)
2822 if (IS_INVALID_NODE(timeSource
)
2823 || (timeSource
.kind
& B_TIME_SOURCE
) == 0)
2824 return B_MEDIA_BAD_NODE
;
2826 timesource_get_start_latency_request request
;
2827 timesource_get_start_latency_reply reply
;
2830 rv
= QueryPort(timeSource
.port
, TIMESOURCE_GET_START_LATENCY
, &request
,
2831 sizeof(request
), &reply
, sizeof(reply
));
2835 *_latency
= reply
.start_latency
;
2837 TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32
" has "
2838 "maximum initial latency %" B_PRId64
"\n", timeSource
.node
, *_latency
);
2844 BMediaRoster::GetFileFormatsFor(const media_node
& fileInterface
,
2845 media_file_format
* _formats
, int32
* _numFormats
)
2849 if (IS_INVALID_NODE(fileInterface
)
2850 || (fileInterface
.kind
& B_FILE_INTERFACE
) == 0)
2851 return B_MEDIA_BAD_NODE
;
2853 if (_numFormats
== NULL
|| *_numFormats
< 1)
2856 fileinterface_get_formats_request request
;
2857 fileinterface_get_formats_reply reply
;
2859 media_file_format
* formats
;
2860 size_t needSize
= sizeof(media_file_format
) * *_numFormats
;
2861 size_t size
= (needSize
+ (B_PAGE_SIZE
- 1)) & ~(B_PAGE_SIZE
- 1);
2863 area_id area
= create_area("formats area", (void**)&formats
,
2864 B_ANY_ADDRESS
, size
, B_NO_LOCK
,
2865 B_READ_AREA
| B_WRITE_AREA
);
2870 request
.num_formats
= *_numFormats
;
2871 request
.data_area
= area
;
2873 status_t status
= QueryPort(fileInterface
.port
,
2874 FILEINTERFACE_GET_FORMATS
, &request
,
2875 sizeof(request
), &reply
, sizeof(reply
));
2877 if (status
== B_OK
) {
2878 memcpy(_formats
, formats
, sizeof(media_file_format
)*reply
.filled_slots
);
2879 *_numFormats
= reply
.filled_slots
;
2887 BMediaRoster::SetRefFor(const media_node
& file_interface
, const entry_ref
& file
,
2888 bool createAndTruncate
, bigtime_t
* _length
)
2892 if (IS_INVALID_NODE(file_interface
)
2893 || (file_interface
.kind
& B_FILE_INTERFACE
) == 0)
2894 return B_MEDIA_BAD_NODE
;
2896 fileinterface_set_ref_request request
;
2897 fileinterface_set_ref_reply reply
;
2900 request
.device
= file
.device
;
2901 request
.directory
= file
.directory
;
2902 strcpy(request
.name
, file
.name
);
2903 request
.create
= createAndTruncate
;
2904 if (_length
!= NULL
)
2905 request
.duration
= *_length
;
2907 rv
= QueryPort(file_interface
.port
, FILEINTERFACE_SET_REF
, &request
,
2908 sizeof(request
), &reply
, sizeof(reply
));
2912 if (!createAndTruncate
&& _length
)
2913 *_length
= reply
.duration
;
2920 BMediaRoster::GetRefFor(const media_node
& node
, entry_ref
* _file
,
2921 BMimeType
* mimeType
)
2925 if (IS_INVALID_NODE(node
)
2926 || (node
.kind
& B_FILE_INTERFACE
) == 0)
2927 return B_MEDIA_BAD_NODE
;
2932 fileinterface_get_ref_request request
;
2933 fileinterface_get_ref_reply reply
;
2936 rv
= QueryPort(node
.port
, FILEINTERFACE_GET_REF
, &request
, sizeof(request
),
2937 &reply
, sizeof(reply
));
2941 *_file
= entry_ref(reply
.device
, reply
.directory
, reply
.name
);
2944 mimeType
->SetTo(reply
.mimetype
);
2951 BMediaRoster::SniffRefFor(const media_node
& file_interface
,
2952 const entry_ref
& file
, BMimeType
* mimeType
, float* _capability
)
2956 if (IS_INVALID_NODE(file_interface
)
2957 || (file_interface
.kind
& B_FILE_INTERFACE
) == 0)
2958 return B_MEDIA_BAD_NODE
;
2960 if (mimeType
== NULL
|| _capability
== NULL
)
2963 fileinterface_sniff_ref_request request
;
2964 fileinterface_sniff_ref_reply reply
;
2967 request
.device
= file
.device
;
2968 request
.directory
= file
.directory
;
2969 strcpy(request
.name
, file
.name
);
2971 rv
= QueryPort(file_interface
.port
, FILEINTERFACE_SNIFF_REF
, &request
,
2972 sizeof(request
), &reply
, sizeof(reply
));
2976 mimeType
->SetTo(reply
.mimetype
);
2977 *_capability
= reply
.capability
;
2983 /*! This is the generic "here's a file, now can someone please play it"
2987 BMediaRoster::SniffRef(const entry_ref
& file
, uint64 requireNodeKinds
,
2988 dormant_node_info
* _node
, BMimeType
* mimeType
)
2992 TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64
2993 "\n", file
.name
, requireNodeKinds
);
2998 BMimeType aMimeType
;
3000 dormant_node_info nodes
[30];
3002 int32 highestCapability
= -1;
3007 // Get all dormant nodes using GetDormantNodes
3008 if (GetDormantNodes(nodes
, &count
, NULL
, NULL
, NULL
, requireNodeKinds
| B_FILE_INTERFACE
, 0) == B_OK
) {
3009 // Call SniffRefFor on each node that matches requireNodeKinds
3010 for (int32 i
=0;i
<count
;i
++) {
3011 if (InstantiateDormantNode(nodes
[i
], &node
) == B_OK
) {
3013 if (SniffRefFor(node
, file
, &aMimeType
, &capability
) == B_OK
) {
3014 // find the first node that has 100% capability
3015 TRACE("%s has a %f%% chance of playing file\n",nodes
[i
].name
, capability
* 100.0);
3016 if (capability
== 1.0) {
3017 highestCapability
= i
;
3025 if (highestCapability
!= -1) {
3026 *_node
= nodes
[highestCapability
];
3028 TRACE("BMediaRoster::SniffRef: found a node %s addon-id %" B_PRId32
3029 ", flavor_id %" B_PRId32
"\n",
3030 nodes
[highestCapability
].name
, nodes
[highestCapability
].addon
,
3031 nodes
[highestCapability
].flavor_id
);
3033 if (mimeType
!= NULL
) {
3034 //*mimeType = aMimeType; -- need a copy constructor
3047 BMediaRoster::GetDormantNodeForType(const BMimeType
& type
,
3048 uint64 requireNodeKinds
, dormant_node_info
* _node
)
3056 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info
& node
,
3057 media_file_format
* _readFormats
, int32 readCount
, int32
* _readCount
)
3065 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info
& node
,
3066 media_file_format
* _write_formats
, int32 writeCount
, int32
* _writeCount
)
3074 BMediaRoster::GetFormatFor(const media_output
& output
, media_format
* _format
,
3078 if (_format
== NULL
)
3080 if ((output
.node
.kind
& B_BUFFER_PRODUCER
) == 0)
3081 return B_MEDIA_BAD_NODE
;
3082 if (IS_INVALID_SOURCE(output
.source
))
3083 return B_MEDIA_BAD_SOURCE
;
3085 producer_format_suggestion_requested_request request
;
3086 producer_format_suggestion_requested_reply reply
;
3089 request
.type
= B_MEDIA_UNKNOWN_TYPE
;
3090 request
.quality
= 0; // TODO: what should this be?
3092 rv
= QueryPort(output
.source
.port
, PRODUCER_FORMAT_SUGGESTION_REQUESTED
,
3093 &request
, sizeof(request
), &reply
, sizeof(reply
));
3097 *_format
= reply
.format
;
3103 BMediaRoster::GetFormatFor(const media_input
& input
, media_format
* _format
,
3107 if (_format
== NULL
)
3109 if ((input
.node
.kind
& B_BUFFER_CONSUMER
) == 0)
3110 return B_MEDIA_BAD_NODE
;
3111 if (IS_INVALID_DESTINATION(input
.destination
))
3112 return B_MEDIA_BAD_DESTINATION
;
3114 consumer_accept_format_request request
;
3115 consumer_accept_format_reply reply
;
3118 request
.dest
= input
.destination
;
3119 memset(&request
.format
, 0, sizeof(request
.format
)); // wildcard
3121 rv
= QueryPort(input
.destination
.port
, CONSUMER_ACCEPT_FORMAT
, &request
,
3122 sizeof(request
), &reply
, sizeof(reply
));
3126 *_format
= reply
.format
;
3132 BMediaRoster::GetFormatFor(const media_node
& node
, media_format
* _format
,
3136 if (_format
== NULL
)
3138 if (IS_INVALID_NODE(node
))
3139 return B_MEDIA_BAD_NODE
;
3140 if ((node
.kind
& (B_BUFFER_CONSUMER
| B_BUFFER_PRODUCER
)) == 0)
3141 return B_MEDIA_BAD_NODE
;
3148 BMediaRoster::GetNodeAttributesFor(const media_node
& node
,
3149 media_node_attribute
* _array
, size_t maxCount
)
3153 if (IS_INVALID_NODE(node
))
3154 return B_MEDIA_BAD_NODE
;
3156 node_get_attributes_for_request request
;
3157 node_get_attributes_for_reply reply
;
3160 media_node_attribute
* addr
= NULL
;
3161 size_t totalSize
= maxCount
*sizeof(media_node_attribute
);
3162 size_t size
= (totalSize
+ (B_PAGE_SIZE
- 1)) & ~(B_PAGE_SIZE
- 1);
3164 area_id dataArea
= create_area("attributes area", (void**)&addr
,
3165 B_ANY_ADDRESS
, size
, B_NO_LOCK
,
3166 B_READ_AREA
| B_WRITE_AREA
);
3167 // No need to memset the padding
3168 memset(addr
, 0, totalSize
);
3173 request
.count
= maxCount
;
3174 request
.area
= dataArea
;
3176 status
= QueryPort(node
.port
, NODE_GET_ATTRIBUTES_FOR
, &request
,
3177 sizeof(request
), &reply
, sizeof(reply
));
3181 memcpy(_array
, addr
, reply
.filled_count
3182 * sizeof(media_node_attribute
));
3184 delete_area(dataArea
);
3185 return reply
.filled_count
;
3190 BMediaRoster::NodeIDFor(port_id port
)
3194 server_node_id_for_request request
;
3195 server_node_id_for_reply reply
;
3198 request
.port
= port
;
3200 rv
= QueryServer(SERVER_NODE_ID_FOR
, &request
, sizeof(request
), &reply
,
3203 ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32
")\n", rv
);
3207 return reply
.node_id
;
3212 BMediaRoster::GetInstancesFor(media_addon_id addon
, int32 flavor
,
3213 media_node_id
* _id
, int32
* _count
)
3218 if (_count
&& *_count
<= 0)
3221 server_get_instances_for_request request
;
3222 server_get_instances_for_reply reply
;
3225 request
.max_count
= (_count
? *_count
: 1);
3226 request
.add_on_id
= addon
;
3227 request
.flavor_id
= flavor
;
3229 rv
= QueryServer(SERVER_GET_INSTANCES_FOR
, &request
, sizeof(request
),
3230 &reply
, sizeof(reply
));
3232 ERROR("BMediaRoster::GetLiveNodes failed\n");
3237 *_count
= reply
.count
;
3238 if (reply
.count
> 0)
3239 memcpy(_id
, reply
.node_id
, sizeof(media_node_id
) * reply
.count
);
3246 BMediaRoster::IsRunning()
3248 return be_roster
->IsRunning(B_MEDIA_SERVER_SIGNATURE
)
3249 && be_roster
->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE
);
3254 BMediaRoster::SetRealtimeFlags(uint32 enabled
)
3262 BMediaRoster::GetRealtimeFlags(uint32
* _enabled
)
3270 BMediaRoster::AudioBufferSizeFor(int32 channelCount
, uint32 sampleFormat
,
3271 float frameRate
, bus_type busKind
)
3273 bigtime_t bufferDuration
;
3276 if (busKind
== B_ISA_BUS
|| busKind
== B_PCMCIA_BUS
)
3277 bufferDuration
= 25000;
3279 bufferDuration
= 10000;
3281 bufferSize
= (sampleFormat
& 0xf) * channelCount
3282 * (ssize_t
)((frameRate
* bufferDuration
) / 1000000.0);
3284 printf("Suggested buffer duration %" B_PRId64
", size %" B_PRIdSSIZE
"\n",
3285 bufferDuration
, bufferSize
);
3291 /*! Use MediaFlags to inquire about specific features of the Media Kit.
3292 Returns < 0 for "not present", positive size for output data size.
3293 0 means that the capability is present, but no data about it.
3296 BMediaRoster::MediaFlags(media_flags cap
, void* buffer
, size_t maxSize
)
3303 // #pragma mark - BLooper overrides
3307 BMediaRoster::MessageReceived(BMessage
* message
)
3309 switch (message
->what
) {
3312 // media_server plays ping-pong with the BMediaRosters
3313 // to detect dead teams. Normal communication uses ports.
3314 static BMessage
pong('PONG');
3315 message
->SendReply(&pong
, static_cast<BHandler
*>(NULL
), 2000000);
3319 case MEDIA_ROSTER_REQUEST_NOTIFICATIONS
:
3321 RosterNotification notification
;
3322 if (message
->FindInt32(NOTIFICATION_PARAM_WHAT
, ¬ification
.what
)
3324 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3325 "find what parameter");
3328 if (message
->FindMessenger(NOTIFICATION_PARAM_MESSENGER
,
3329 ¬ification
.messenger
) != B_OK
) {
3330 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't"
3334 sNotificationList
.Insert(notification
);
3338 case MEDIA_ROSTER_CANCEL_NOTIFICATIONS
:
3340 RosterNotification notification
;
3341 if (message
->FindInt32(NOTIFICATION_PARAM_WHAT
, ¬ification
.what
)
3343 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3344 "find what parameter");
3347 if (message
->FindMessenger(NOTIFICATION_PARAM_MESSENGER
,
3348 ¬ification
.messenger
) != B_OK
) {
3349 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't"
3353 for (int32 i
= 0; i
< sNotificationList
.CountItems(); i
++) {
3354 RosterNotification
* current
;
3355 if (sNotificationList
.Get(i
, ¤t
) != true)
3357 if (current
->what
== notification
.what
3358 && current
->messenger
== notification
.messenger
) {
3359 sNotificationList
.Remove(i
);
3366 case B_SOME_APP_LAUNCHED
:
3369 if (message
->FindString("be:signature", &mimeSig
) != B_OK
)
3371 if (mimeSig
!= B_MEDIA_ADDON_SERVER_SIGNATURE
3372 && mimeSig
!= B_MEDIA_SERVER_SIGNATURE
)
3375 TRACE("BMediaRoster::MessageReceived media services are going up.");
3377 // Send the notification to our subscribers
3378 if (BMediaRoster::IsRunning()) {
3380 // Wait for media services to wake up
3381 // TODO: This should be solved so that the server
3382 // have a way to notify us when the system is really
3383 // ready to run and we avoid sleeping.
3385 // Restore our friendship with the media servers
3386 if (MediaRosterEx(this)->BuildConnections() != B_OK
) {
3387 TRACE("BMediaRoster::MessageReceived can't reconnect"
3388 "to media_server.");
3391 for (int32 i
= 0; i
< sNotificationList
.CountItems(); i
++) {
3392 RosterNotification
* current
;
3393 if (sNotificationList
.Get(i
, ¤t
) != true)
3395 if (current
->what
== B_MEDIA_SERVER_STARTED
) {
3396 if (current
->messenger
.SendMessage(
3397 B_MEDIA_SERVER_STARTED
) != B_OK
) {
3398 if(!current
->messenger
.IsValid())
3399 sNotificationList
.Remove(i
);
3407 case B_SOME_APP_QUIT
:
3410 if (message
->FindString("be:signature", &mimeSig
) != B_OK
)
3412 if (mimeSig
!= B_MEDIA_ADDON_SERVER_SIGNATURE
3413 && mimeSig
!= B_MEDIA_SERVER_SIGNATURE
)
3416 TRACE("BMediaRoster::MessageReceived media services are down.");
3418 // Send the notification to our subscribers
3419 if (!BMediaRoster::IsRunning() && sServerIsUp
== true) {
3420 sServerIsUp
= false;
3421 for (int32 i
= 0; i
< sNotificationList
.CountItems(); i
++) {
3422 RosterNotification
* current
;
3423 if (sNotificationList
.Get(i
, ¤t
) != true)
3425 if (current
->what
== B_MEDIA_SERVER_QUIT
) {
3426 if (current
->messenger
.SendMessage(
3427 B_MEDIA_SERVER_QUIT
) != B_OK
) {
3428 if(!current
->messenger
.IsValid())
3429 sNotificationList
.Remove(i
);
3437 case NODE_FINAL_RELEASE
:
3439 // this function is called by a BMediaNode to delete
3440 // itself, as this needs to be done from another thread
3441 // context, it is done here.
3442 // TODO: If a node is released using BMediaRoster::ReleaseNode()
3443 // TODO: instead of using BMediaNode::Release() / BMediaNode::Acquire()
3444 // TODO: fRefCount of the BMediaNode will not be correct.
3447 message
->FindPointer("node", reinterpret_cast<void **>(&node
));
3449 TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE saving "
3450 "node %" B_PRId32
" configuration\n", node
->ID());
3451 MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(node
);
3453 TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing "
3454 "node %" B_PRId32
"\n", node
->ID());
3455 node
->DeleteHook(node
); // we don't call Release(), see above!
3459 printf("BMediaRoster::MessageReceived: unknown message!\n");
3460 message
->PrintToStream();
3465 BMediaRoster::QuitRequested()
3469 if (be_roster
->StopWatching(BMessenger(this, this)) != B_OK
)
3470 TRACE("Can't unregister roster notifications");
3472 if (sNotificationList
.CountItems() != 0)
3473 sNotificationList
.MakeEmpty();
3480 BMediaRoster::ResolveSpecifier(BMessage
* msg
, int32 index
, BMessage
* specifier
,
3481 int32 form
, const char* property
)
3483 return BLooper::ResolveSpecifier(msg
, index
, specifier
, form
, property
);
3488 BMediaRoster::GetSupportedSuites(BMessage
* data
)
3490 return BLooper::GetSupportedSuites(data
);
3494 BMediaRoster::~BMediaRoster()
3498 // Unset the global instance pointer, the destructor is also called
3499 // if a client app calls Lock(); and Quit(); directly.
3500 sDefaultInstance
= NULL
;
3504 // #pragma mark - private BMediaRoster
3507 //! Deprecated call.
3509 BMediaRoster::SetOutputBuffersFor(const media_source
& output
,
3510 BBufferGroup
* group
, bool willReclaim
)
3513 debugger("BMediaRoster::SetOutputBuffersFor missing\n");
3518 // FBC reserved virtuals
3519 status_t
BMediaRoster::_Reserved_MediaRoster_0(void*) { return B_ERROR
; }
3520 status_t
BMediaRoster::_Reserved_MediaRoster_1(void*) { return B_ERROR
; }
3521 status_t
BMediaRoster::_Reserved_MediaRoster_2(void*) { return B_ERROR
; }
3522 status_t
BMediaRoster::_Reserved_MediaRoster_3(void*) { return B_ERROR
; }
3523 status_t
BMediaRoster::_Reserved_MediaRoster_4(void*) { return B_ERROR
; }
3524 status_t
BMediaRoster::_Reserved_MediaRoster_5(void*) { return B_ERROR
; }
3525 status_t
BMediaRoster::_Reserved_MediaRoster_6(void*) { return B_ERROR
; }
3526 status_t
BMediaRoster::_Reserved_MediaRoster_7(void*) { return B_ERROR
; }
3529 BMediaRoster::BMediaRoster()
3531 BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY
,
3532 B_LOOPER_PORT_DEFAULT_CAPACITY
)
3541 // TODO: Looks like these can be safely removed:
3543 BMediaRoster::ParseCommand(BMessage
& reply
)
3551 BMediaRoster::GetDefaultInfo(media_node_id forDefault
, BMessage
& config
)
3559 BMediaRoster::SetRunningDefault(media_node_id forDefault
,
3560 const media_node
& node
)
3567 // #pragma mark - static variables
3570 BMediaRoster
* BMediaRoster::sDefaultInstance
= NULL
;