xref: /haiku/src/servers/media/media_server.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
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 /* to comply with the license above, do not remove the following line */
31 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>";
32 
33 #include <Application.h>
34 #include <Roster.h>
35 #include <Messenger.h>
36 #include <MediaDefs.h>
37 #include <MediaFormats.h>
38 #include <Autolock.h>
39 #include <Alert.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "MMediaFilesManager.h"
44 #include "NotificationManager.h"
45 #include "ServerInterface.h"
46 #include "DataExchange.h"
47 #include "BufferManager.h"
48 #include "NodeManager.h"
49 #include "AddOnManager.h"
50 #include "AppManager.h"
51 #include "FormatManager.h"
52 #include "MediaMisc.h"
53 #include "media_server.h"
54 #include "debug.h"
55 
56 /*
57  *
58  * An implementation of a new media_server for the OpenBeOS MediaKit
59  * Started by Marcus Overhagen <marcus@overhagen.de> on 2001-10-25
60  *
61  */
62 
63 AddOnManager *			gAddOnManager;
64 AppManager *			gAppManager;
65 BufferManager *			gBufferManager;
66 FormatManager *			gFormatManager;
67 MMediaFilesManager *	gMMediaFilesManager;
68 NodeManager *			gNodeManager;
69 NotificationManager *	gNotificationManager;
70 
71 namespace BPrivate { namespace media {
72 	extern team_id team;
73 } } // BPrivate::media
74 
75 
76 #define REPLY_TIMEOUT ((bigtime_t)500000)
77 
78 class ServerApp : BApplication
79 {
80 public:
81 	ServerApp();
82 	~ServerApp();
83 
84 private:
85 	bool		QuitRequested();
86 	void		HandleMessage(int32 code, void *data, size_t size);
87 	void		ArgvReceived(int32 argc, char **argv);
88 
89 	void		StartAddonServer();
90 	void		TerminateAddonServer();
91 
92 /* functionality not yet implemented
93 00014a00 T _ServerApp::_ServerApp(void)
94 00014e1c T _ServerApp::~_ServerApp(void)
95 00014ff4 T _ServerApp::MessageReceived(BMessage *);
96 00015840 T _ServerApp::QuitRequested(void)
97 00015b50 T _ServerApp::_DoNotify(command_data *)
98 00015d18 T _ServerApp::_UnregisterApp(long, bool)
99 00018e90 T _ServerApp::AddOnHost(void)
100 00019530 T _ServerApp::AboutRequested(void)
101 00019d04 T _ServerApp::AddPurgableBufferGroup(long, long, long, void *)
102 00019db8 T _ServerApp::CancelPurgableBufferGroupCleanup(long)
103 00019e50 T _ServerApp::DirtyWork(void)
104 0001a4bc T _ServerApp::ArgvReceived(long, char **)
105 0001a508 T _ServerApp::CleanupPurgedBufferGroup(_ServerApp::purgable_buffer_group const &, bool)
106 0001a5dc T _ServerApp::DirtyWorkLaunch(void *)
107 0001a634 T _ServerApp::SetQuitMode(bool)
108 0001a648 T _ServerApp::IsQuitMode(void) const
109 0001a658 T _ServerApp::BroadcastCurrentStateTo(BMessenger &)
110 0001adcc T _ServerApp::ReadyToRun(void)
111 */
112 
113 	static int32 controlthread(void *arg);
114 
115 private:
116 	port_id		control_port;
117 	thread_id	control_thread;
118 
119 	BLocker *fLocker;
120 
121 	virtual void MessageReceived(BMessage *msg);
122 	virtual void ReadyToRun();
123 	typedef BApplication inherited;
124 };
125 
126 ServerApp::ServerApp()
127  	: BApplication(B_MEDIA_SERVER_SIGNATURE),
128 	fLocker(new BLocker("media server locker"))
129 {
130  	gNotificationManager = new NotificationManager;
131  	gBufferManager = new BufferManager;
132 	gAppManager = new AppManager;
133 	gNodeManager = new NodeManager;
134 	gMMediaFilesManager = new MMediaFilesManager;
135 	gFormatManager = new FormatManager;
136 	gAddOnManager = new AddOnManager;
137 
138 	control_port = create_port(64, MEDIA_SERVER_PORT_NAME);
139 	control_thread = spawn_thread(controlthread, "media_server control", 105, this);
140 	resume_thread(control_thread);
141 }
142 
143 void ServerApp::ReadyToRun()
144 {
145 	gNodeManager->LoadState();
146 	gFormatManager->LoadState();
147 
148 	// make sure any previous media_addon_server is gone
149 	TerminateAddonServer();
150 	// and start a new one
151 	StartAddonServer();
152 
153 	gAddOnManager->LoadState();
154 }
155 
156 ServerApp::~ServerApp()
157 {
158 	TRACE("ServerApp::~ServerApp()\n");
159 	delete gAddOnManager;
160 	delete gNotificationManager;
161 	delete gBufferManager;
162 	delete gAppManager;
163 	delete gNodeManager;
164 	delete gMMediaFilesManager;
165 	delete gFormatManager;
166 	delete fLocker;
167 	delete_port(control_port);
168 	status_t err;
169 	wait_for_thread(control_thread,&err);
170 }
171 
172 
173 bool
174 ServerApp::QuitRequested()
175 {
176 	TRACE("ServerApp::QuitRequested()\n");
177 	gMMediaFilesManager->SaveState();
178 	gNodeManager->SaveState();
179 	gFormatManager->SaveState();
180 	gAddOnManager->SaveState();
181 	TerminateAddonServer();
182 	return true;
183 }
184 
185 
186 void ServerApp::ArgvReceived(int32 argc, char **argv)
187 {
188 	for (int arg = 1; arg < argc; arg++) {
189 		if (strstr(argv[arg], "dump")) {
190 			gAppManager->Dump();
191 			gNodeManager->Dump();
192 			gBufferManager->Dump();
193 			gNotificationManager->Dump();
194 			gMMediaFilesManager->Dump();
195 		}
196 		if (strstr(argv[arg], "buffer")) {
197 			gBufferManager->Dump();
198 		}
199 		if (strstr(argv[arg], "node")) {
200 			gNodeManager->Dump();
201 		}
202 		if (strstr(argv[arg], "quit")) {
203 			PostMessage(B_QUIT_REQUESTED);
204 		}
205 	}
206 }
207 
208 
209 void ServerApp::StartAddonServer()
210 {
211 	status_t err;
212 
213 	// launching media_addon_server from this application's directoy
214 	// should no longer be needed, we now can launch by mime signature
215 /*
216 	app_info info;
217 	BEntry entry;
218 	BDirectory dir;
219 	entry_ref ref;
220 
221 	err = GetAppInfo(&info);
222 	err |= entry.SetTo(&info.ref);
223 	err |= entry.GetParent(&entry);
224 	err |= dir.SetTo(&entry);
225 	err |= entry.SetTo(&dir, "media_addon_server");
226 	err |= entry.GetRef(&ref);
227 
228 	if (err == B_OK)
229 		be_roster->Launch(&ref);
230 	if (err == B_OK)
231 		return;
232 */
233 
234 	err = be_roster->Launch(B_MEDIA_ADDON_SERVER_SIGNATURE);
235 	if (err == B_OK)
236 		return;
237 
238 	(new BAlert("media_server", "Launching media_addon_server failed.\n\nmedia_server will terminate", "OK"))->Go();
239 	fprintf(stderr, "Launching media_addon_server (%s) failed: %s\n", B_MEDIA_ADDON_SERVER_SIGNATURE, strerror(err));
240 	exit(1);
241 }
242 
243 
244 void ServerApp::TerminateAddonServer()
245 {
246 	// nothing to do if it's already terminated
247 	if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE))
248 		return;
249 
250 	// send a quit request to the media_addon_server
251 	BMessenger msger(B_MEDIA_ADDON_SERVER_SIGNATURE);
252 	if (!msger.IsValid()) {
253 		ERROR("Trouble terminating media_addon_server. Messenger invalid\n");
254 	} else {
255 		BMessage msg(B_QUIT_REQUESTED);
256 		status_t err = msger.SendMessage(&msg, (BHandler *)NULL, 2000000 /* 2 sec timeout */);
257 		if (err) {
258 			ERROR("Trouble terminating media_addon_server (2). Error %d (%s)\n", err, strerror(err));
259 		}
260 	}
261 
262 	// wait 5 seconds for it to terminate
263 	for (int i = 0; i < 50; i++) {
264 		if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE))
265 			return;
266 		snooze(100000); // 100 ms
267 	}
268 
269 	// try to kill it (or many of them), up to 10 seconds
270 	for (int i = 0; i < 50; i++) {
271 		team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
272 		if (id < 0)
273 			break;
274 		kill_team(id);
275 		snooze(200000); // 200 ms
276 	}
277 
278 	if (be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) {
279 		ERROR("Trouble terminating media_addon_server, it's still running\n");
280 	}
281 }
282 
283 
284 void
285 ServerApp::HandleMessage(int32 code, void *data, size_t size)
286 {
287 	status_t rv;
288 	TRACE("ServerApp::HandleMessage %#lx enter\n", code);
289 	switch (code) {
290 		case SERVER_CHANGE_ADDON_FLAVOR_INSTANCES_COUNT:
291 		{
292 			const server_change_addon_flavor_instances_count_request *request = reinterpret_cast<const server_change_addon_flavor_instances_count_request *>(data);
293 			server_change_addon_flavor_instances_count_reply reply;
294 			ASSERT(request->delta == 1 || request->delta == -1);
295 			if (request->delta == 1)
296 				rv = gNodeManager->IncrementAddonFlavorInstancesCount(request->addonid,	request->flavorid, request->team);
297 			else
298 				rv = gNodeManager->DecrementAddonFlavorInstancesCount(request->addonid,	request->flavorid, request->team);
299 			request->SendReply(rv, &reply, sizeof(reply));
300 			break;
301 		}
302 
303 		case SERVER_RESCAN_DEFAULTS:
304 		{
305 			gNodeManager->RescanDefaultNodes();
306 			break;
307 		}
308 
309 		case SERVER_REGISTER_APP:
310 		{
311 			const server_register_app_request *request = reinterpret_cast<const server_register_app_request *>(data);
312 			server_register_app_reply reply;
313 			rv = gAppManager->RegisterTeam(request->team, request->messenger);
314 			request->SendReply(rv, &reply, sizeof(reply));
315 			break;
316 		}
317 
318 		case SERVER_UNREGISTER_APP:
319 		{
320 			const server_unregister_app_request *request = reinterpret_cast<const server_unregister_app_request *>(data);
321 			server_unregister_app_reply reply;
322 			rv = gAppManager->UnregisterTeam(request->team);
323 			request->SendReply(rv, &reply, sizeof(reply));
324 			break;
325 		}
326 
327 		case SERVER_GET_MEDIAADDON_REF:
328 		{
329 			server_get_mediaaddon_ref_request *msg = (server_get_mediaaddon_ref_request *)data;
330 			server_get_mediaaddon_ref_reply reply;
331 			entry_ref tempref;
332 			reply.result = gNodeManager->GetAddonRef(&tempref, msg->addonid);
333 			reply.ref = tempref;
334 			write_port(msg->reply_port, 0, &reply, sizeof(reply));
335 			break;
336 		}
337 
338 		case SERVER_NODE_ID_FOR:
339 		{
340 			const server_node_id_for_request *request = reinterpret_cast<const server_node_id_for_request *>(data);
341 			server_node_id_for_reply reply;
342 			rv = gNodeManager->FindNodeId(&reply.nodeid, request->port);
343 			request->SendReply(rv, &reply, sizeof(reply));
344 			break;
345 		}
346 
347 		case SERVER_GET_LIVE_NODE_INFO:
348 		{
349 			const server_get_live_node_info_request *request = reinterpret_cast<const server_get_live_node_info_request *>(data);
350 			server_get_live_node_info_reply reply;
351 			rv = gNodeManager->GetLiveNodeInfo(&reply.live_info, request->node);
352 			request->SendReply(rv, &reply, sizeof(reply));
353 			break;
354 		}
355 
356 		case SERVER_GET_LIVE_NODES:
357 		{
358 			const server_get_live_nodes_request *request = reinterpret_cast<const server_get_live_nodes_request *>(data);
359 			server_get_live_nodes_reply reply;
360 			Stack<live_node_info> livenodes;
361 			rv = gNodeManager->GetLiveNodes(
362 					&livenodes,
363 					request->maxcount,
364 					request->has_input ? &request->inputformat : NULL,
365 					request->has_output ? &request->outputformat : NULL,
366 					request->has_name ? request->name : NULL,
367 					request->require_kinds);
368 			reply.count = livenodes.CountItems();
369 			if (reply.count <= MAX_LIVE_INFO) {
370 				for (int32 index = 0; index < reply.count; index++)
371 					livenodes.Pop(&reply.live_info[index]);
372 				reply.area = -1;
373 			} else {
374 				// we create an area here, and pass it to the library, where it will be deleted.
375 				live_node_info *start_addr;
376 				size_t size;
377 				size = ((reply.count * sizeof(live_node_info)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
378 				reply.area = create_area("get live nodes", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
379 				if (reply.area < B_OK) {
380 					ERROR("SERVER_GET_LIVE_NODES: failed to create area, error %#lx\n", reply.area);
381 					reply.count = 0;
382 					rv = B_ERROR;
383 				} else {
384 					for (int32 index = 0; index < reply.count; index++)
385 						livenodes.Pop(&start_addr[index]);
386 				}
387 			}
388 			rv = request->SendReply(rv, &reply, sizeof(reply));
389 			if (rv != B_OK)
390 				delete_area(reply.area); // if we couldn't send the message, delete the area
391 			break;
392 		}
393 
394 		case SERVER_GET_NODE_FOR:
395 		{
396 			const server_get_node_for_request *request = reinterpret_cast<const server_get_node_for_request *>(data);
397 			server_get_node_for_reply reply;
398 			rv = gNodeManager->GetCloneForId(&reply.clone, request->nodeid, request->team);
399 			request->SendReply(rv, &reply, sizeof(reply));
400 			break;
401 		}
402 
403 		case SERVER_RELEASE_NODE:
404 		{
405 			const server_release_node_request *request = reinterpret_cast<const server_release_node_request *>(data);
406 			server_release_node_reply reply;
407 			rv = gNodeManager->ReleaseNode(request->node, request->team);
408 			request->SendReply(rv, &reply, sizeof(reply));
409 			break;
410 		}
411 
412 		case SERVER_REGISTER_NODE:
413 		{
414 			const server_register_node_request *request = reinterpret_cast<const server_register_node_request *>(data);
415 			server_register_node_reply reply;
416 			rv = gNodeManager->RegisterNode(&reply.nodeid, request->addon_id, request->addon_flavor_id, request->name, request->kinds, request->port, request->team);
417 			request->SendReply(rv, &reply, sizeof(reply));
418 			break;
419 		}
420 
421 		case SERVER_UNREGISTER_NODE:
422 		{
423 			const server_unregister_node_request *request = reinterpret_cast<const server_unregister_node_request *>(data);
424 			server_unregister_node_reply reply;
425 			rv = gNodeManager->UnregisterNode(&reply.addonid, &reply.flavorid, request->nodeid, request->team);
426 			request->SendReply(rv, &reply, sizeof(reply));
427 			break;
428 		}
429 
430 		case SERVER_PUBLISH_INPUTS:
431 		{
432 			const server_publish_inputs_request *request = reinterpret_cast<const server_publish_inputs_request *>(data);
433 			server_publish_inputs_reply reply;
434 			if (request->count <= MAX_INPUTS) {
435 				rv = gNodeManager->PublishInputs(request->node, request->inputs, request->count);
436 			} else {
437 				media_input *inputs;
438 				area_id clone;
439 				clone = clone_area("media_inputs clone", reinterpret_cast<void **>(&inputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
440 				if (clone < B_OK) {
441 					ERROR("SERVER_PUBLISH_INPUTS: failed to clone area, error %#lx\n", clone);
442 					rv = B_ERROR;
443 				} else {
444 					rv = gNodeManager->PublishInputs(request->node, inputs, request->count);
445 					delete_area(clone);
446 				}
447 			}
448 			request->SendReply(rv, &reply, sizeof(reply));
449 			break;
450 		}
451 
452 		case SERVER_PUBLISH_OUTPUTS:
453 		{
454 			const server_publish_outputs_request *request = reinterpret_cast<const server_publish_outputs_request *>(data);
455 			server_publish_outputs_reply reply;
456 			if (request->count <= MAX_OUTPUTS) {
457 				rv = gNodeManager->PublishOutputs(request->node, request->outputs, request->count);
458 			} else {
459 				media_output *outputs;
460 				area_id clone;
461 				clone = clone_area("media_outputs clone", reinterpret_cast<void **>(&outputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
462 				if (clone < B_OK) {
463 					ERROR("SERVER_PUBLISH_OUTPUTS: failed to clone area, error %#lx\n", clone);
464 					rv = B_ERROR;
465 				} else {
466 					rv = gNodeManager->PublishOutputs(request->node, outputs, request->count);
467 					delete_area(clone);
468 				}
469 			}
470 			request->SendReply(rv, &reply, sizeof(reply));
471 			break;
472 		}
473 
474 		case SERVER_GET_NODE:
475 		{
476 			const server_get_node_request *request = reinterpret_cast<const server_get_node_request *>(data);
477 			server_get_node_reply reply;
478 			rv = gNodeManager->GetClone(&reply.node, reply.input_name, &reply.input_id, request->type, request->team);
479 			request->SendReply(rv, &reply, sizeof(reply));
480 			break;
481 		}
482 
483 		case SERVER_SET_NODE:
484 		{
485 			const server_set_node_request *request = reinterpret_cast<const server_set_node_request *>(data);
486 			server_set_node_reply reply;
487 			rv = gNodeManager->SetDefaultNode(request->type, request->use_node ? &request->node : NULL, request->use_dni ? &request->dni : NULL, request->use_input ?  &request->input : NULL);
488 			request->SendReply(rv, &reply, sizeof(reply));
489 			break;
490 		}
491 
492 		case SERVER_GET_DORMANT_NODE_FOR:
493 		{
494 			const server_get_dormant_node_for_request *request = reinterpret_cast<const server_get_dormant_node_for_request *>(data);
495 			server_get_dormant_node_for_reply reply;
496 			rv = gNodeManager->GetDormantNodeInfo(&reply.node_info, request->node);
497 			request->SendReply(rv, &reply, sizeof(reply));
498 			break;
499 		}
500 
501 		case SERVER_GET_INSTANCES_FOR:
502 		{
503 			const server_get_instances_for_request *request = reinterpret_cast<const server_get_instances_for_request *>(data);
504 			server_get_instances_for_reply reply;
505 			rv = gNodeManager->GetInstances(reply.node_id, &reply.count, min_c(request->maxcount, MAX_NODE_ID), request->addon_id, request->addon_flavor_id);
506 			if (reply.count == MAX_NODE_ID && request->maxcount > MAX_NODE_ID) { // XXX might be fixed by using an area
507 				PRINT(1, "Warning: SERVER_GET_INSTANCES_FOR: returning possibly truncated list of node id's\n");
508 			}
509 			request->SendReply(rv, &reply, sizeof(reply));
510 			break;
511 		}
512 
513 		case SERVER_REGISTER_MEDIAADDON:
514 		{
515 			server_register_mediaaddon_request *msg = (server_register_mediaaddon_request *)data;
516 			server_register_mediaaddon_reply reply;
517 			gNodeManager->RegisterAddon(msg->ref, &reply.addonid);
518 			write_port(msg->reply_port, 0, &reply, sizeof(reply));
519 			break;
520 		}
521 
522 		case SERVER_UNREGISTER_MEDIAADDON:
523 		{
524 			server_unregister_mediaaddon_command *msg = (server_unregister_mediaaddon_command *)data;
525 			gNodeManager->UnregisterAddon(msg->addonid);
526 			break;
527 		}
528 
529 		case SERVER_REGISTER_DORMANT_NODE:
530 		{
531 			xfer_server_register_dormant_node *msg = (xfer_server_register_dormant_node *)data;
532 			dormant_flavor_info dfi;
533 			if (msg->purge_id > 0)
534 				gNodeManager->InvalidateDormantFlavorInfo(msg->purge_id);
535 			rv = dfi.Unflatten(msg->dfi_type, &(msg->dfi), msg->dfi_size);
536 			ASSERT(rv == B_OK);
537 			gNodeManager->AddDormantFlavorInfo(dfi);
538 			break;
539 		}
540 
541 		case SERVER_GET_DORMANT_NODES:
542 		{
543 			xfer_server_get_dormant_nodes *msg = (xfer_server_get_dormant_nodes *)data;
544 			xfer_server_get_dormant_nodes_reply reply;
545 			dormant_node_info * infos = new dormant_node_info[msg->maxcount];
546 			reply.count = msg->maxcount;
547 			reply.result = gNodeManager->GetDormantNodes(
548 				infos,
549 				&reply.count,
550 				msg->has_input ? &msg->inputformat : NULL,
551 				msg->has_output ? &msg->outputformat : NULL,
552 				msg->has_name ? msg->name : NULL,
553 				msg->require_kinds,
554 				msg->deny_kinds);
555 			if (reply.result != B_OK)
556 				reply.count = 0;
557 			write_port(msg->reply_port, 0, &reply, sizeof(reply));
558 			if (reply.count > 0)
559 				write_port(msg->reply_port, 0, infos, reply.count * sizeof(dormant_node_info));
560 			delete [] infos;
561 			break;
562 		}
563 
564 		case SERVER_GET_DORMANT_FLAVOR_INFO:
565 		{
566 			xfer_server_get_dormant_flavor_info *msg = (xfer_server_get_dormant_flavor_info *)data;
567 			dormant_flavor_info dfi;
568 			status_t rv;
569 
570 			rv = gNodeManager->GetDormantFlavorInfoFor(msg->addon, msg->flavor_id, &dfi);
571 			if (rv != B_OK) {
572 				xfer_server_get_dormant_flavor_info_reply reply;
573 				reply.result = rv;
574 				write_port(msg->reply_port, 0, &reply, sizeof(reply));
575 			} else {
576 				xfer_server_get_dormant_flavor_info_reply *reply;
577 				int replysize;
578 				replysize = sizeof(xfer_server_get_dormant_flavor_info_reply) + dfi.FlattenedSize();
579 				reply = (xfer_server_get_dormant_flavor_info_reply *)malloc(replysize);
580 
581 				reply->dfi_size = dfi.FlattenedSize();
582 				reply->dfi_type = dfi.TypeCode();
583 				reply->result = dfi.Flatten(reply->dfi, reply->dfi_size);
584 				write_port(msg->reply_port, 0, reply, replysize);
585 				free(reply);
586 			}
587 			break;
588 		}
589 
590 		case SERVER_SET_NODE_CREATOR:
591 		{
592 			const server_set_node_creator_request *request = reinterpret_cast<const server_set_node_creator_request *>(data);
593 			server_set_node_creator_reply reply;
594 			rv = gNodeManager->SetNodeCreator(request->node, request->creator);
595 			request->SendReply(rv, &reply, sizeof(reply));
596 			break;
597 		}
598 
599 		case SERVER_GET_SHARED_BUFFER_AREA:
600 		{
601 			const server_get_shared_buffer_area_request *request = reinterpret_cast<const server_get_shared_buffer_area_request *>(data);
602 			server_get_shared_buffer_area_reply reply;
603 
604 			reply.area = gBufferManager->SharedBufferListID();
605 			request->SendReply(B_OK, &reply, sizeof(reply));
606 			break;
607 		}
608 
609 		case SERVER_REGISTER_BUFFER:
610 		{
611 			const server_register_buffer_request *request = reinterpret_cast<const server_register_buffer_request *>(data);
612 			server_register_buffer_reply reply;
613 			status_t status;
614 			if (request->info.buffer == 0) {
615 				reply.info = request->info; //size, offset, flags, area is kept
616 				// get a new beuffer id into reply.info.buffer
617 				status = gBufferManager->RegisterBuffer(request->team, request->info.size, request->info.flags, request->info.offset, request->info.area, &reply.info.buffer);
618 			} else {
619 				reply.info = request->info; //buffer id is kept
620 				status = gBufferManager->RegisterBuffer(request->team, request->info.buffer, &reply.info.size, &reply.info.flags, &reply.info.offset, &reply.info.area);
621 			}
622 			request->SendReply(status, &reply, sizeof(reply));
623 			break;
624 		}
625 
626 		case SERVER_UNREGISTER_BUFFER:
627 		{
628 			const server_unregister_buffer_command *cmd = reinterpret_cast<const server_unregister_buffer_command *>(data);
629 
630 			gBufferManager->UnregisterBuffer(cmd->team, cmd->bufferid);
631 			break;
632 		}
633 
634 		case SERVER_REWINDTYPES:
635 		{
636 			const server_rewindtypes_request *request = reinterpret_cast<const server_rewindtypes_request *>(data);
637 			server_rewindtypes_reply reply;
638 
639 			BString **types = NULL;
640 
641 			rv = gMMediaFilesManager->RewindTypes(
642 					&types, &reply.count);
643 			if(reply.count>0) {
644 				// we create an area here, and pass it to the library, where it will be deleted.
645 				char *start_addr;
646 				size_t size = ((reply.count * B_MEDIA_NAME_LENGTH) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
647 				reply.area = create_area("rewind types", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
648 				if (reply.area < B_OK) {
649 					ERROR("SERVER_REWINDTYPES: failed to create area, error %s\n", strerror(reply.area));
650 					reply.count = 0;
651 					rv = B_ERROR;
652 				} else {
653 					for (int32 index = 0; index < reply.count; index++)
654 						strncpy(start_addr + B_MEDIA_NAME_LENGTH * index, types[index]->String(), B_MEDIA_NAME_LENGTH);
655 				}
656 			}
657 
658 			delete types;
659 
660 			rv = request->SendReply(rv, &reply, sizeof(reply));
661 			if (rv != B_OK)
662 				delete_area(reply.area); // if we couldn't send the message, delete the area
663 			break;
664 		}
665 
666 		case SERVER_REWINDREFS:
667 		{
668 			const server_rewindrefs_request *request = reinterpret_cast<const server_rewindrefs_request *>(data);
669 			server_rewindrefs_reply reply;
670 
671 			BString **items = NULL;
672 
673 			rv = gMMediaFilesManager->RewindRefs(request->type,
674 					&items, &reply.count);
675 			// we create an area here, and pass it to the library, where it will be deleted.
676 			if(reply.count>0) {
677 				char *start_addr;
678 				size_t size = ((reply.count * B_MEDIA_NAME_LENGTH) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
679 				reply.area = create_area("rewind refs", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
680 				if (reply.area < B_OK) {
681 					ERROR("SERVER_REWINDREFS: failed to create area, error %s\n", strerror(reply.area));
682 					reply.count = 0;
683 					rv = B_ERROR;
684 				} else {
685 					for (int32 index = 0; index < reply.count; index++)
686 						strncpy(start_addr + B_MEDIA_NAME_LENGTH * index, items[index]->String(), B_MEDIA_NAME_LENGTH);
687 				}
688 			}
689 
690 			delete items;
691 
692 			rv = request->SendReply(rv, &reply, sizeof(reply));
693 			if (rv != B_OK)
694 				delete_area(reply.area); // if we couldn't send the message, delete the area
695 			break;
696 		}
697 
698 		case SERVER_GETREFFOR:
699 		{
700 			const server_getreffor_request *request = reinterpret_cast<const server_getreffor_request *>(data);
701 			server_getreffor_reply reply;
702 			entry_ref *ref;
703 
704 			rv = gMMediaFilesManager->GetRefFor(request->type, request->item, &ref);
705 			if(rv==B_OK) {
706 				reply.ref = *ref;
707 			}
708 			request->SendReply(rv, &reply, sizeof(reply));
709 			break;
710 		}
711 
712 		case SERVER_SETREFFOR:
713 		{
714 			const server_setreffor_request *request = reinterpret_cast<const server_setreffor_request *>(data);
715 			server_setreffor_reply reply;
716 			entry_ref ref = request->ref;
717 
718 			rv = gMMediaFilesManager->SetRefFor(request->type, request->item, ref);
719 			request->SendReply(rv, &reply, sizeof(reply));
720 			break;
721 		}
722 
723 		case SERVER_REMOVEREFFOR:
724 		{
725 			const server_removereffor_request *request = reinterpret_cast<const server_removereffor_request *>(data);
726 			server_removereffor_reply reply;
727 			entry_ref ref = request->ref;
728 
729 			rv = gMMediaFilesManager->RemoveRefFor(request->type, request->item, ref);
730 			request->SendReply(rv, &reply, sizeof(reply));
731 			break;
732 		}
733 
734 		case SERVER_REMOVEITEM:
735 		{
736 			const server_removeitem_request *request = reinterpret_cast<const server_removeitem_request *>(data);
737 			server_removeitem_reply reply;
738 
739 			rv = gMMediaFilesManager->RemoveItem(request->type, request->item);
740 			request->SendReply(rv, &reply, sizeof(reply));
741 			break;
742 		}
743 
744 		case SERVER_GET_READERS:
745 		{
746 			const server_get_readers_request *request = reinterpret_cast<const server_get_readers_request *>(data);
747 			server_get_readers_reply reply;
748 			rv = gAddOnManager->GetReaders(reply.ref, &reply.count, MAX_READERS);
749 			request->SendReply(rv, &reply, sizeof(reply));
750 			break;
751 		}
752 
753 		case SERVER_GET_DECODER_FOR_FORMAT:
754 		{
755 			const server_get_decoder_for_format_request *request = reinterpret_cast<const server_get_decoder_for_format_request *>(data);
756 			server_get_decoder_for_format_reply reply;
757 			rv = gAddOnManager->GetDecoderForFormat(&reply.ref, request->format);
758 			request->SendReply(rv, &reply, sizeof(reply));
759 			break;
760 		}
761 
762 		default:
763 			printf("media_server: received unknown message code %#08lx\n",code);
764 	}
765 	TRACE("ServerApp::HandleMessage %#lx leave\n", code);
766 }
767 
768 int32
769 ServerApp::controlthread(void *arg)
770 {
771 	char data[B_MEDIA_MESSAGE_SIZE];
772 	ServerApp *app;
773 	ssize_t size;
774 	int32 code;
775 
776 	app = (ServerApp *)arg;
777 	while ((size = read_port_etc(app->control_port, &code, data, sizeof(data), 0, 0)) > 0)
778 		app->HandleMessage(code, data, size);
779 
780 	return 0;
781 }
782 
783 void
784 ServerApp::MessageReceived(BMessage *msg)
785 {
786 	TRACE("ServerApp::MessageReceived %lx enter\n", msg->what);
787 	switch (msg->what) {
788 		case MEDIA_SERVER_REQUEST_NOTIFICATIONS:
789 		case MEDIA_SERVER_CANCEL_NOTIFICATIONS:
790 		case MEDIA_SERVER_SEND_NOTIFICATIONS:
791 			gNotificationManager->EnqueueMessage(msg);
792 			break;
793 
794 		case MMEDIAFILESMANAGER_SAVE_TIMER:
795 			gMMediaFilesManager->TimerMessage();
796 			break;
797 
798 		case MEDIA_SERVER_GET_FORMATS:
799 			gFormatManager->GetFormats(*msg);
800 			break;
801 
802 		case MEDIA_SERVER_MAKE_FORMAT_FOR:
803 			gFormatManager->MakeFormatFor(*msg);
804 			break;
805 
806 		case MEDIA_SERVER_ADD_SYSTEM_BEEP_EVENT:
807 			gMMediaFilesManager->HandleAddSystemBeepEvent(msg);
808 			break;
809 		default:
810 			inherited::MessageReceived(msg);
811 			printf("\nmedia_server: unknown message received:\n");
812 			msg->PrintToStream();
813 			break;
814 	}
815 	TRACE("ServerApp::MessageReceived %lx leave\n", msg->what);
816 }
817 
818 int
819 main()
820 {
821 	new ServerApp;
822 	be_app->Run();
823 	delete be_app;
824 	return 0;
825 }
826