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