Make UEFI boot-platform build again
[haiku.git] / src / servers / media_addon / MediaAddonServer.cpp
blob6201700c4c45bdee4c008df96093c4846a8a5a96
1 /*
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.
5 */
7 /*
8 * Copyright (c) 2002-2004, Marcus Overhagen <marcus@overhagen.de>
9 * All rights reserved.
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.
33 #include <map>
34 #include <stdio.h>
35 #include <vector>
37 #include <Alert.h>
38 #include <Application.h>
39 #include <Beep.h>
40 #include <Directory.h>
41 #include <Entry.h>
42 #include <MediaAddOn.h>
43 #include <MediaRoster.h>
44 #include <MessageRunner.h>
45 #include <Path.h>
46 #include <Roster.h>
47 #include <String.h>
49 #include <AddOnMonitorHandler.h>
50 #include <debug.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;
69 struct AddOnInfo {
70 media_addon_id id;
71 bool wants_autostart;
72 int32 flavor_count;
74 NodeVector active_flavors;
76 // if != NULL, need to call gDormantNodeManager->PutAddOn(id)
77 BMediaAddOn* addon;
81 class MediaAddonServer : BApplication {
82 public:
83 MediaAddonServer(const char* signature);
84 virtual ~MediaAddonServer();
85 virtual void ReadyToRun();
86 virtual bool QuitRequested();
87 virtual void MessageReceived(BMessage* message);
89 private:
90 class MonitorHandler;
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,
96 size_t size);
98 void _PutAddonIfPossible(AddOnInfo& info);
99 void _InstantiatePhysicalInputsAndOutputs(
100 AddOnInfo& info);
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);
110 private:
111 typedef std::map<ino_t, media_addon_id> FileMap;
112 typedef std::map<media_addon_id, AddOnInfo> InfoMap;
114 FileMap fFileMap;
115 InfoMap fInfoMap;
117 BMediaRoster* fMediaRoster;
118 MonitorHandler* fMonitorHandler;
119 BMessageRunner* fPulseRunner;
120 port_id fControlPort;
121 thread_id fControlThread;
122 bool fStartup;
123 bool fStartupSound;
124 SystemTimeSource* fSystemTimeSource;
128 class MediaAddonServer::MonitorHandler : public AddOnMonitorHandler {
129 public:
130 MonitorHandler(MediaAddonServer* server);
132 virtual void AddOnEnabled(const add_on_entry_info* info);
133 virtual void AddOnDisabled(const add_on_entry_info* info);
135 private:
136 MediaAddonServer* fServer;
140 #if DEBUG >= 2
141 static void
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");
151 printf("\n");
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");
162 printf("\n");
163 printf(" in_format_count = %ld\n", info->in_format_count);
164 printf(" out_format_count = %ld\n", info->out_format_count);
166 #endif
169 // #pragma mark -
172 MediaAddonServer::MonitorHandler::MonitorHandler(MediaAddonServer* server)
174 fServer = server;
178 void
179 MediaAddonServer::MonitorHandler::AddOnEnabled(const add_on_entry_info* info)
181 entry_ref ref;
182 make_entry_ref(info->dir_nref.device, info->dir_nref.node,
183 info->name, &ref);
184 BEntry entry(&ref, true);
185 if (!entry.IsFile())
186 return;
188 BPath path(&ref);
189 if (path.InitCheck() == B_OK)
190 fServer->_AddOnAdded(path.Path(), info->nref.node);
194 void
195 MediaAddonServer::MonitorHandler::AddOnDisabled(const add_on_entry_info* info)
197 fServer->_AddOnRemoved(info->nref.node);
201 // #pragma mark -
204 MediaAddonServer::MediaAddonServer(const char* signature)
206 BApplication(signature),
207 fMonitorHandler(NULL),
208 fPulseRunner(NULL),
209 fStartup(true),
210 fStartupSound(true),
211 fSystemTimeSource(NULL)
213 CALLED();
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()
224 CALLED();
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;
235 delete fPulseRunner;
239 void
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");
245 Quit();
246 return;
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",
261 strerror(result));
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);
269 if (result != B_OK)
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();
286 if (result != B_OK)
287 ERROR("Can't create the pulse runner");
289 fMonitorHandler->AddAddOnDirectories("media");
291 #ifdef USER_ADDON_PATH
292 node_ref nodeRef;
293 if (entry.SetTo(USER_ADDON_PATH) == B_OK
294 && entry.GetNodeRef(&nodeRef) == B_OK) {
295 fMonitorHandler->AddDirectory(&nodeRef);
297 #endif
299 fStartup = false;
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));
316 bool
317 MediaAddonServer::QuitRequested()
319 CALLED();
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",
331 strerror(result));
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);
341 return true;
345 void
346 MediaAddonServer::MessageReceived(BMessage* message)
348 switch (message->what) {
349 case MEDIA_ADD_ON_SERVER_PLAY_MEDIA:
351 const char* name;
352 const char* type;
353 if (message->FindString(MEDIA_NAME_KEY, &name) != B_OK
354 || message->FindString(MEDIA_TYPE_KEY, &type) != B_OK) {
355 message->SendReply(B_ERROR);
356 break;
359 PlayMediaFile(type, name);
360 message->SendReply((uint32)B_OK);
361 // TODO: don't know which reply is expected
362 return;
365 default:
366 BApplication::MessageReceived(message);
367 break;
372 void
373 MediaAddonServer::_HandleMessage(int32 code, const void* data, size_t size)
375 switch (code) {
376 case ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE:
378 const add_on_server_instantiate_dormant_node_request* request
379 = static_cast<
380 const add_on_server_instantiate_dormant_node_request*>(
381 data);
382 add_on_server_instantiate_dormant_node_reply reply;
384 status_t status
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));
389 break;
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);
396 BMediaAddOn* addOn
397 = gDormantNodeManager->GetAddOn(command->add_on_id);
398 if (addOn == NULL) {
399 ERROR("rescan flavors: Can't find a addon object for id %d\n",
400 (int)command->add_on_id);
401 break;
403 _ScanAddOnFlavors(addOn);
404 gDormantNodeManager->PutAddOn(command->add_on_id);
405 break;
408 case ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY:
409 if (fStartupSound) {
410 system_beep(MEDIA_SOUNDS_STARTUP);
411 fStartupSound = false;
413 break;
415 default:
416 ERROR("media_addon_server: received unknown message code %#08"
417 B_PRIx32 "\n", code);
418 break;
423 status_t
424 MediaAddonServer::_ControlThread(void* _server)
426 MediaAddonServer* server = (MediaAddonServer*)_server;
428 char data[B_MEDIA_MESSAGE_SIZE];
429 ssize_t size;
430 int32 code;
431 while ((size = read_port_etc(server->_ControlPort(), &code, data,
432 sizeof(data), 0, 0)) > 0)
433 server->_HandleMessage(code, data, size);
435 return B_OK;
439 void
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 "
468 "index %d!\n", i);
469 continue;
472 #if DEBUG >= 2
473 DumpFlavorInfo(flavorInfo);
474 #endif
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);
488 if (message == NULL)
489 break;
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));
507 free(message);
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,
513 oldFlavorCount);
517 void
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);
523 if (id <= 0) {
524 ERROR("MediaAddonServer::_AddOnAdded: failed to register add-on %s\n",
525 path);
526 return;
529 TRACE("MediaAddonServer::_AddOnAdded: loading addon %ld now...\n", id);
531 BMediaAddOn* addon = gDormantNodeManager->GetAddOn(id);
532 if (addon == NULL) {
533 ERROR("MediaAddonServer::_AddOnAdded: failed to get add-on %s\n", path);
534 gDormantNodeManager->UnregisterAddOn(id);
535 return;
538 TRACE("MediaAddonServer::_AddOnAdded: loading finished, id %ld\n", id);
540 try {
541 // put file's inode and addon's id into map
542 fFileMap.insert(std::make_pair(fileNode, id));
544 AddOnInfo info;
545 fInfoMap.insert(std::make_pair(id, info));
546 } catch (std::bad_alloc& exception) {
547 fFileMap.erase(fileNode);
548 return;
551 InfoMap::iterator found = fInfoMap.find(id);
552 AddOnInfo& info = found->second;
554 info.id = id;
555 // temporary default
556 info.wants_autostart = false;
557 info.flavor_count = 0;
558 info.addon = addon;
560 // scan the flavors
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.
578 if (!fStartup) {
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()
593 void
594 MediaAddonServer::_DestroyInstantiatedFlavors(AddOnInfo& info)
596 printf("MediaAddonServer::_DestroyInstantiatedFlavors addon %" B_PRId32
597 "\n", info.id);
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 "
608 "timesource\n");
609 continue;
612 if (fMediaRoster->StopNode(node, 0, true) != B_OK) {
613 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't stop "
614 "node\n");
615 continue;
618 if ((node.kind & B_BUFFER_CONSUMER) != 0) {
619 media_input inputs[16];
620 int32 count = 0;
621 if (fMediaRoster->GetConnectedInputsFor(node, inputs, 16, &count)
622 != B_OK) {
623 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't "
624 "get connected inputs\n");
625 continue;
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");
634 continue;
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");
641 continue;
646 if ((node.kind & B_BUFFER_PRODUCER) != 0) {
647 media_output outputs[16];
648 int32 count = 0;
649 if (fMediaRoster->GetConnectedOutputsFor(node, outputs, 16,
650 &count) != B_OK) {
651 printf("MediaAddonServer::_DestroyInstantiatedFlavors couldn't "
652 "get connected outputs\n");
653 continue;
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");
662 continue;
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");
669 continue;
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
680 snooze(50000);
683 info.active_flavors.clear();
687 void
688 MediaAddonServer::_PutAddonIfPossible(AddOnInfo& info)
690 if (info.addon && info.active_flavors.empty()) {
691 gDormantNodeManager->PutAddOn(info.id);
692 info.addon = NULL;
697 void
698 MediaAddonServer::_InstantiatePhysicalInputsAndOutputs(AddOnInfo& info)
700 CALLED();
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);
708 continue;
710 if ((flavorinfo->kinds & (B_PHYSICAL_INPUT | B_PHYSICAL_OUTPUT)) != 0) {
711 media_node node;
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);
726 } else {
727 TRACE("Node created!\n");
728 info.active_flavors.push_back(node);
735 void
736 MediaAddonServer::_InstantiateAutostartFlavors(AddOnInfo& info)
738 if (!info.wants_autostart)
739 return;
741 for (int32 index = 0;; index++) {
742 TRACE("trying autostart of node %ld, index %ld\n", info.id, index);
744 BMediaNode* node;
745 int32 internalID;
746 bool hasMore;
747 status_t status = info.addon->AutoStart(index, &node, &internalID,
748 &hasMore);
749 if (status == B_MEDIA_ADDON_FAILED && hasMore)
750 continue;
751 else if (status != B_OK)
752 break;
754 printf("started node %" B_PRId32 "\n", index);
756 status = MediaRosterEx(fMediaRoster)->RegisterNode(node, info.id,
757 internalID);
758 if (status != B_OK) {
759 ERROR("failed to register node %" B_PRId32 "\n", index);
760 node->Release();
761 } else {
762 MediaRosterEx(fMediaRoster)->IncrementAddonFlavorInstancesCount(
763 info.id, internalID);
764 info.active_flavors.push_back(node->Node());
767 if (!hasMore)
768 return;
773 void
774 MediaAddonServer::_AddOnRemoved(ino_t fileNode)
776 // TODO: locking?
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);
782 return;
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;
795 } else {
796 AddOnInfo& info = foundInfo->second;
797 oldFlavorCount = info.flavor_count;
799 _DestroyInstantiatedFlavors(info);
800 _PutAddonIfPossible(info);
802 if (info.addon) {
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);
816 // #pragma mark -
820 main()
822 new MediaAddonServer(B_MEDIA_ADDON_SERVER_SIGNATURE);
823 be_app->Run();
824 delete be_app;
825 return 0;