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
32const uint32 kMsgHeader = 'sepx';
33const uint32 kMsgTypeVideoIn = 0xffffffef;
34const uint32 kMsgTypeVideoOut = 0xffffffee;
35const uint32 kMsgTypeAudioIn = 0xfffffffe;
36const uint32 kMsgTypeAudioOut = 0xffffffff;
37
38const char *kDefaultManagerType 			= "be:_default";
39const char *kDefaultManagerAddon 			= "be:_addon_id";
40const char *kDefaultManagerFlavorId 		= "be:_internal_id";
41const char *kDefaultManagerFlavorName 		= "be:_flavor_name";
42const char *kDefaultManagerPath 			= "be:_path";
43const char *kDefaultManagerInput 			= "be:_input_id";
44
45const char *kDefaultManagerSettingsDirectory			= "Media";
46const char *kDefaultManagerSettingsFile				= "MDefaultManager";
47
48
49DefaultManager::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
79DefaultManager::~DefaultManager()
80{
81}
82
83
84// this is called by the media_server *before* any add-ons have been loaded
85status_t
86DefaultManager::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
144status_t
145DefaultManager::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
225status_t
226DefaultManager::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
271status_t
272DefaultManager::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
338status_t
339DefaultManager::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
353int32
354DefaultManager::rescan_thread(void *arg)
355{
356	reinterpret_cast<DefaultManager *>(arg)->_RescanThread();
357	return 0;
358}
359
360
361void
362DefaultManager::_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
430void
431DefaultManager::_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
533void
534DefaultManager::_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
597void
598DefaultManager::_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
619status_t
620DefaultManager::_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
757finish:
758	fRoster->ReleaseNode(mixer);
759	fRoster->ReleaseNode(soundcard);
760	fRoster->ReleaseNode(timesource);
761	return rv;
762}
763
764
765void
766DefaultManager::Dump()
767{
768}
769
770
771void
772DefaultManager::CleanupTeam(team_id team)
773{
774}
775