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