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