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