xref: /haiku/src/servers/media/media_server.cpp (revision 04a0e9c7b68cbe3a43d38e2bca8e860fd80936fb)
1  /*
2   * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3   *
4   * Permission is hereby granted, free of charge, to any person obtaining
5   * a copy of this software and associated documentation files or portions
6   * thereof (the "Software"), to deal in the Software without restriction,
7   * including without limitation the rights to use, copy, modify, merge,
8   * publish, distribute, sublicense, and/or sell copies of the Software,
9   * and to permit persons to whom the Software is furnished to do so, subject
10   * to the following conditions:
11   *
12   *  * Redistributions of source code must retain the above copyright notice,
13   *    this list of conditions and the following disclaimer.
14   *
15   *  * Redistributions in binary form must reproduce the above copyright notice
16   *    in the  binary, as well as this list of conditions and the following
17   *    disclaimer in the documentation and/or other materials provided with
18   *    the distribution.
19   *
20   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26   * THE SOFTWARE.
27   *
28   */
29  
30  
31  /* to comply with the license above, do not remove the following line */
32  char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 "
33  	"Marcus Overhagen <Marcus@Overhagen.de>";
34  
35  
36  #include <stdio.h>
37  #include <string.h>
38  
39  #include <Alert.h>
40  #include <Application.h>
41  #include <Autolock.h>
42  #include <Directory.h>
43  #include <Roster.h>
44  #include <MediaDefs.h>
45  #include <MediaFormats.h>
46  #include <Messenger.h>
47  
48  #include <syscalls.h>
49  
50  #include "AddOnManager.h"
51  #include "AppManager.h"
52  #include "BufferManager.h"
53  #include "DataExchange.h"
54  #include "FormatManager.h"
55  #include "MediaMisc.h"
56  #include "MediaFilesManager.h"
57  #include "NodeManager.h"
58  #include "NotificationManager.h"
59  #include "ServerInterface.h"
60  #include "debug.h"
61  #include "media_server.h"
62  
63  
64  AddOnManager* gAddOnManager;
65  AppManager* gAppManager;
66  BufferManager* gBufferManager;
67  FormatManager* gFormatManager;
68  MediaFilesManager* gMediaFilesManager;
69  NodeManager* gNodeManager;
70  NotificationManager* gNotificationManager;
71  
72  
73  #define REPLY_TIMEOUT ((bigtime_t)500000)
74  
75  
76  class ServerApp : BApplication {
77  public:
78  	ServerApp();
79  	~ServerApp();
80  
81  protected:
82  	virtual void				ArgvReceived(int32 argc, char** argv);
83  	virtual void				ReadyToRun();
84  	virtual bool				QuitRequested();
85  	virtual void				MessageReceived(BMessage* message);
86  
87  private:
88  			void				_HandleMessage(int32 code, const void* data,
89  									size_t size);
90  			void				_LaunchAddOnServer();
91  			void				_QuitAddOnServer();
92  
93  private:
94  			port_id				_ControlPort() const { return fControlPort; }
95  
96  	static	int32				_ControlThread(void* arg);
97  
98  			BLocker				fLocker;
99  			port_id				fControlPort;
100  			thread_id			fControlThread;
101  };
102  
103  
104  ServerApp::ServerApp()
105   	:
106   	BApplication(B_MEDIA_SERVER_SIGNATURE),
107  	fLocker("media server locker")
108  {
109   	gNotificationManager = new NotificationManager;
110   	gBufferManager = new BufferManager;
111  	gAppManager = new AppManager;
112  	gNodeManager = new NodeManager;
113  	gMediaFilesManager = new MediaFilesManager;
114  	gFormatManager = new FormatManager;
115  	gAddOnManager = new AddOnManager;
116  
117  	fControlPort = create_port(64, MEDIA_SERVER_PORT_NAME);
118  	fControlThread = spawn_thread(_ControlThread, "media_server control", 105,
119  		this);
120  	resume_thread(fControlThread);
121  }
122  
123  
124  ServerApp::~ServerApp()
125  {
126  	TRACE("ServerApp::~ServerApp()\n");
127  
128  	delete_port(fControlPort);
129  	wait_for_thread(fControlThread, NULL);
130  
131  	delete gAddOnManager;
132  	delete gNotificationManager;
133  	delete gBufferManager;
134  	delete gAppManager;
135  	delete gNodeManager;
136  	delete gMediaFilesManager;
137  	delete gFormatManager;
138  }
139  
140  
141  void
142  ServerApp::ReadyToRun()
143  {
144  	gNodeManager->LoadState();
145  	gFormatManager->LoadState();
146  
147  	// make sure any previous media_addon_server is gone
148  	_QuitAddOnServer();
149  	// and start a new one
150  	_LaunchAddOnServer();
151  
152  	gAddOnManager->LoadState();
153  }
154  
155  
156  bool
157  ServerApp::QuitRequested()
158  {
159  	TRACE("ServerApp::QuitRequested()\n");
160  	gMediaFilesManager->SaveState();
161  	gNodeManager->SaveState();
162  	gFormatManager->SaveState();
163  	gAddOnManager->SaveState();
164  
165  	_QuitAddOnServer();
166  
167  	return true;
168  }
169  
170  
171  void
172  ServerApp::ArgvReceived(int32 argc, char **argv)
173  {
174  	for (int arg = 1; arg < argc; arg++) {
175  		if (strstr(argv[arg], "dump") != NULL) {
176  			gAppManager->Dump();
177  			gNodeManager->Dump();
178  			gBufferManager->Dump();
179  			gNotificationManager->Dump();
180  			gMediaFilesManager->Dump();
181  		}
182  		if (strstr(argv[arg], "buffer") != NULL)
183  			gBufferManager->Dump();
184  		if (strstr(argv[arg], "node") != NULL)
185  			gNodeManager->Dump();
186  		if (strstr(argv[arg], "files") != NULL)
187  			gMediaFilesManager->Dump();
188  		if (strstr(argv[arg], "quit") != NULL)
189  			PostMessage(B_QUIT_REQUESTED);
190  	}
191  }
192  
193  
194  void
195  ServerApp::_LaunchAddOnServer()
196  {
197  	// Try to launch media_addon_server by mime signature.
198  	// If it fails (for example on the Live CD, where the executable
199  	// hasn't yet been mimesetted), try from this application's
200  	// directory
201  	status_t err = be_roster->Launch(B_MEDIA_ADDON_SERVER_SIGNATURE);
202  	if (err == B_OK)
203  		return;
204  
205  	app_info info;
206  	BEntry entry;
207  	BDirectory dir;
208  	entry_ref ref;
209  
210  	err = GetAppInfo(&info);
211  	err |= entry.SetTo(&info.ref);
212  	err |= entry.GetParent(&entry);
213  	err |= dir.SetTo(&entry);
214  	err |= entry.SetTo(&dir, "media_addon_server");
215  	err |= entry.GetRef(&ref);
216  
217  	if (err == B_OK)
218  		be_roster->Launch(&ref);
219  	if (err == B_OK)
220  		return;
221  
222  	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  
232  void
233  ServerApp::_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  
275  void
276  ServerApp::_HandleMessage(int32 code, const void* data, size_t size)
277  {
278  	TRACE("ServerApp::HandleMessage %#" B_PRIx32 " 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 %#" B_PRIx32 "\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 %#" B_PRIx32 "\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 %#08" B_PRIx32
965  				"\n", code);
966  	}
967  	TRACE("ServerApp::HandleMessage %#" B_PRIx32 " leave\n", code);
968  }
969  
970  
971  status_t
972  ServerApp::_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  
988  void
989  ServerApp::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  
1027  int
1028  main()
1029  {
1030  	new ServerApp;
1031  	be_app->Run();
1032  	delete be_app;
1033  	return 0;
1034  }
1035