2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2013 Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
8 * Copyright (c) 2002-2004, Marcus Overhagen <marcus@overhagen.de>
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <Application.h>
40 #include <Directory.h>
42 #include <MediaAddOn.h>
43 #include <MediaRoster.h>
44 #include <MessageRunner.h>
49 #include <AddOnMonitorHandler.h>
51 #include <DataExchange.h>
52 #include <DormantNodeManager.h>
53 #include <MediaMisc.h>
54 #include <MediaRosterEx.h>
55 #include <MediaSounds.h>
56 #include <Notifications.h>
57 #include <ServerInterface.h>
59 #include "MediaFilePlayer.h"
60 #include "SystemTimeSource.h"
63 //#define USER_ADDON_PATH "../add-ons/media"
66 typedef std::vector
<media_node
> NodeVector
;
74 NodeVector active_flavors
;
76 // if != NULL, need to call gDormantNodeManager->PutAddOn(id)
81 class MediaAddonServer
: BApplication
{
83 MediaAddonServer(const char* signature
);
84 virtual ~MediaAddonServer();
85 virtual void ReadyToRun();
86 virtual bool QuitRequested();
87 virtual void MessageReceived(BMessage
* message
);
91 friend class MonitorHandler
;
93 void _AddOnAdded(const char* path
, ino_t fileNode
);
94 void _AddOnRemoved(ino_t fileNode
);
95 void _HandleMessage(int32 code
, const void* data
,
98 void _PutAddonIfPossible(AddOnInfo
& info
);
99 void _InstantiatePhysicalInputsAndOutputs(
101 void _InstantiateAutostartFlavors(AddOnInfo
& info
);
102 void _DestroyInstantiatedFlavors(AddOnInfo
& info
);
104 void _ScanAddOnFlavors(BMediaAddOn
* addOn
);
106 port_id
_ControlPort() const { return fControlPort
; }
108 static status_t
_ControlThread(void* arg
);
111 typedef std::map
<ino_t
, media_addon_id
> FileMap
;
112 typedef std::map
<media_addon_id
, AddOnInfo
> InfoMap
;
117 BMediaRoster
* fMediaRoster
;
118 MonitorHandler
* fMonitorHandler
;
119 BMessageRunner
* fPulseRunner
;
120 port_id fControlPort
;
121 thread_id fControlThread
;
124 SystemTimeSource
* fSystemTimeSource
;
128 class MediaAddonServer::MonitorHandler
: public AddOnMonitorHandler
{
130 MonitorHandler(MediaAddonServer
* server
);
132 virtual void AddOnEnabled(const add_on_entry_info
* info
);
133 virtual void AddOnDisabled(const add_on_entry_info
* info
);
136 MediaAddonServer
* fServer
;
142 DumpFlavorInfo(const flavor_info
* info
)
144 printf(" name = %s\n", info
->name
);
145 printf(" info = %s\n", info
->info
);
146 printf(" internal_id = %ld\n", info
->internal_id
);
147 printf(" possible_count = %ld\n", info
->possible_count
);
148 printf(" flavor_flags = 0x%lx", info
->flavor_flags
);
149 if (info
->flavor_flags
& B_FLAVOR_IS_GLOBAL
) printf(" B_FLAVOR_IS_GLOBAL");
150 if (info
->flavor_flags
& B_FLAVOR_IS_LOCAL
) printf(" B_FLAVOR_IS_LOCAL");
152 printf(" kinds = 0x%Lx", info
->kinds
);
153 if (info
->kinds
& B_BUFFER_PRODUCER
) printf(" B_BUFFER_PRODUCER");
154 if (info
->kinds
& B_BUFFER_CONSUMER
) printf(" B_BUFFER_CONSUMER");
155 if (info
->kinds
& B_TIME_SOURCE
) printf(" B_TIME_SOURCE");
156 if (info
->kinds
& B_CONTROLLABLE
) printf(" B_CONTROLLABLE");
157 if (info
->kinds
& B_FILE_INTERFACE
) printf(" B_FILE_INTERFACE");
158 if (info
->kinds
& B_ENTITY_INTERFACE
) printf(" B_ENTITY_INTERFACE");
159 if (info
->kinds
& B_PHYSICAL_INPUT
) printf(" B_PHYSICAL_INPUT");
160 if (info
->kinds
& B_PHYSICAL_OUTPUT
) printf(" B_PHYSICAL_OUTPUT");
161 if (info
->kinds
& B_SYSTEM_MIXER
) printf(" B_SYSTEM_MIXER");
163 printf(" in_format_count = %ld\n", info
->in_format_count
);
164 printf(" out_format_count = %ld\n", info
->out_format_count
);
172 MediaAddonServer::MonitorHandler::MonitorHandler(MediaAddonServer
* server
)
179 MediaAddonServer::MonitorHandler::AddOnEnabled(const add_on_entry_info
* info
)
182 make_entry_ref(info
->dir_nref
.device
, info
->dir_nref
.node
,
184 BEntry
entry(&ref
, true);
189 if (path
.InitCheck() == B_OK
)
190 fServer
->_AddOnAdded(path
.Path(), info
->nref
.node
);
195 MediaAddonServer::MonitorHandler::AddOnDisabled(const add_on_entry_info
* info
)
197 fServer
->_AddOnRemoved(info
->nref
.node
);
204 MediaAddonServer::MediaAddonServer(const char* signature
)
206 BApplication(signature
),
207 fMonitorHandler(NULL
),
211 fSystemTimeSource(NULL
)
214 fMediaRoster
= BMediaRoster::Roster();
215 fControlPort
= create_port(64, MEDIA_ADDON_SERVER_PORT_NAME
);
216 fControlThread
= spawn_thread(_ControlThread
, "media_addon_server control",
217 B_NORMAL_PRIORITY
+ 2, this);
218 resume_thread(fControlThread
);
222 MediaAddonServer::~MediaAddonServer()
226 delete_port(fControlPort
);
227 wait_for_thread(fControlThread
, NULL
);
229 // unregister all media add-ons
230 FileMap::iterator iterator
= fFileMap
.begin();
231 for (; iterator
!= fFileMap
.end(); iterator
++)
232 gDormantNodeManager
->UnregisterAddOn(iterator
->second
);
234 delete fMonitorHandler
;
240 MediaAddonServer::ReadyToRun()
242 if (!be_roster
->IsRunning(B_MEDIA_SERVER_SIGNATURE
)) {
243 // the media server is not running, let's quit
244 fprintf(stderr
, "The media_server is not running!\n");
249 // the control thread is already running at this point,
250 // so we can talk to the media server and also receive
251 // commands for instantiation
253 ASSERT(fStartup
== true);
255 // The very first thing to do is to create the system time source,
256 // register it with the server, and make it the default SYSTEM_TIME_SOURCE
257 fSystemTimeSource
= new SystemTimeSource();
258 status_t result
= fMediaRoster
->RegisterNode(fSystemTimeSource
);
259 if (result
!= B_OK
) {
260 fprintf(stderr
, "Can't register system time source : %s\n",
262 ERROR("Can't register system time source");
265 if (fSystemTimeSource
->ID() != NODE_SYSTEM_TIMESOURCE_ID
)
266 ERROR("System time source got wrong node ID");
267 media_node node
= fSystemTimeSource
->Node();
268 result
= MediaRosterEx(fMediaRoster
)->SetNode(SYSTEM_TIME_SOURCE
, &node
);
270 ERROR("Can't setup system time source as default");
272 // During startup, first all add-ons are loaded, then all
273 // nodes (flavors) representing physical inputs and outputs
274 // are instantiated. Next, all add-ons that need autostart
275 // will be autostarted. Finally, add-ons that don't have
276 // any active nodes (flavors) will be unloaded.
278 fMonitorHandler
= new MonitorHandler(this);
279 AddHandler(fMonitorHandler
);
281 BMessage
pulse(B_PULSE
);
282 // the monitor handler needs a pulse to check if add-ons are ready
283 fPulseRunner
= new BMessageRunner(fMonitorHandler
, &pulse
, 1000000LL);
285 result
= fPulseRunner
->InitCheck();
287 ERROR("Can't create the pulse runner");
289 fMonitorHandler
->AddAddOnDirectories("media");
291 #ifdef USER_ADDON_PATH
293 if (entry
.SetTo(USER_ADDON_PATH
) == B_OK
294 && entry
.GetNodeRef(&nodeRef
) == B_OK
) {
295 fMonitorHandler
->AddDirectory(&nodeRef
);
301 InfoMap::iterator iterator
= fInfoMap
.begin();
302 for (; iterator
!= fInfoMap
.end(); iterator
++)
303 _InstantiatePhysicalInputsAndOutputs(iterator
->second
);
305 for (iterator
= fInfoMap
.begin(); iterator
!= fInfoMap
.end(); iterator
++)
306 _InstantiateAutostartFlavors(iterator
->second
);
308 for (iterator
= fInfoMap
.begin(); iterator
!= fInfoMap
.end(); iterator
++)
309 _PutAddonIfPossible(iterator
->second
);
311 server_rescan_defaults_command cmd
;
312 SendToServer(SERVER_RESCAN_DEFAULTS
, &cmd
, sizeof(cmd
));
317 MediaAddonServer::QuitRequested()
321 InfoMap::iterator iterator
= fInfoMap
.begin();
322 for (iterator
= fInfoMap
.begin(); iterator
!= fInfoMap
.end(); iterator
++)
323 _DestroyInstantiatedFlavors(iterator
->second
);
325 // the System timesource should be removed before we quit the roster
326 if (fSystemTimeSource
!= NULL
&&
327 be_roster
->IsRunning(B_MEDIA_SERVER_SIGNATURE
)) {
328 status_t result
= fMediaRoster
->UnregisterNode(fSystemTimeSource
);
329 if (result
!= B_OK
) {
330 fprintf(stderr
, "Error removing the system time source : %s\n",
332 ERROR("Can't remove the system time source");
334 fSystemTimeSource
->Release();
335 fSystemTimeSource
= NULL
;
338 for (iterator
= fInfoMap
.begin(); iterator
!= fInfoMap
.end(); iterator
++)
339 _PutAddonIfPossible(iterator
->second
);
346 MediaAddonServer::MessageReceived(BMessage
* message
)
348 switch (message
->what
) {
349 case MEDIA_ADD_ON_SERVER_PLAY_MEDIA
:
353 if (message
->FindString(MEDIA_NAME_KEY
, &name
) != B_OK
354 || message
->FindString(MEDIA_TYPE_KEY
, &type
) != B_OK
) {
355 message
->SendReply(B_ERROR
);
359 PlayMediaFile(type
, name
);
360 message
->SendReply((uint32
)B_OK
);
361 // TODO: don't know which reply is expected
366 BApplication::MessageReceived(message
);
373 MediaAddonServer::_HandleMessage(int32 code
, const void* data
, size_t size
)
376 case ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE
:
378 const add_on_server_instantiate_dormant_node_request
* request
380 const add_on_server_instantiate_dormant_node_request
*>(
382 add_on_server_instantiate_dormant_node_reply reply
;
385 = MediaRosterEx(fMediaRoster
)->InstantiateDormantNode(
386 request
->add_on_id
, request
->flavor_id
,
387 request
->creator_team
, &reply
.node
);
388 request
->SendReply(status
, &reply
, sizeof(reply
));
392 case ADD_ON_SERVER_RESCAN_ADD_ON_FLAVORS
:
394 const add_on_server_rescan_flavors_command
* command
= static_cast<
395 const add_on_server_rescan_flavors_command
*>(data
);
397 = gDormantNodeManager
->GetAddOn(command
->add_on_id
);
399 ERROR("rescan flavors: Can't find a addon object for id %d\n",
400 (int)command
->add_on_id
);
403 _ScanAddOnFlavors(addOn
);
404 gDormantNodeManager
->PutAddOn(command
->add_on_id
);
408 case ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY
:
410 system_beep(MEDIA_SOUNDS_STARTUP
);
411 fStartupSound
= false;
416 ERROR("media_addon_server: received unknown message code %#08"
417 B_PRIx32
"\n", code
);
424 MediaAddonServer::_ControlThread(void* _server
)
426 MediaAddonServer
* server
= (MediaAddonServer
*)_server
;
428 char data
[B_MEDIA_MESSAGE_SIZE
];
431 while ((size
= read_port_etc(server
->_ControlPort(), &code
, data
,
432 sizeof(data
), 0, 0)) > 0)
433 server
->_HandleMessage(code
, data
, size
);
440 MediaAddonServer::_ScanAddOnFlavors(BMediaAddOn
* addon
)
442 ASSERT(addon
->AddonID() > 0);
444 TRACE("MediaAddonServer::_ScanAddOnFlavors: id %ld\n", addon
->AddonID());
446 // cache the media_addon_id in a local variable to avoid
447 // calling BMediaAddOn::AddonID() too often
448 media_addon_id addonID
= addon
->AddonID();
450 // update the cached flavor count, get oldflavorcount and newflavorcount
452 InfoMap::iterator found
= fInfoMap
.find(addonID
);
453 ASSERT(found
!= fInfoMap
.end());
455 AddOnInfo
& info
= found
->second
;
456 int32 oldFlavorCount
= info
.flavor_count
;
457 int32 newFlavorCount
= addon
->CountFlavors();
458 info
.flavor_count
= newFlavorCount
;
460 TRACE("%ld old flavors, %ld new flavors\n", oldFlavorCount
, newFlavorCount
);
462 // during the first update (i == 0), the server removes old dormant_flavor_infos
463 for (int i
= 0; i
< newFlavorCount
; i
++) {
464 const flavor_info
* flavorInfo
;
465 TRACE("flavor %d:\n", i
);
466 if (addon
->GetFlavorAt(i
, &flavorInfo
) != B_OK
) {
467 ERROR("MediaAddonServer::_ScanAddOnFlavors GetFlavorAt failed for "
473 DumpFlavorInfo(flavorInfo
);
476 dormant_flavor_info dormantFlavorInfo
;
477 dormantFlavorInfo
= *flavorInfo
;
478 dormantFlavorInfo
.node_info
.addon
= addonID
;
479 dormantFlavorInfo
.node_info
.flavor_id
= flavorInfo
->internal_id
;
480 strlcpy(dormantFlavorInfo
.node_info
.name
, flavorInfo
->name
,
481 B_MEDIA_NAME_LENGTH
);
483 size_t flattenedSize
= dormantFlavorInfo
.FlattenedSize();
484 size_t messageSize
= flattenedSize
485 + sizeof(server_register_dormant_node_command
);
486 server_register_dormant_node_command
* message
487 = (server_register_dormant_node_command
*)malloc(messageSize
);
491 // The server should remove previously registered "dormant_flavor_info"s
492 // during the first update, but after the first iteration, we don't
493 // want the server to anymore remove old dormant_flavor_infos
494 message
->purge_id
= i
== 0 ? addonID
: 0;
496 message
->type
= dormantFlavorInfo
.TypeCode();
497 message
->flattened_size
= flattenedSize
;
498 dormantFlavorInfo
.Flatten(message
->flattened_data
, flattenedSize
);
500 status_t status
= SendToServer(SERVER_REGISTER_DORMANT_NODE
,
501 message
, messageSize
);
502 if (status
!= B_OK
) {
503 ERROR("MediaAddonServer::_ScanAddOnFlavors: couldn't register "
504 "dormant node: %s\n", strerror(status
));
510 // TODO: we currently pretend that all old flavors have been removed, this
511 // could probably be done in a smarter way
512 BPrivate::media::notifications::FlavorsChanged(addonID
, newFlavorCount
,
518 MediaAddonServer::_AddOnAdded(const char* path
, ino_t fileNode
)
520 TRACE("\n\nMediaAddonServer::_AddOnAdded: path %s\n", path
);
522 media_addon_id id
= gDormantNodeManager
->RegisterAddOn(path
);
524 ERROR("MediaAddonServer::_AddOnAdded: failed to register add-on %s\n",
529 TRACE("MediaAddonServer::_AddOnAdded: loading addon %ld now...\n", id
);
531 BMediaAddOn
* addon
= gDormantNodeManager
->GetAddOn(id
);
533 ERROR("MediaAddonServer::_AddOnAdded: failed to get add-on %s\n", path
);
534 gDormantNodeManager
->UnregisterAddOn(id
);
538 TRACE("MediaAddonServer::_AddOnAdded: loading finished, id %ld\n", id
);
541 // put file's inode and addon's id into map
542 fFileMap
.insert(std::make_pair(fileNode
, id
));
545 fInfoMap
.insert(std::make_pair(id
, info
));
546 } catch (std::bad_alloc
& exception
) {
547 fFileMap
.erase(fileNode
);
551 InfoMap::iterator found
= fInfoMap
.find(id
);
552 AddOnInfo
& info
= found
->second
;
556 info
.wants_autostart
= false;
557 info
.flavor_count
= 0;
561 _ScanAddOnFlavors(addon
);
563 // need to call BMediaNode::WantsAutoStart()
564 // after the flavors have been scanned
565 info
.wants_autostart
= addon
->WantsAutoStart();
567 if (info
.wants_autostart
)
568 TRACE("add-on %ld WantsAutoStart!\n", id
);
570 // During startup, first all add-ons are loaded, then all
571 // nodes (flavors) representing physical inputs and outputs
572 // are instantiated. Next, all add-ons that need autostart
573 // will be autostarted. Finally, add-ons that don't have
574 // any active nodes (flavors) will be unloaded.
576 // After startup is done, we simply do it for each new
577 // loaded add-on, too.
579 _InstantiatePhysicalInputsAndOutputs(info
);
580 _InstantiateAutostartFlavors(info
);
581 _PutAddonIfPossible(info
);
583 // since something might have changed
584 server_rescan_defaults_command cmd
;
585 SendToServer(SERVER_RESCAN_DEFAULTS
, &cmd
, sizeof(cmd
));
588 // we do not call gDormantNodeManager->PutAddOn(id)
589 // since it is done by _PutAddonIfPossible()
594 MediaAddonServer::_DestroyInstantiatedFlavors(AddOnInfo
& info
)
596 printf("MediaAddonServer::_DestroyInstantiatedFlavors addon %" B_PRId32
599 NodeVector::iterator iterator
= info
.active_flavors
.begin();
600 for (; iterator
!= info
.active_flavors
.end(); iterator
++) {
601 media_node
& node
= *iterator
;
603 printf("node %" B_PRId32
"\n", node
.node
);
605 if ((node
.kind
& B_TIME_SOURCE
) != 0
606 && (fMediaRoster
->StopTimeSource(node
, 0, true) != B_OK
)) {
607 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't stop "
612 if (fMediaRoster
->StopNode(node
, 0, true) != B_OK
) {
613 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't stop "
618 if ((node
.kind
& B_BUFFER_CONSUMER
) != 0) {
619 media_input inputs
[16];
621 if (fMediaRoster
->GetConnectedInputsFor(node
, inputs
, 16, &count
)
623 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't "
624 "get connected inputs\n");
628 for (int32 i
= 0; i
< count
; i
++) {
629 media_node_id sourceNode
;
630 if ((sourceNode
= fMediaRoster
->NodeIDFor(
631 inputs
[i
].source
.port
)) < 0) {
632 printf("MediaAddonServer::_DestroyInstantiatedFlavors "
633 "couldn't get source node id\n");
637 if (fMediaRoster
->Disconnect(sourceNode
, inputs
[i
].source
,
638 node
.node
, inputs
[i
].destination
) != B_OK
) {
639 printf("MediaAddonServer::_DestroyInstantiatedFlavors "
640 "couldn't disconnect input\n");
646 if ((node
.kind
& B_BUFFER_PRODUCER
) != 0) {
647 media_output outputs
[16];
649 if (fMediaRoster
->GetConnectedOutputsFor(node
, outputs
, 16,
651 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't "
652 "get connected outputs\n");
656 for (int32 i
= 0; i
< count
; i
++) {
657 media_node_id destNode
;
658 if ((destNode
= fMediaRoster
->NodeIDFor(
659 outputs
[i
].destination
.port
)) < 0) {
660 printf("MediaAddonServer::_DestroyInstantiatedFlavors "
661 "couldn't get destination node id\n");
665 if (fMediaRoster
->Disconnect(node
.node
, outputs
[i
].source
,
666 destNode
, outputs
[i
].destination
) != B_OK
) {
667 printf("MediaAddonServer::_DestroyInstantiatedFlavors "
668 "couldn't disconnect output\n");
674 if (MediaRosterEx(fMediaRoster
)->ReleaseNodeAll(node
) != B_OK
) {
675 printf("MediaAddonServer::_DestroyInstantiatedFlavors "
676 "couldn't release node\n");
679 // wait a bit to let the node clean up
683 info
.active_flavors
.clear();
688 MediaAddonServer::_PutAddonIfPossible(AddOnInfo
& info
)
690 if (info
.addon
&& info
.active_flavors
.empty()) {
691 gDormantNodeManager
->PutAddOn(info
.id
);
698 MediaAddonServer::_InstantiatePhysicalInputsAndOutputs(AddOnInfo
& info
)
701 int32 count
= info
.addon
->CountFlavors();
703 for (int32 i
= 0; i
< count
; i
++) {
704 const flavor_info
* flavorinfo
;
705 if (info
.addon
->GetFlavorAt(i
, &flavorinfo
) != B_OK
) {
706 ERROR("MediaAddonServer::InstantiatePhysialInputsAndOutputs "
707 "GetFlavorAt failed for index %" B_PRId32
"!\n", i
);
710 if ((flavorinfo
->kinds
& (B_PHYSICAL_INPUT
| B_PHYSICAL_OUTPUT
)) != 0) {
713 dormant_node_info dormantNodeInfo
;
714 dormantNodeInfo
.addon
= info
.id
;
715 dormantNodeInfo
.flavor_id
= flavorinfo
->internal_id
;
716 strcpy(dormantNodeInfo
.name
, flavorinfo
->name
);
718 TRACE("MediaAddonServer::InstantiatePhysialInputsAndOutputs: "
719 "\"%s\" is a physical input/output\n", flavorinfo
->name
);
720 status_t status
= fMediaRoster
->InstantiateDormantNode(
721 dormantNodeInfo
, &node
);
722 if (status
!= B_OK
) {
723 ERROR("MediaAddonServer::InstantiatePhysialInputsAndOutputs "
724 "Couldn't instantiate node flavor, internal_id %" B_PRId32
725 ", name %s\n", flavorinfo
->internal_id
, flavorinfo
->name
);
727 TRACE("Node created!\n");
728 info
.active_flavors
.push_back(node
);
736 MediaAddonServer::_InstantiateAutostartFlavors(AddOnInfo
& info
)
738 if (!info
.wants_autostart
)
741 for (int32 index
= 0;; index
++) {
742 TRACE("trying autostart of node %ld, index %ld\n", info
.id
, index
);
747 status_t status
= info
.addon
->AutoStart(index
, &node
, &internalID
,
749 if (status
== B_MEDIA_ADDON_FAILED
&& hasMore
)
751 else if (status
!= B_OK
)
754 printf("started node %" B_PRId32
"\n", index
);
756 status
= MediaRosterEx(fMediaRoster
)->RegisterNode(node
, info
.id
,
758 if (status
!= B_OK
) {
759 ERROR("failed to register node %" B_PRId32
"\n", index
);
762 MediaRosterEx(fMediaRoster
)->IncrementAddonFlavorInstancesCount(
763 info
.id
, internalID
);
764 info
.active_flavors
.push_back(node
->Node());
774 MediaAddonServer::_AddOnRemoved(ino_t fileNode
)
778 FileMap::iterator foundFile
= fFileMap
.find(fileNode
);
779 if (foundFile
== fFileMap
.end()) {
780 ERROR("MediaAddonServer::_AddOnRemoved: inode %" B_PRIdINO
" removed, but no "
781 "media add-on found\n", fileNode
);
785 media_addon_id id
= foundFile
->second
;
786 fFileMap
.erase(foundFile
);
788 int32 oldFlavorCount
;
789 InfoMap::iterator foundInfo
= fInfoMap
.find(id
);
791 if (foundInfo
== fInfoMap
.end()) {
792 ERROR("MediaAddonServer::_AddOnRemoved: couldn't get addon info for "
793 "add-on %" B_PRId32
"\n", id
);
794 oldFlavorCount
= 1000;
796 AddOnInfo
& info
= foundInfo
->second
;
797 oldFlavorCount
= info
.flavor_count
;
799 _DestroyInstantiatedFlavors(info
);
800 _PutAddonIfPossible(info
);
803 ERROR("MediaAddonServer::_AddOnRemoved: couldn't unload addon "
804 "%" B_PRId32
" since flavors are in use\n", id
);
807 fInfoMap
.erase(foundInfo
);
810 gDormantNodeManager
->UnregisterAddOn(id
);
812 BPrivate::media::notifications::FlavorsChanged(id
, 0, oldFlavorCount
);
822 new MediaAddonServer(B_MEDIA_ADDON_SERVER_SIGNATURE
);