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