xref: /haiku/src/servers/media/DefaultManager.cpp (revision 8f3a684551ef612f4b2dee43979f4a20f887c082)
1 /*
2  * Copyright 2002, 2003 Marcus Overhagen, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "DefaultManager.h"
8 
9 #include <Application.h>
10 #include <Directory.h>
11 #include <File.h>
12 #include <FindDirectory.h>
13 #include <MediaNode.h>
14 #include <OS.h>
15 #include <Path.h>
16 #include <TimeSource.h>
17 #include <string.h>
18 
19 #include "MediaDebug.h"
20 #include "DormantNodeManager.h"
21 #include "media_server.h"
22 #include "NodeManager.h"
23 
24 
25 /* no locking used in this file, we assume that the caller (NodeManager) does it.
26  */
27 
28 
29 #define MAX_NODE_INFOS 10
30 #define MAX_INPUT_INFOS 10
31 
32 const uint32 kMsgHeader = 'sepx';
33 const uint32 kMsgTypeVideoIn = 0xffffffef;
34 const uint32 kMsgTypeVideoOut = 0xffffffee;
35 const uint32 kMsgTypeAudioIn = 0xfffffffe;
36 const uint32 kMsgTypeAudioOut = 0xffffffff;
37 
38 const char *kDefaultManagerType 			= "be:_default";
39 const char *kDefaultManagerAddon 			= "be:_addon_id";
40 const char *kDefaultManagerFlavorId 		= "be:_internal_id";
41 const char *kDefaultManagerFlavorName 		= "be:_flavor_name";
42 const char *kDefaultManagerPath 			= "be:_path";
43 const char *kDefaultManagerInput 			= "be:_input_id";
44 
45 const char *kDefaultManagerSettingsDirectory			= "Media";
46 const char *kDefaultManagerSettingsFile				= "MDefaultManager";
47 
48 
DefaultManager()49 DefaultManager::DefaultManager()
50 	:
51 	fMixerConnected(false),
52  	fPhysicalVideoOut(-1),
53 	fPhysicalVideoIn(-1),
54 	fPhysicalAudioOut(-1),
55 	fPhysicalAudioIn(-1),
56 	fSystemTimeSource(-1),
57 	fTimeSource(-1),
58 	fAudioMixer(-1),
59 	fPhysicalAudioOutInputID(0),
60 	fRescanThread(-1),
61 	fRescanRequested(0),
62 	fRescanLock("rescan default manager"),
63 	fRoster(NULL)
64 {
65 	strcpy(fPhysicalAudioOutInputName, "default");
66 	fBeginHeader[0] = 0xab00150b;
67 	fBeginHeader[1] = 0x18723462;
68 	fBeginHeader[2] = 0x00000002;
69 	fEndHeader[0] = 0x7465726d;
70 	fEndHeader[1] = 0x6d666c67;
71 	fEndHeader[2] = 0x00000002;
72 
73 	fRoster = BMediaRoster::Roster();
74 	if (fRoster == NULL)
75 		TRACE("DefaultManager: The roster is NULL\n");
76 }
77 
78 
~DefaultManager()79 DefaultManager::~DefaultManager()
80 {
81 }
82 
83 
84 // this is called by the media_server *before* any add-ons have been loaded
85 status_t
LoadState()86 DefaultManager::LoadState()
87 {
88 	CALLED();
89 	status_t err = B_OK;
90 	BPath path;
91 	if ((err = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK)
92 		return err;
93 
94 	path.Append(kDefaultManagerSettingsDirectory);
95 	path.Append(kDefaultManagerSettingsFile);
96 
97 	BFile file(path.Path(), B_READ_ONLY);
98 
99 	uint32 categoryCount;
100 	ssize_t size = sizeof(uint32) * 3;
101 	if (file.Read(fBeginHeader, size) < size)
102 		return B_ERROR;
103 	TRACE("0x%08lx %ld\n", fBeginHeader[0], fBeginHeader[0]);
104 	TRACE("0x%08lx %ld\n", fBeginHeader[1], fBeginHeader[1]);
105 	TRACE("0x%08lx %ld\n", fBeginHeader[2], fBeginHeader[2]);
106 	size = sizeof(uint32);
107 	if (file.Read(&categoryCount, size) < size) {
108 		fprintf(stderr,
109 			"DefaultManager::LoadState() failed to read categoryCount\n");
110 		return B_ERROR;
111 	}
112 	TRACE("DefaultManager::LoadState() categoryCount %ld\n", categoryCount);
113 	while (categoryCount--) {
114 		BMessage settings;
115 		uint32 msg_header;
116 		uint32 default_type;
117 		if (file.Read(&msg_header, size) < size) {
118 			fprintf(stderr,
119 				"DefaultManager::LoadState() failed to read msg_header\n");
120 			return B_ERROR;
121 		}
122 		if (file.Read(&default_type, size) < size) {
123 			fprintf(stderr,
124 				"DefaultManager::LoadState() failed to read default_type\n");
125 			return B_ERROR;
126 		}
127 		if (settings.Unflatten(&file) == B_OK)
128 			fMsgList.AddItem(new BMessage(settings));
129 		else
130 			fprintf(stderr, "DefaultManager::LoadState() failed to unflatten\n");
131 	}
132 	size = sizeof(uint32) * 3;
133 	if (file.Read(fEndHeader,size) < size) {
134 		fprintf(stderr,
135 			"DefaultManager::LoadState() failed to read fEndHeader\n");
136 		return B_ERROR;
137 	}
138 
139 	TRACE("LoadState returns B_OK\n");
140 	return B_OK;
141 }
142 
143 
144 status_t
SaveState(NodeManager * node_manager)145 DefaultManager::SaveState(NodeManager *node_manager)
146 {
147 	CALLED();
148 	status_t err = B_OK;
149 	BPath path;
150 	BList list;
151 	if ((err = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) != B_OK)
152 		return err;
153 	path.Append(kDefaultManagerSettingsDirectory);
154 	if ((err = create_directory(path.Path(), 0755)) != B_OK)
155 		return err;
156 	path.Append(kDefaultManagerSettingsFile);
157 
158 	uint32 default_types[] = {kMsgTypeVideoIn, kMsgTypeVideoOut,
159 		kMsgTypeAudioIn, kMsgTypeAudioOut};
160 	media_node_id media_node_ids[] = {fPhysicalVideoIn, fPhysicalVideoOut,
161 		fPhysicalAudioIn, fPhysicalAudioOut};
162 	for (uint32 i = 0; i < sizeof(default_types) / sizeof(default_types[0]);
163 		i++) {
164 
165 		// we call the node manager to have more infos about nodes
166 		dormant_node_info info;
167 		media_node node;
168 		entry_ref ref;
169 		if (node_manager->GetCloneForID(media_node_ids[i], be_app->Team(),
170 				&node) != B_OK
171 			|| node_manager->GetDormantNodeInfo(node, &info) != B_OK
172 			|| node_manager->ReleaseNodeReference(media_node_ids[i],
173 				be_app->Team()) != B_OK
174 			|| node_manager->GetAddOnRef(info.addon, &ref) != B_OK) {
175 			if (media_node_ids[i] != -1) {
176 				// failed to get node info thus just return
177 				return B_ERROR;
178 			}
179 			continue;
180 		}
181 
182 		BMessage *settings = new BMessage();
183 		settings->AddInt32(kDefaultManagerType, default_types[i]);
184 		BPath path(&ref);
185 		settings->AddInt32(kDefaultManagerAddon, info.addon);
186 		settings->AddInt32(kDefaultManagerFlavorId, info.flavor_id);
187 		settings->AddInt32(kDefaultManagerInput,
188 			default_types[i] == kMsgTypeAudioOut ? fPhysicalAudioOutInputID : 0);
189 		settings->AddString(kDefaultManagerFlavorName, info.name);
190 		settings->AddString(kDefaultManagerPath, path.Path());
191 
192 		list.AddItem(settings);
193 		TRACE("message %s added\n", info.name);
194 	}
195 
196 	BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
197 
198 	if (file.Write(fBeginHeader, sizeof(uint32)*3) < (int32)sizeof(uint32)*3)
199 		return B_ERROR;
200 	int32 categoryCount = list.CountItems();
201 	if (file.Write(&categoryCount, sizeof(uint32)) < (int32)sizeof(uint32))
202 		return B_ERROR;
203 
204 	for (int32 i = 0; i < categoryCount; i++) {
205 		BMessage *settings = (BMessage *)list.ItemAt(i);
206 		uint32 default_type;
207 		if (settings->FindInt32(kDefaultManagerType,
208 			(int32*)&default_type) < B_OK)
209 			return B_ERROR;
210 		if (file.Write(&kMsgHeader, sizeof(uint32)) < (int32)sizeof(uint32))
211 			return B_ERROR;
212 		if (file.Write(&default_type, sizeof(uint32)) < (int32)sizeof(uint32))
213 			return B_ERROR;
214 		if (settings->Flatten(&file) < B_OK)
215 			return B_ERROR;
216 		delete settings;
217 	}
218 	if (file.Write(fEndHeader, sizeof(uint32)*3) < (int32)sizeof(uint32)*3)
219 		return B_ERROR;
220 
221 	return B_OK;
222 }
223 
224 
225 status_t
Set(media_node_id node_id,const char * input_name,int32 input_id,node_type type)226 DefaultManager::Set(media_node_id node_id, const char *input_name,
227 	int32 input_id, node_type type)
228 {
229 	CALLED();
230 	TRACE("DefaultManager::Set type : %i, node : %li, input : %li\n", type,
231 		node_id, input_id);
232 	switch (type) {
233 		case VIDEO_INPUT:
234 			fPhysicalVideoIn = node_id;
235 			return B_OK;
236 		case AUDIO_INPUT:
237 			fPhysicalAudioIn = node_id;
238 			return B_OK;
239 		case VIDEO_OUTPUT:
240 			fPhysicalVideoOut = node_id;
241 			return B_OK;
242 		case AUDIO_MIXER:
243 			return B_ERROR;
244 		case AUDIO_OUTPUT:
245 			fPhysicalAudioOut = node_id;
246 			fPhysicalAudioOutInputID = input_id;
247 			strcpy(fPhysicalAudioOutInputName,
248 				input_name ? input_name : "<null>");
249 			return B_OK;
250 		case TIME_SOURCE:
251 			return B_ERROR;
252 
253 		// called by the media_server's ServerApp::StartSystemTimeSource()
254 		case SYSTEM_TIME_SOURCE:
255 		{
256 			ASSERT(fSystemTimeSource == -1);
257 			fSystemTimeSource = node_id;
258 			return B_OK;
259 		}
260 
261 		default:
262 		{
263 			ERROR("DefaultManager::Set Error: called with unknown type %d\n",
264 				type);
265 			return B_ERROR;
266 		}
267 	}
268 }
269 
270 
271 status_t
Get(media_node_id * nodeid,char * input_name,int32 * inputid,node_type type)272 DefaultManager::Get(media_node_id *nodeid, char *input_name, int32 *inputid,
273 	node_type type)
274 {
275 	CALLED();
276 	switch (type) {
277 		case VIDEO_INPUT: 		// output: nodeid
278 			if (fPhysicalVideoIn == -1)
279 				return B_NAME_NOT_FOUND;
280 			*nodeid = fPhysicalVideoIn;
281 			return B_OK;
282 
283 		case AUDIO_INPUT: 		// output: nodeid
284 			if (fPhysicalAudioIn == -1)
285 				return B_NAME_NOT_FOUND;
286 			*nodeid = fPhysicalAudioIn;
287 			return B_OK;
288 
289 		case VIDEO_OUTPUT: 		// output: nodeid
290 			if (fPhysicalVideoOut == -1)
291 				return B_NAME_NOT_FOUND;
292 			*nodeid = fPhysicalVideoOut;
293 			return B_OK;
294 
295 		case AUDIO_OUTPUT:		// output: nodeid
296 			if (fPhysicalAudioOut == -1)
297 				return B_NAME_NOT_FOUND;
298 			*nodeid = fPhysicalAudioOut;
299 			return B_OK;
300 
301 		case AUDIO_OUTPUT_EX:	// output: nodeid, input_name, input_id
302 			if (fPhysicalAudioOut == -1)
303 				return B_NAME_NOT_FOUND;
304 			*nodeid = fPhysicalAudioOut;
305 			*inputid = fPhysicalAudioOutInputID;
306 			strcpy(input_name, fPhysicalAudioOutInputName);
307 			return B_OK;
308 
309 		case AUDIO_MIXER:		// output: nodeid
310 			if (fAudioMixer == -1)
311 				return B_NAME_NOT_FOUND;
312 			*nodeid = fAudioMixer;
313 			return B_OK;
314 
315 		case TIME_SOURCE:
316 			if (fTimeSource != -1)
317 				*nodeid = fTimeSource;
318 			else
319 				*nodeid = fSystemTimeSource;
320 			return B_OK;
321 
322 		case SYSTEM_TIME_SOURCE:
323 			*nodeid = fSystemTimeSource;
324 			return B_OK;
325 
326 		default:
327 		{
328 			ERROR("DefaultManager::Get Error: called with unknown type %d\n",
329 				type);
330 			return B_ERROR;
331 		}
332 	}
333 }
334 
335 
336 // this is called by the media_server *after* the initial add-on loading
337 // has been done
338 status_t
Rescan()339 DefaultManager::Rescan()
340 {
341 	BAutolock locker(fRescanLock);
342 	atomic_add(&fRescanRequested, 1);
343 	if (fRescanThread < 0) {
344 		fRescanThread = spawn_thread(rescan_thread, "rescan defaults",
345 			B_NORMAL_PRIORITY - 2, this);
346 		resume_thread(fRescanThread);
347 	}
348 
349 	return B_OK;
350 }
351 
352 
353 int32
rescan_thread(void * arg)354 DefaultManager::rescan_thread(void *arg)
355 {
356 	reinterpret_cast<DefaultManager *>(arg)->_RescanThread();
357 	return 0;
358 }
359 
360 
361 void
_RescanThread()362 DefaultManager::_RescanThread()
363 {
364 	TRACE("DefaultManager::_RescanThread() enter\n");
365 
366 	BAutolock locker(fRescanLock);
367 
368 	while (atomic_and(&fRescanRequested, 0) != 0) {
369 		locker.Unlock();
370 
371 		// We do not search for the system time source,
372 		// it should already exist
373 		ASSERT(fSystemTimeSource != -1);
374 
375 		if (fPhysicalVideoOut == -1) {
376 			_FindPhysical(&fPhysicalVideoOut, kMsgTypeVideoOut, false,
377 				B_MEDIA_RAW_VIDEO);
378 			_FindPhysical(&fPhysicalVideoOut, kMsgTypeVideoOut, false,
379 				B_MEDIA_ENCODED_VIDEO);
380 		}
381 		if (fPhysicalVideoIn == -1) {
382 			_FindPhysical(&fPhysicalVideoIn, kMsgTypeVideoIn, true,
383 				B_MEDIA_RAW_VIDEO);
384 			_FindPhysical(&fPhysicalVideoIn, kMsgTypeVideoIn, true,
385 				B_MEDIA_ENCODED_VIDEO);
386 		}
387 		if (fPhysicalAudioOut == -1)
388 			_FindPhysical(&fPhysicalAudioOut, kMsgTypeAudioOut, false,
389 				B_MEDIA_RAW_AUDIO);
390 		if (fPhysicalAudioIn == -1)
391 			_FindPhysical(&fPhysicalAudioIn, kMsgTypeAudioIn, true,
392 				B_MEDIA_RAW_AUDIO);
393 		if (fAudioMixer == -1)
394 			_FindAudioMixer();
395 
396 		// The normal time source is searched for after the
397 		// Physical Audio Out has been created.
398 		if (fTimeSource == -1)
399 			_FindTimeSource();
400 
401 		// Connect the mixer and physical audio out (soundcard)
402 		if (!fMixerConnected && fAudioMixer != -1 && fPhysicalAudioOut != -1) {
403 			fMixerConnected = _ConnectMixerToOutput() == B_OK;
404 			if (!fMixerConnected)
405 				TRACE("DefaultManager: failed to connect mixer and "
406 					"soundcard\n");
407 		} else {
408 			TRACE("DefaultManager: Did not try to connect mixer and "
409 				"soundcard\n");
410 		}
411 
412 		if (fMixerConnected) {
413 			add_on_server_rescan_finished_notify_command cmd;
414 			SendToAddOnServer(ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY, &cmd,
415 				sizeof(cmd));
416 		}
417 
418 		locker.Lock();
419 	}
420 
421 	fRescanThread = -1;
422 
423 	BMessage msg(MEDIA_SERVER_RESCAN_COMPLETED);
424 	be_app->PostMessage(&msg);
425 
426 	TRACE("DefaultManager::_RescanThread() leave\n");
427 }
428 
429 
430 void
_FindPhysical(volatile media_node_id * id,uint32 default_type,bool isInput,media_type type)431 DefaultManager::_FindPhysical(volatile media_node_id *id, uint32 default_type,
432 	bool isInput, media_type type)
433 {
434 	live_node_info info[MAX_NODE_INFOS];
435 	media_format format;
436 	int32 count;
437 	status_t rv;
438 	BMessage *msg = NULL;
439 	BPath msgPath;
440 	dormant_node_info msgDninfo;
441 	int32 input_id;
442 	bool isAudio = (type == B_MEDIA_RAW_AUDIO)
443 		|| (type == B_MEDIA_ENCODED_AUDIO);
444 
445 	for (int32 i = 0; i < fMsgList.CountItems(); i++) {
446 		msg = (BMessage *)fMsgList.ItemAt(i);
447 		int32 msgType;
448 		if (msg->FindInt32(kDefaultManagerType, &msgType) == B_OK
449 			&& ((uint32)msgType == default_type)) {
450 			const char *name = NULL;
451 			const char *path = NULL;
452 			msg->FindInt32(kDefaultManagerAddon, &msgDninfo.addon);
453 			msg->FindInt32(kDefaultManagerFlavorId, &msgDninfo.flavor_id);
454 			msg->FindInt32(kDefaultManagerInput, &input_id);
455 			msg->FindString(kDefaultManagerFlavorName, &name);
456 			msg->FindString(kDefaultManagerPath, &path);
457 			if (name)
458 				strcpy(msgDninfo.name, name);
459 			if (path)
460 				msgPath = BPath(path);
461 			break;
462 		}
463 	}
464 
465 	format.type = type;
466 	count = MAX_NODE_INFOS;
467 	rv = fRoster->GetLiveNodes(&info[0], &count,
468 		isInput ? NULL : &format, isInput ? &format : NULL, NULL,
469 		isInput ? B_BUFFER_PRODUCER | B_PHYSICAL_INPUT
470 			: B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
471 	if (rv != B_OK || count < 1) {
472 		TRACE("Couldn't find physical %s %s node\n",
473 			isAudio ? "audio" : "video", isInput ? "input" : "output");
474 		return;
475 	}
476 	for (int i = 0; i < count; i++)
477 		TRACE("info[%d].name %s\n", i, info[i].name);
478 
479 	for (int i = 0; i < count; i++) {
480 		if (isAudio) {
481 			if (isInput) {
482 				if (0 == strcmp(info[i].name, "None In")) {
483 					// we keep the Null audio driver if none else matchs
484 					*id = info[i].node.node;
485 					continue;
486 				}
487 				// skip the Firewire audio driver
488 				if (0 == strcmp(info[i].name, "DV Input"))
489 					continue;
490 			} else {
491 				if (0 == strcmp(info[i].name, "None Out")) {
492 					// we keep the Null audio driver if none else matchs
493 					*id = info[i].node.node;
494 					if (msg)
495 						fPhysicalAudioOutInputID = input_id;
496 					continue;
497 				}
498 				// skip the Firewire audio driver
499 				if (0 == strcmp(info[i].name, "DV Output"))
500 					continue;
501 			}
502 		}
503 		if (msg) {	// we have a default info msg
504 			dormant_node_info dninfo;
505 			if (fRoster->GetDormantNodeFor(info[i].node,
506 					&dninfo) != B_OK) {
507 				ERROR("Couldn't GetDormantNodeFor\n");
508 				continue;
509 			}
510 			if (dninfo.flavor_id != msgDninfo.flavor_id
511 				|| strcmp(dninfo.name, msgDninfo.name) != 0) {
512 				ERROR("Doesn't match flavor or name\n");
513 				continue;
514 			}
515 			BPath path;
516 			if (gDormantNodeManager->FindAddOnPath(&path, dninfo.addon) != B_OK
517 				|| path != msgPath) {
518 				ERROR("Doesn't match : path\n");
519 				continue;
520 			}
521 		}
522 		TRACE("Default physical %s %s \"%s\" created!\n",
523 			isAudio ? "audio" : "video", isInput ? "input" : "output",
524 			info[i].name);
525 		*id = info[i].node.node;
526 		if (msg && isAudio && !isInput)
527 			fPhysicalAudioOutInputID = input_id;
528 		return;
529 	}
530 }
531 
532 
533 void
_FindTimeSource()534 DefaultManager::_FindTimeSource()
535 {
536 	live_node_info info[MAX_NODE_INFOS];
537 	media_format input; /* a physical audio output has a logical data input (DAC)*/
538 	int32 count;
539 	status_t rv;
540 
541 	/* First try to use the current default physical audio out
542 	 */
543 	if (fPhysicalAudioOut != -1) {
544 		media_node clone;
545 		if (fRoster->GetNodeFor(fPhysicalAudioOut,
546 				&clone) == B_OK) {
547 			if (clone.kind & B_TIME_SOURCE) {
548 				fTimeSource = clone.node;
549 				fRoster->StartTimeSource(clone,
550 					system_time() + 1000);
551 				fRoster->ReleaseNode(clone);
552 				TRACE("Default DAC timesource created!\n");
553 				return;
554 			}
555 			fRoster->ReleaseNode(clone);
556 		} else {
557 			TRACE("Default DAC is not a timesource!\n");
558 		}
559 	} else {
560 		TRACE("Default DAC node does not exist!\n");
561 	}
562 
563 	/* Now try to find another physical audio out node
564 	 */
565 	input.type = B_MEDIA_RAW_AUDIO;
566 	count = MAX_NODE_INFOS;
567 	rv = fRoster->GetLiveNodes(&info[0], &count, &input, NULL, NULL,
568 		B_TIME_SOURCE | B_PHYSICAL_OUTPUT);
569 	if (rv == B_OK && count >= 1) {
570 		for (int i = 0; i < count; i++)
571 			printf("info[%d].name %s\n", i, info[i].name);
572 
573 		for (int i = 0; i < count; i++) {
574 			// The BeOS R5 None Out node pretend to be a physical time source,
575 			// that is pretty dumb
576 			// skip the Null audio driver
577 			if (0 == strcmp(info[i].name, "None Out"))
578 				continue;
579 			// skip the Firewire audio driver
580 			if (0 != strstr(info[i].name, "DV Output"))
581 				continue;
582 			TRACE("Default DAC timesource \"%s\" created!\n", info[i].name);
583 			fTimeSource = info[i].node.node;
584 			fRoster->StartTimeSource(info[i].node,
585 				system_time() + 1000);
586 			return;
587 		}
588 	} else {
589 		TRACE("Couldn't find DAC timesource node\n");
590 	}
591 
592 	/* XXX we might use other audio or video clock timesources
593 	 */
594 }
595 
596 
597 void
_FindAudioMixer()598 DefaultManager::_FindAudioMixer()
599 {
600 	live_node_info info;
601 	int32 count;
602 	status_t rv;
603 
604 	if (fRoster == NULL)
605 		fRoster = BMediaRoster::Roster();
606 
607 	count = 1;
608 	rv = fRoster->GetLiveNodes(&info, &count, NULL, NULL, NULL,
609 		B_BUFFER_PRODUCER | B_BUFFER_CONSUMER | B_SYSTEM_MIXER);
610 	if (rv != B_OK || count != 1) {
611 		TRACE("Couldn't find audio mixer node\n");
612 		return;
613 	}
614 	fAudioMixer = info.node.node;
615 	TRACE("Default audio mixer node created\n");
616 }
617 
618 
619 status_t
_ConnectMixerToOutput()620 DefaultManager::_ConnectMixerToOutput()
621 {
622 	media_node 			timesource;
623 	media_node 			mixer;
624 	media_node 			soundcard;
625 	media_input			inputs[MAX_INPUT_INFOS];
626 	media_input 		input;
627 	media_output 		output;
628 	media_input 		newinput;
629 	media_output 		newoutput;
630 	media_format 		format;
631 	BTimeSource * 		ts;
632 	bigtime_t 			start_at;
633 	int32 				count;
634 	status_t 			rv;
635 
636 	if (fRoster == NULL)
637 		fRoster = BMediaRoster::Roster();
638 
639 	rv = fRoster->GetNodeFor(fPhysicalAudioOut, &soundcard);
640 	if (rv != B_OK) {
641 		TRACE("DefaultManager: failed to find soundcard (physical audio "
642 			"output)\n");
643 		return B_ERROR;
644 	}
645 
646 	rv = fRoster->GetNodeFor(fAudioMixer, &mixer);
647 	if (rv != B_OK) {
648 		fRoster->ReleaseNode(soundcard);
649 		TRACE("DefaultManager: failed to find mixer\n");
650 		return B_ERROR;
651 	}
652 
653 	// we now have the mixer and soundcard nodes,
654 	// find a free input/output and connect them
655 
656 	rv = fRoster->GetFreeOutputsFor(mixer, &output, 1, &count,
657 		B_MEDIA_RAW_AUDIO);
658 	if (rv != B_OK || count != 1) {
659 		TRACE("DefaultManager: can't find free mixer output\n");
660 		rv = B_ERROR;
661 		goto finish;
662 	}
663 
664 	rv = fRoster->GetFreeInputsFor(soundcard, inputs, MAX_INPUT_INFOS, &count,
665 		B_MEDIA_RAW_AUDIO);
666 	if (rv != B_OK || count < 1) {
667 		TRACE("DefaultManager: can't find free soundcard inputs\n");
668 		rv = B_ERROR;
669 		goto finish;
670 	}
671 
672 	for (int32 i = 0; i < count; i++) {
673 		input = inputs[i];
674 		if (input.destination.id == fPhysicalAudioOutInputID)
675 			break;
676 	}
677 
678 	for (int i = 0; i < 6; i++) {
679 		switch (i) {
680 			case 0:
681 				TRACE("DefaultManager: Trying connect in native format (1)\n");
682 				if (fRoster->GetFormatFor(input, &format) != B_OK) {
683 					ERROR("DefaultManager: GetFormatFor failed\n");
684 					continue;
685 				}
686 				// XXX BeOS R5 multiaudio node bug workaround
687 				if (format.u.raw_audio.channel_count == 1) {
688 					TRACE("##### WARNING! DefaultManager: ignored mono format\n");
689 					continue;
690 				}
691 				break;
692 
693 			case 1:
694 				TRACE("DefaultManager: Trying connect in format 1\n");
695 				format.Clear();
696 				format.type = B_MEDIA_RAW_AUDIO;
697 				format.u.raw_audio.frame_rate = 44100;
698 				format.u.raw_audio.channel_count = 2;
699 				format.u.raw_audio.format = 0x2;
700 				break;
701 
702 			case 2:
703 				TRACE("DefaultManager: Trying connect in format 2\n");
704 				format.Clear();
705 				format.type = B_MEDIA_RAW_AUDIO;
706 				format.u.raw_audio.frame_rate = 48000;
707 				format.u.raw_audio.channel_count = 2;
708 				format.u.raw_audio.format = 0x2;
709 				break;
710 
711 			case 3:
712 				TRACE("DefaultManager: Trying connect in format 3\n");
713 				format.Clear();
714 				format.type = B_MEDIA_RAW_AUDIO;
715 				break;
716 
717 			case 4:
718 				// BeOS R5 multiaudio node bug workaround
719 				TRACE("DefaultManager: Trying connect in native format (2)\n");
720 				if (fRoster->GetFormatFor(input, &format) != B_OK) {
721 					ERROR("DefaultManager: GetFormatFor failed\n");
722 					continue;
723 				}
724 				break;
725 
726 			case 5:
727 				TRACE("DefaultManager: Trying connect in format 4\n");
728 				format.Clear();
729 				break;
730 
731 		}
732 		rv = fRoster->Connect(output.source, input.destination, &format,
733 			&newoutput, &newinput);
734 		if (rv == B_OK)
735 			break;
736 	}
737 	if (rv != B_OK) {
738 		ERROR("DefaultManager: connect failed\n");
739 		goto finish;
740 	}
741 
742 	fRoster->SetRunModeNode(mixer, BMediaNode::B_INCREASE_LATENCY);
743 	fRoster->SetRunModeNode(soundcard, BMediaNode::B_RECORDING);
744 
745 	fRoster->GetTimeSource(&timesource);
746 	fRoster->SetTimeSourceFor(mixer.node, timesource.node);
747 	fRoster->SetTimeSourceFor(soundcard.node, timesource.node);
748 	fRoster->PrerollNode(mixer);
749 	fRoster->PrerollNode(soundcard);
750 
751 	ts = fRoster->MakeTimeSourceFor(mixer);
752 	start_at = ts->Now() + 50000;
753 	fRoster->StartNode(mixer, start_at);
754 	fRoster->StartNode(soundcard, start_at);
755 	ts->Release();
756 
757 finish:
758 	fRoster->ReleaseNode(mixer);
759 	fRoster->ReleaseNode(soundcard);
760 	fRoster->ReleaseNode(timesource);
761 	return rv;
762 }
763 
764 
765 void
Dump()766 DefaultManager::Dump()
767 {
768 }
769 
770 
771 void
CleanupTeam(team_id team)772 DefaultManager::CleanupTeam(team_id team)
773 {
774 }
775