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