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