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