1 /*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
11 *
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
18 * the distribution.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 *
28 */
29
30
31 /* to comply with the license above, do not remove the following line */
32 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 "
33 "Marcus Overhagen <Marcus@Overhagen.de>";
34
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include <Alert.h>
40 #include <Autolock.h>
41 #include <Directory.h>
42 #include <Roster.h>
43 #include <MediaDefs.h>
44 #include <MediaFormats.h>
45 #include <Messenger.h>
46 #include <Server.h>
47
48 #include <syscalls.h>
49
50 #include "AppManager.h"
51 #include "BufferManager.h"
52 #include "DataExchange.h"
53 #include "MediaDebug.h"
54 #include "MediaFilesManager.h"
55 #include "MediaMisc.h"
56 #include "NodeManager.h"
57 #include "NotificationManager.h"
58 #include "ServerInterface.h"
59 #include "media_server.h"
60
61
62 AppManager* gAppManager;
63 BufferManager* gBufferManager;
64 MediaFilesManager* gMediaFilesManager;
65 NodeManager* gNodeManager;
66 NotificationManager* gNotificationManager;
67
68
69 #define REPLY_TIMEOUT ((bigtime_t)500000)
70
71
72 class ServerApp : public BServer {
73 public:
74 ServerApp(status_t& error);
75 virtual ~ServerApp();
76
77 protected:
78 virtual void ArgvReceived(int32 argc, char** argv);
79 virtual void ReadyToRun();
80 virtual bool QuitRequested();
81 virtual void MessageReceived(BMessage* message);
82
83 private:
84 void _HandleMessage(int32 code, const void* data,
85 size_t size);
86 void _LaunchAddOnServer();
87 void _QuitAddOnServer();
88
89 private:
_ControlPort() const90 port_id _ControlPort() const { return fControlPort; }
91
92 static int32 _ControlThread(void* arg);
93
94 BLocker fLocker;
95 port_id fControlPort;
96 thread_id fControlThread;
97 };
98
99
ServerApp(status_t & error)100 ServerApp::ServerApp(status_t& error)
101 :
102 BServer(B_MEDIA_SERVER_SIGNATURE, true, &error),
103 fLocker("media server locker")
104 {
105 gNotificationManager = new NotificationManager;
106 gBufferManager = new BufferManager;
107 gAppManager = new AppManager;
108 gNodeManager = new NodeManager;
109 gMediaFilesManager = new MediaFilesManager;
110
111 fControlPort = create_port(64, MEDIA_SERVER_PORT_NAME);
112 fControlThread = spawn_thread(_ControlThread, "media_server control", 105,
113 this);
114 resume_thread(fControlThread);
115
116 if (be_roster->StartWatching(BMessenger(this, this),
117 B_REQUEST_QUIT) != B_OK) {
118 TRACE("ServerApp: Can't find the registrar.");
119 }
120 }
121
122
~ServerApp()123 ServerApp::~ServerApp()
124 {
125 TRACE("ServerApp::~ServerApp()\n");
126
127 delete_port(fControlPort);
128 wait_for_thread(fControlThread, NULL);
129
130 if (be_roster->StopWatching(BMessenger(this, this)) != B_OK)
131 TRACE("ServerApp: Can't unregister roster notifications.");
132
133 delete gNotificationManager;
134 delete gBufferManager;
135 delete gAppManager;
136 delete gNodeManager;
137 delete gMediaFilesManager;
138 }
139
140
141 void
ReadyToRun()142 ServerApp::ReadyToRun()
143 {
144 gNodeManager->LoadState();
145
146 // make sure any previous media_addon_server is gone
147 _QuitAddOnServer();
148 // and start a new one
149 _LaunchAddOnServer();
150
151 }
152
153
154 bool
QuitRequested()155 ServerApp::QuitRequested()
156 {
157 TRACE("ServerApp::QuitRequested()\n");
158 gMediaFilesManager->SaveState();
159 gNodeManager->SaveState();
160
161 _QuitAddOnServer();
162
163 return true;
164 }
165
166
167 void
ArgvReceived(int32 argc,char ** argv)168 ServerApp::ArgvReceived(int32 argc, char **argv)
169 {
170 for (int arg = 1; arg < argc; arg++) {
171 if (strstr(argv[arg], "dump") != NULL) {
172 gAppManager->Dump();
173 gNodeManager->Dump();
174 gBufferManager->Dump();
175 gNotificationManager->Dump();
176 gMediaFilesManager->Dump();
177 }
178 if (strstr(argv[arg], "buffer") != NULL)
179 gBufferManager->Dump();
180 if (strstr(argv[arg], "node") != NULL)
181 gNodeManager->Dump();
182 if (strstr(argv[arg], "files") != NULL)
183 gMediaFilesManager->Dump();
184 if (strstr(argv[arg], "quit") != NULL)
185 PostMessage(B_QUIT_REQUESTED);
186 }
187 }
188
189
190 void
_LaunchAddOnServer()191 ServerApp::_LaunchAddOnServer()
192 {
193 // Try to launch media_addon_server by mime signature.
194 // If it fails (for example on the Live CD, where the executable
195 // hasn't yet been mimesetted), try from this application's
196 // directory
197 status_t err = be_roster->Launch(B_MEDIA_ADDON_SERVER_SIGNATURE);
198 if (err == B_OK)
199 return;
200
201 app_info info;
202 BEntry entry;
203 BDirectory dir;
204 entry_ref ref;
205
206 err = GetAppInfo(&info);
207 err |= entry.SetTo(&info.ref);
208 err |= entry.GetParent(&entry);
209 err |= dir.SetTo(&entry);
210 err |= entry.SetTo(&dir, "media_addon_server");
211 err |= entry.GetRef(&ref);
212
213 if (err == B_OK)
214 be_roster->Launch(&ref);
215 if (err == B_OK)
216 return;
217
218 BAlert* alert = new BAlert("media_server", "Launching media_addon_server "
219 "failed.\n\nmedia_server will terminate", "OK");
220 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
221 alert->Go();
222 fprintf(stderr, "Launching media_addon_server (%s) failed: %s\n",
223 B_MEDIA_ADDON_SERVER_SIGNATURE, strerror(err));
224 exit(1);
225 }
226
227
228 void
_QuitAddOnServer()229 ServerApp::_QuitAddOnServer()
230 {
231 // nothing to do if it's already terminated
232 if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE))
233 return;
234
235 // send a quit request to the media_addon_server
236 BMessenger msger(B_MEDIA_ADDON_SERVER_SIGNATURE);
237 if (!msger.IsValid()) {
238 ERROR("Trouble terminating media_addon_server. Messenger invalid\n");
239 } else {
240 BMessage msg(B_QUIT_REQUESTED);
241 status_t err = msger.SendMessage(&msg, (BHandler *)NULL, 2000000);
242 // 2 sec timeout
243 if (err != B_OK) {
244 ERROR("Trouble terminating media_addon_server (2): %s\n",
245 strerror(err));
246 }
247 }
248
249 // wait 5 seconds for it to terminate
250 for (int i = 0; i < 50; i++) {
251 if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE))
252 return;
253 snooze(100000); // 100 ms
254 }
255
256 // try to kill it (or many of them), up to 10 seconds
257 for (int i = 0; i < 50; i++) {
258 team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
259 if (id < 0)
260 break;
261 kill_team(id);
262 snooze(200000); // 200 ms
263 }
264
265 if (be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) {
266 ERROR("Trouble terminating media_addon_server, it's still running\n");
267 }
268 }
269
270
271 void
_HandleMessage(int32 code,const void * data,size_t size)272 ServerApp::_HandleMessage(int32 code, const void* data, size_t size)
273 {
274 TRACE("ServerApp::HandleMessage %#" B_PRIx32 " enter\n", code);
275 switch (code) {
276 case SERVER_CHANGE_FLAVOR_INSTANCES_COUNT:
277 {
278 const server_change_flavor_instances_count_request& request
279 = *static_cast<
280 const server_change_flavor_instances_count_request*>(data);
281 server_change_flavor_instances_count_reply reply;
282 status_t status = B_BAD_VALUE;
283
284 if (request.delta == 1) {
285 status = gNodeManager->IncrementFlavorInstancesCount(
286 request.add_on_id, request.flavor_id, request.team);
287 } else if (request.delta == -1) {
288 status = gNodeManager->DecrementFlavorInstancesCount(
289 request.add_on_id, request.flavor_id, request.team);
290 }
291 request.SendReply(status, &reply, sizeof(reply));
292 break;
293 }
294
295 case SERVER_RESCAN_DEFAULTS:
296 {
297 gNodeManager->RescanDefaultNodes();
298 break;
299 }
300
301 case SERVER_REGISTER_APP:
302 {
303 const server_register_app_request& request = *static_cast<
304 const server_register_app_request*>(data);
305 server_register_app_reply reply;
306
307 status_t status = gAppManager->RegisterTeam(request.team,
308 request.messenger);
309 request.SendReply(status, &reply, sizeof(reply));
310 break;
311 }
312
313 case SERVER_UNREGISTER_APP:
314 {
315 const server_unregister_app_request& request = *static_cast<
316 const server_unregister_app_request*>(data);
317 server_unregister_app_reply reply;
318
319 status_t status = gAppManager->UnregisterTeam(request.team);
320 request.SendReply(status, &reply, sizeof(reply));
321 break;
322 }
323
324 case SERVER_GET_ADD_ON_REF:
325 {
326 const server_get_add_on_ref_request& request = *static_cast<
327 const server_get_add_on_ref_request*>(data);
328 server_get_add_on_ref_reply reply;
329
330 entry_ref ref;
331 reply.result = gNodeManager->GetAddOnRef(request.add_on_id, &ref);
332 reply.ref = ref;
333
334 request.SendReply(reply.result, &reply, sizeof(reply));
335 break;
336 }
337
338 case SERVER_NODE_ID_FOR:
339 {
340 const server_node_id_for_request& request
341 = *static_cast<const server_node_id_for_request*>(data);
342 server_node_id_for_reply reply;
343
344 status_t status = gNodeManager->FindNodeID(request.port,
345 &reply.node_id);
346 request.SendReply(status, &reply, sizeof(reply));
347 break;
348 }
349
350 case SERVER_GET_LIVE_NODE_INFO:
351 {
352 const server_get_live_node_info_request& request = *static_cast<
353 const server_get_live_node_info_request*>(data);
354 server_get_live_node_info_reply reply;
355
356 status_t status = gNodeManager->GetLiveNodeInfo(request.node,
357 &reply.live_info);
358 request.SendReply(status, &reply, sizeof(reply));
359 break;
360 }
361
362 case SERVER_GET_LIVE_NODES:
363 {
364 const server_get_live_nodes_request& request
365 = *static_cast<const server_get_live_nodes_request*>(data);
366 server_get_live_nodes_reply reply;
367 LiveNodeList nodes;
368
369 status_t status = gNodeManager->GetLiveNodes(nodes,
370 request.max_count,
371 request.has_input ? &request.input_format : NULL,
372 request.has_output ? &request.output_format : NULL,
373 request.has_name ? request.name : NULL, request.require_kinds);
374
375 reply.count = nodes.size();
376 reply.area = -1;
377
378 live_node_info* infos = reply.live_info;
379 area_id area = -1;
380
381 if (reply.count > MAX_LIVE_INFO) {
382 // We create an area here, and transfer it to the client
383 size_t size = (reply.count * sizeof(live_node_info)
384 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
385
386 area = create_area("get live nodes", (void**)&infos,
387 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
388 if (area < 0) {
389 reply.area = area;
390 reply.count = 0;
391 }
392 }
393
394 for (int32 index = 0; index < reply.count; index++)
395 infos[index] = nodes[index];
396
397 if (area >= 0) {
398 // transfer the area to the target team
399 reply.area = _kern_transfer_area(area, &reply.address,
400 B_ANY_ADDRESS, request.team);
401 if (reply.area < 0) {
402 delete_area(area);
403 reply.count = 0;
404 }
405 }
406
407 status = request.SendReply(status, &reply, sizeof(reply));
408 if (status != B_OK && reply.area >= 0) {
409 // if we couldn't send the message, delete the area
410 delete_area(reply.area);
411 }
412 break;
413 }
414
415 case SERVER_GET_NODE_FOR:
416 {
417 const server_get_node_for_request& request
418 = *static_cast<const server_get_node_for_request*>(data);
419 server_get_node_for_reply reply;
420
421 status_t status = gNodeManager->GetCloneForID(request.node_id,
422 request.team, &reply.clone);
423 request.SendReply(status, &reply, sizeof(reply));
424 break;
425 }
426
427 case SERVER_RELEASE_NODE:
428 {
429 const server_release_node_request& request
430 = *static_cast<const server_release_node_request*>(data);
431 server_release_node_reply reply;
432
433 status_t status = gNodeManager->ReleaseNode(request.node,
434 request.team);
435 request.SendReply(status, &reply, sizeof(reply));
436 break;
437 }
438
439 case SERVER_RELEASE_NODE_ALL:
440 {
441 const server_release_node_request& request
442 = *static_cast<const server_release_node_request*>(data);
443 server_release_node_reply reply;
444
445 status_t status = gNodeManager->ReleaseNodeAll(request.node.node);
446 request.SendReply(status, &reply, sizeof(reply));
447 break;
448 }
449
450 case SERVER_REGISTER_NODE:
451 {
452 const server_register_node_request& request
453 = *static_cast<const server_register_node_request*>(data);
454 server_register_node_reply reply;
455
456 status_t status = gNodeManager->RegisterNode(request.add_on_id,
457 request.flavor_id, request.name, request.kinds, request.port,
458 request.team, request.timesource_id, &reply.node_id);
459 request.SendReply(status, &reply, sizeof(reply));
460 break;
461 }
462
463 case SERVER_UNREGISTER_NODE:
464 {
465 const server_unregister_node_request& request
466 = *static_cast<const server_unregister_node_request*>(data);
467 server_unregister_node_reply reply;
468
469 status_t status = gNodeManager->UnregisterNode(request.node_id,
470 request.team, &reply.add_on_id, &reply.flavor_id);
471 request.SendReply(status, &reply, sizeof(reply));
472 break;
473 }
474
475 case SERVER_PUBLISH_INPUTS:
476 {
477 const server_publish_inputs_request& request
478 = *static_cast<const server_publish_inputs_request*>(data);
479 server_publish_inputs_reply reply;
480 status_t status;
481
482 if (request.count <= MAX_INPUTS) {
483 status = gNodeManager->PublishInputs(request.node,
484 request.inputs, request.count);
485 } else {
486 media_input* inputs;
487 area_id clone;
488 clone = clone_area("media_inputs clone", (void**)&inputs,
489 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request.area);
490 if (clone < B_OK) {
491 ERROR("SERVER_PUBLISH_INPUTS: failed to clone area, "
492 "error %#" B_PRIx32 "\n", clone);
493 status = clone;
494 } else {
495 status = gNodeManager->PublishInputs(request.node, inputs,
496 request.count);
497 delete_area(clone);
498 }
499 }
500 request.SendReply(status, &reply, sizeof(reply));
501 break;
502 }
503
504 case SERVER_PUBLISH_OUTPUTS:
505 {
506 const server_publish_outputs_request& request
507 = *static_cast<const server_publish_outputs_request*>(data);
508 server_publish_outputs_reply reply;
509 status_t status;
510
511 if (request.count <= MAX_OUTPUTS) {
512 status = gNodeManager->PublishOutputs(request.node,
513 request.outputs, request.count);
514 } else {
515 media_output* outputs;
516 area_id clone;
517 clone = clone_area("media_outputs clone", (void**)&outputs,
518 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request.area);
519 if (clone < B_OK) {
520 ERROR("SERVER_PUBLISH_OUTPUTS: failed to clone area, "
521 "error %#" B_PRIx32 "\n", clone);
522 status = clone;
523 } else {
524 status = gNodeManager->PublishOutputs(request.node, outputs,
525 request.count);
526 delete_area(clone);
527 }
528 }
529 request.SendReply(status, &reply, sizeof(reply));
530 break;
531 }
532
533 case SERVER_GET_NODE:
534 {
535 const server_get_node_request& request
536 = *static_cast<const server_get_node_request*>(data);
537 server_get_node_reply reply;
538
539 status_t status = gNodeManager->GetClone(request.type, request.team,
540 &reply.node, reply.input_name, &reply.input_id);
541 request.SendReply(status, &reply, sizeof(reply));
542 break;
543 }
544
545 case SERVER_SET_NODE:
546 {
547 const server_set_node_request& request
548 = *static_cast<const server_set_node_request*>(data);
549 server_set_node_reply reply;
550
551 status_t status = gNodeManager->SetDefaultNode(request.type,
552 request.use_node ? &request.node : NULL,
553 request.use_dni ? &request.dni : NULL,
554 request.use_input ? &request.input : NULL);
555 request.SendReply(status, &reply, sizeof(reply));
556 break;
557 }
558
559 case SERVER_GET_DORMANT_NODE_FOR:
560 {
561 const server_get_dormant_node_for_request& request
562 = *static_cast<const server_get_dormant_node_for_request*>(
563 data);
564 server_get_dormant_node_for_reply reply;
565
566 status_t status = gNodeManager->GetDormantNodeInfo(request.node,
567 &reply.node_info);
568 request.SendReply(status, &reply, sizeof(reply));
569 break;
570 }
571
572 case SERVER_GET_INSTANCES_FOR:
573 {
574 const server_get_instances_for_request& request
575 = *static_cast<const server_get_instances_for_request*>(data);
576 server_get_instances_for_reply reply;
577
578 status_t status = gNodeManager->GetInstances(request.add_on_id,
579 request.flavor_id, reply.node_id, &reply.count,
580 min_c(request.max_count, MAX_NODE_ID));
581 if (reply.count == MAX_NODE_ID
582 && request.max_count > MAX_NODE_ID) {
583 // TODO: might be fixed by using an area
584 PRINT(1, "Warning: SERVER_GET_INSTANCES_FOR: returning "
585 "possibly truncated list of node id's\n");
586 }
587 request.SendReply(status, &reply, sizeof(reply));
588 break;
589 }
590
591 case SERVER_SET_NODE_TIMESOURCE:
592 {
593 const server_set_node_timesource_request& request
594 = *static_cast<const server_set_node_timesource_request*>(data);
595 server_set_node_timesource_reply reply;
596 status_t result = gNodeManager->SetNodeTimeSource(request.node_id,
597 request.timesource_id);
598 request.SendReply(result, &reply, sizeof(reply));
599 break;
600 }
601
602 case SERVER_REGISTER_ADD_ON:
603 {
604 const server_register_add_on_request& request = *static_cast<
605 const server_register_add_on_request*>(data);
606 server_register_add_on_reply reply;
607
608 gNodeManager->RegisterAddOn(request.ref, &reply.add_on_id);
609 request.SendReply(B_OK, &reply, sizeof(reply));
610 break;
611 }
612
613 case SERVER_UNREGISTER_ADD_ON:
614 {
615 const server_unregister_add_on_command& request = *static_cast<
616 const server_unregister_add_on_command*>(data);
617 gNodeManager->UnregisterAddOn(request.add_on_id);
618 break;
619 }
620
621 case SERVER_REGISTER_DORMANT_NODE:
622 {
623 const server_register_dormant_node_command& command
624 = *static_cast<const server_register_dormant_node_command*>(
625 data);
626 if (command.purge_id > 0)
627 gNodeManager->InvalidateDormantFlavorInfo(command.purge_id);
628
629 dormant_flavor_info dormantFlavorInfo;
630 status_t status = dormantFlavorInfo.Unflatten(command.type,
631 command.flattened_data, command.flattened_size);
632 if (status == B_OK)
633 gNodeManager->AddDormantFlavorInfo(dormantFlavorInfo);
634 break;
635 }
636
637 case SERVER_GET_DORMANT_NODES:
638 {
639 const server_get_dormant_nodes_request& request
640 = *static_cast<const server_get_dormant_nodes_request*>(data);
641
642 server_get_dormant_nodes_reply reply;
643 reply.count = request.max_count;
644
645 dormant_node_info* infos
646 = new(std::nothrow) dormant_node_info[reply.count];
647 if (infos != NULL) {
648 reply.result = gNodeManager->GetDormantNodes(infos,
649 &reply.count,
650 request.has_input ? &request.input_format : NULL,
651 request.has_output ? &request.output_format : NULL,
652 request.has_name ? request.name : NULL,
653 request.require_kinds, request.deny_kinds);
654 } else
655 reply.result = B_NO_MEMORY;
656
657 if (reply.result != B_OK)
658 reply.count = 0;
659
660 request.SendReply(reply.result, &reply, sizeof(reply));
661 if (reply.count > 0) {
662 write_port(request.reply_port, 0, infos,
663 reply.count * sizeof(dormant_node_info));
664 }
665 delete[] infos;
666 break;
667 }
668
669 case SERVER_GET_DORMANT_FLAVOR_INFO:
670 {
671 const server_get_dormant_flavor_info_request& request
672 = *static_cast<const server_get_dormant_flavor_info_request*>(
673 data);
674 dormant_flavor_info dormantFlavorInfo;
675
676 status_t status = gNodeManager->GetDormantFlavorInfoFor(
677 request.add_on_id, request.flavor_id, &dormantFlavorInfo);
678 if (status != B_OK) {
679 server_get_dormant_flavor_info_reply reply;
680 reply.result = status;
681 request.SendReply(reply.result, &reply, sizeof(reply));
682 } else {
683 size_t replySize
684 = sizeof(server_get_dormant_flavor_info_reply)
685 + dormantFlavorInfo.FlattenedSize();
686 server_get_dormant_flavor_info_reply* reply
687 = (server_get_dormant_flavor_info_reply*)malloc(
688 replySize);
689 if (reply != NULL) {
690 reply->type = dormantFlavorInfo.TypeCode();
691 reply->flattened_size = dormantFlavorInfo.FlattenedSize();
692 reply->result = dormantFlavorInfo.Flatten(
693 reply->flattened_data, reply->flattened_size);
694
695 request.SendReply(reply->result, reply, replySize);
696 free(reply);
697 } else {
698 server_get_dormant_flavor_info_reply reply;
699 reply.result = B_NO_MEMORY;
700 request.SendReply(reply.result, &reply, sizeof(reply));
701 }
702 }
703 break;
704 }
705
706 case SERVER_SET_NODE_CREATOR:
707 {
708 const server_set_node_creator_request& request
709 = *static_cast<const server_set_node_creator_request*>(data);
710 server_set_node_creator_reply reply;
711 status_t status = gNodeManager->SetNodeCreator(request.node,
712 request.creator);
713 request.SendReply(status, &reply, sizeof(reply));
714 break;
715 }
716
717 case SERVER_GET_SHARED_BUFFER_AREA:
718 {
719 const server_get_shared_buffer_area_request& request
720 = *static_cast<const server_get_shared_buffer_area_request*>(
721 data);
722 server_get_shared_buffer_area_reply reply;
723
724 reply.area = gBufferManager->SharedBufferListArea();
725 request.SendReply(reply.area >= 0 ? B_OK : reply.area, &reply,
726 sizeof(reply));
727 break;
728 }
729
730 case SERVER_REGISTER_BUFFER:
731 {
732 const server_register_buffer_request& request
733 = *static_cast<const server_register_buffer_request*>(data);
734 server_register_buffer_reply reply;
735 status_t status;
736
737 if (request.info.buffer == 0) {
738 reply.info = request.info;
739 // size, offset, flags, area is kept
740 // get a new beuffer id into reply.info.buffer
741 status = gBufferManager->RegisterBuffer(request.team,
742 request.info.size, request.info.flags,
743 request.info.offset, request.info.area,
744 &reply.info.buffer);
745 } else {
746 reply.info = request.info; // buffer id is kept
747 status = gBufferManager->RegisterBuffer(request.team,
748 request.info.buffer, &reply.info.size, &reply.info.flags,
749 &reply.info.offset, &reply.info.area);
750 }
751 request.SendReply(status, &reply, sizeof(reply));
752 break;
753 }
754
755 case SERVER_UNREGISTER_BUFFER:
756 {
757 const server_unregister_buffer_command& request = *static_cast<
758 const server_unregister_buffer_command*>(data);
759
760 gBufferManager->UnregisterBuffer(request.team, request.buffer_id);
761 break;
762 }
763
764 case SERVER_GET_MEDIA_FILE_TYPES:
765 {
766 const server_get_media_types_request& request
767 = *static_cast<const server_get_media_types_request*>(data);
768
769 server_get_media_types_reply reply;
770 area_id area = gMediaFilesManager->GetTypesArea(reply.count);
771 if (area >= 0) {
772 // transfer the area to the target team
773 reply.area = _kern_transfer_area(area, &reply.address,
774 B_ANY_ADDRESS, request.team);
775 if (reply.area < 0) {
776 delete_area(area);
777 reply.area = B_ERROR;
778 reply.count = 0;
779 }
780 }
781
782 status_t status = request.SendReply(
783 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply));
784 if (status != B_OK) {
785 // if we couldn't send the message, delete the area
786 delete_area(reply.area);
787 }
788 break;
789 }
790
791 case SERVER_GET_MEDIA_FILE_ITEMS:
792 {
793 const server_get_media_items_request& request
794 = *static_cast<const server_get_media_items_request*>(data);
795
796 server_get_media_items_reply reply;
797 area_id area = gMediaFilesManager->GetItemsArea(request.type,
798 reply.count);
799 if (area >= 0) {
800 // transfer the area to the target team
801 reply.area = _kern_transfer_area(area, &reply.address,
802 B_ANY_ADDRESS, request.team);
803 if (reply.area < 0) {
804 delete_area(area);
805 reply.area = B_ERROR;
806 reply.count = 0;
807 }
808 } else
809 reply.area = area;
810
811 status_t status = request.SendReply(
812 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply));
813 if (status != B_OK) {
814 // if we couldn't send the message, delete the area
815 delete_area(reply.area);
816 }
817 break;
818 }
819
820 case SERVER_GET_REF_FOR:
821 {
822 const server_get_ref_for_request& request
823 = *static_cast<const server_get_ref_for_request*>(data);
824 server_get_ref_for_reply reply;
825 entry_ref* ref;
826
827 status_t status = gMediaFilesManager->GetRefFor(request.type,
828 request.item, &ref);
829 if (status == B_OK)
830 reply.ref = *ref;
831
832 request.SendReply(status, &reply, sizeof(reply));
833 break;
834 }
835
836 case SERVER_SET_REF_FOR:
837 {
838 const server_set_ref_for_request& request
839 = *static_cast<const server_set_ref_for_request*>(data);
840 server_set_ref_for_reply reply;
841 entry_ref ref = request.ref;
842
843 status_t status = gMediaFilesManager->SetRefFor(request.type,
844 request.item, ref);
845 request.SendReply(status, &reply, sizeof(reply));
846 break;
847 }
848
849 case SERVER_INVALIDATE_MEDIA_ITEM:
850 {
851 const server_invalidate_item_request& request
852 = *static_cast<const server_invalidate_item_request*>(data);
853 server_invalidate_item_reply reply;
854
855 status_t status = gMediaFilesManager->InvalidateItem(request.type,
856 request.item);
857 request.SendReply(status, &reply, sizeof(reply));
858 break;
859 }
860
861 case SERVER_REMOVE_MEDIA_ITEM:
862 {
863 const server_remove_media_item_request& request
864 = *static_cast<const server_remove_media_item_request*>(data);
865 server_remove_media_item_reply reply;
866
867 status_t status = gMediaFilesManager->RemoveItem(request.type,
868 request.item);
869 request.SendReply(status, &reply, sizeof(reply));
870 break;
871 }
872
873 case SERVER_GET_ITEM_AUDIO_GAIN:
874 {
875 const server_get_item_audio_gain_request& request
876 = *static_cast<const server_get_item_audio_gain_request*>(data);
877 server_get_item_audio_gain_reply reply;
878
879 status_t status = gMediaFilesManager->GetAudioGainFor(request.type,
880 request.item, &reply.gain);
881 request.SendReply(status, &reply, sizeof(reply));
882 break;
883 }
884
885 case SERVER_SET_ITEM_AUDIO_GAIN:
886 {
887 const server_set_item_audio_gain_request& request
888 = *static_cast<const server_set_item_audio_gain_request*>(data);
889 server_set_ref_for_reply reply;
890
891 status_t status = gMediaFilesManager->SetAudioGainFor(request.type,
892 request.item, request.gain);
893 request.SendReply(status, &reply, sizeof(reply));
894 break;
895 }
896
897 default:
898 printf("media_server: received unknown message code %#08" B_PRIx32
899 "\n", code);
900 }
901 TRACE("ServerApp::HandleMessage %#" B_PRIx32 " leave\n", code);
902 }
903
904
905 status_t
_ControlThread(void * _server)906 ServerApp::_ControlThread(void* _server)
907 {
908 ServerApp* server = (ServerApp*)_server;
909
910 char data[B_MEDIA_MESSAGE_SIZE];
911 ssize_t size;
912 int32 code;
913 while ((size = read_port_etc(server->_ControlPort(), &code, data,
914 sizeof(data), 0, 0)) > 0) {
915 server->_HandleMessage(code, data, size);
916 }
917
918 return B_OK;
919 }
920
921
922 void
MessageReceived(BMessage * msg)923 ServerApp::MessageReceived(BMessage* msg)
924 {
925 TRACE("ServerApp::MessageReceived %" B_PRIu32 " enter\n", msg->what);
926 switch (msg->what) {
927 case MEDIA_SERVER_REQUEST_NOTIFICATIONS:
928 case MEDIA_SERVER_CANCEL_NOTIFICATIONS:
929 case MEDIA_SERVER_SEND_NOTIFICATIONS:
930 gNotificationManager->EnqueueMessage(msg);
931 break;
932
933 case MEDIA_FILES_MANAGER_SAVE_TIMER:
934 gMediaFilesManager->TimerMessage();
935 break;
936
937 case MEDIA_SERVER_ADD_SYSTEM_BEEP_EVENT:
938 gMediaFilesManager->HandleAddSystemBeepEvent(msg);
939 break;
940
941 case MEDIA_SERVER_RESCAN_COMPLETED:
942 gAppManager->NotifyRosters();
943 break;
944
945 case B_SOME_APP_QUIT:
946 {
947 BString mimeSig;
948 if (msg->FindString("be:signature", &mimeSig) != B_OK)
949 return;
950
951 if (mimeSig == B_MEDIA_ADDON_SERVER_SIGNATURE)
952 gNodeManager->CleanupDormantFlavorInfos();
953
954 team_id id;
955 if (msg->FindInt32("be:team", &id) == B_OK
956 && gAppManager->HasTeam(id)) {
957 gAppManager->UnregisterTeam(id);
958 }
959 break;
960 }
961
962 default:
963 BApplication::MessageReceived(msg);
964 TRACE("\nmedia_server: unknown message received!\n");
965 break;
966 }
967 TRACE("ServerApp::MessageReceived %" B_PRIu32 " leave\n", msg->what);
968 }
969
970
971 // #pragma mark -
972
973
974 int
main()975 main()
976 {
977 status_t status;
978 ServerApp app(status);
979
980 if (status == B_OK)
981 app.Run();
982
983 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE;
984 }
985