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