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