2 * OpenSound media addon for BeOS and Haiku
4 * Copyright (c) 2007, François Revol (revol@free.fr)
5 * Distributed under the terms of the MIT License.
7 * Based on MultiAudio media addon
8 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
10 #include "OpenSoundAddOn.h"
12 #include <MediaDefs.h>
13 #include <MediaAddOn.h>
17 #include <StorageDefs.h>
19 #include <Directory.h>
21 #include <FindDirectory.h>
25 #include "OpenSoundNode.h"
26 #include "OpenSoundDevice.h"
27 #include "OpenSoundDeviceEngine.h"
38 // instantiation function
39 extern "C" _EXPORT BMediaAddOn
* make_media_addon(image_id image
) {
41 return new OpenSoundAddOn(image
);
44 // -------------------------------------------------------- //
46 // -------------------------------------------------------- //
48 OpenSoundAddOn::~OpenSoundAddOn()
53 for (int32 i
= 0; (device
= fDevices
.ItemAt(i
)); i
++)
54 delete (OpenSoundDevice
*)device
;
59 OpenSoundAddOn::OpenSoundAddOn(image_id image
) :
64 fInitCheckStatus
= B_NO_INIT
;
67 if (RecursiveScan("/dev/oss/") != B_OK
)
70 if (RecursiveScan("/dev/audio/oss/") != B_OK)
76 fInitCheckStatus
= B_OK
;
79 // -------------------------------------------------------- //
81 // -------------------------------------------------------- //
83 status_t
OpenSoundAddOn::InitCheck(
84 const char ** out_failure_text
)
90 int32
OpenSoundAddOn::CountFlavors()
93 PRINT(("%" B_PRId32
" flavours\n", fDevices
.CountItems()));
94 return fDevices
.CountItems();
97 status_t
OpenSoundAddOn::GetFlavorAt(
99 const flavor_info
** out_info
)
102 if (n
< 0 || n
> fDevices
.CountItems() - 1) {
103 fprintf(stderr
, "<- B_BAD_INDEX\n");
107 OpenSoundDevice
*device
= (OpenSoundDevice
*) fDevices
.ItemAt(n
);
109 flavor_info
* infos
= new flavor_info
[1];
110 OpenSoundNode::GetFlavor(&infos
[0], n
);
111 infos
[0].name
= device
->fCardInfo
.longname
;
116 BMediaNode
* OpenSoundAddOn::InstantiateNodeFor(
117 const flavor_info
* info
,
119 status_t
* out_error
)
123 OpenSoundDevice
*device
= (OpenSoundDevice
*)fDevices
.ItemAt(
125 if (device
== NULL
) {
126 *out_error
= B_ERROR
;
131 if (fSettings
.FindMessage(device
->fCardInfo
.longname
, config
) == B_OK
) {
132 fSettings
.RemoveData(device
->fCardInfo
.longname
);
136 OpenSoundNode
* node
=
137 new OpenSoundNode(this,
138 device
->fCardInfo
.longname
,
143 *out_error
= B_NO_MEMORY
;
144 fprintf(stderr
, "<- B_NO_MEMORY\n");
146 *out_error
= node
->InitCheck();
152 OpenSoundAddOn::GetConfigurationFor(BMediaNode
* your_node
, BMessage
* into_message
)
157 into_message
= new BMessage();
158 OpenSoundNode
* node
= dynamic_cast<OpenSoundNode
*>(your_node
);
160 fprintf(stderr
, "<- B_BAD_TYPE\n");
163 if (node
->GetConfigurationFor(into_message
) == B_OK
) {
164 fSettings
.AddMessage(your_node
->Name(), into_message
);
169 // currently never called by the media kit. Seems it is not implemented.
170 OpenSoundNode
* node
= dynamic_cast<OpenSoundNode
*>(your_node
);
172 fprintf(stderr
, "<- B_BAD_TYPE\n");
175 return node
->GetConfigurationFor(into_message
);
179 bool OpenSoundAddOn::WantsAutoStart()
185 status_t
OpenSoundAddOn::AutoStart(
187 BMediaNode
** out_node
,
188 int32
* out_internal_id
,
196 OpenSoundAddOn::RecursiveScan(const char* rootPath
, BEntry
*rootEntry
)
201 oss_card_info cardinfo
;
207 // make sure directories are scanned in this order
208 BDirectory("/dev/audio/hmulti");
209 BDirectory("/dev/audio/old");
210 // OSS last, to give precedence to native drivers.
211 // If other addons are loaded first it's ok as well.
212 // Also, we must open it to make sure oss_loader is here,
213 // else we don't get /dev/sndstat since we don't have a symlink in dev/.
214 BDirectory("/dev/oss");
216 mixer
= open(OSS_MIXER_DEV
, O_RDWR
);
219 // only works in BeOS
220 BFile
fDevFS("/dev/.", B_WRITE_ONLY
);
221 const char *drv
= "oss_loader";
222 fDevFS
.Write(drv
, strlen(drv
));
223 mixer
= open(OSS_MIXER_DEV
, O_RDWR
);
230 if (ioctl(mixer
, SNDCTL_SYSINFO
, &sysinfo
) < 0) {
235 PRINT(("OSS: %s %s (0x%08X)\n", sysinfo
.product
, sysinfo
.version
, sysinfo
.versionnum
));
236 PRINT(("OSS: %d audio cards, %d audio devs, %d audio engines, %d midi, %d mixers\n", sysinfo
.numcards
, sysinfo
.numaudios
, sysinfo
.numaudioengines
, sysinfo
.nummidis
, sysinfo
.nummixers
));
238 /* construct an empty SoundDevice per card */
240 for (card
= 0; card
< sysinfo
.numcards
; card
++) {
241 cardinfo
.card
= card
;
242 if (ioctl(mixer
, SNDCTL_CARDINFO
, &cardinfo
) < 0) {
246 OpenSoundDevice
*device
= new OpenSoundDevice(&cardinfo
);
248 devs
.AddItem(device
);
255 /* Add its audio engines to it */
257 for (i
= 0; i
< sysinfo
.numaudioengines
; i
++) {
258 oss_audioinfo audioinfo
;
260 if (ioctl(mixer
, SNDCTL_ENGINEINFO
, &audioinfo
, sizeof(oss_audioinfo
)) < 0) {
264 PRINT(("OSS: engine[%d]: card=%d, port=%d, legacy=%d, next_play=%d, next_rec=%d\n", i
, audioinfo
.card_number
, audioinfo
.port_number
, audioinfo
.legacy_device
, audioinfo
.next_play_engine
, audioinfo
.next_rec_engine
));
265 OpenSoundDevice
*device
= (OpenSoundDevice
*)(devs
.ItemAt(audioinfo
.card_number
));
267 device
->AddEngine(&audioinfo
);
270 /* Add its mixers to it */
272 for (i
= 0; i
< sysinfo
.nummixers
; i
++) {
273 oss_mixerinfo mixerinfo
;
275 if (ioctl(mixer
, SNDCTL_MIXERINFO
, &mixerinfo
) < 0) {
279 PRINT(("OSS: mixer[%d]: card=%d\n", i
, mixerinfo
.card_number
));
280 OpenSoundDevice
*device
= (OpenSoundDevice
*)(devs
.ItemAt(mixerinfo
.card_number
));
282 device
->AddMixer(&mixerinfo
);
285 /* resolve engine chains of shadow engines */
287 for (card
= 0; card
< sysinfo
.numcards
; card
++) {
288 OpenSoundDevice
*device
= (OpenSoundDevice
*)(devs
.ItemAt(card
));
291 for (i
= 0; i
< device
->CountEngines(); i
++) {
292 OpenSoundDeviceEngine
*engine
= device
->EngineAt(i
);
294 if (engine
->Info()->next_play_engine
) {
295 for (j
= 0; j
< device
->CountEngines(); j
++) {
296 OpenSoundDeviceEngine
*next
= device
->EngineAt(j
);
297 if (!next
|| (engine
== next
))
299 if (next
->Info()->dev
== engine
->Info()->next_play_engine
) {
300 PRINT(("OSS: engine[%d].next_play = engine[%d]\n", i
, j
));
301 engine
->fNextPlay
= next
;
306 if (engine
->Info()->next_rec_engine
) {
307 for (j
= 0; j
< device
->CountEngines(); j
++) {
308 OpenSoundDeviceEngine
*next
= device
->EngineAt(j
);
309 if (!next
|| (engine
== next
))
311 if (next
->Info()->dev
== engine
->Info()->next_rec_engine
) {
312 PRINT(("OSS: engine[%d].next_rec = engine[%d]\n", i
, j
));
313 engine
->fNextRec
= next
;
322 /* copy correctly initialized devs to fDevices */
324 for (card
= 0; card
< sysinfo
.numcards
; card
++) {
325 OpenSoundDevice
*device
= (OpenSoundDevice
*)(devs
.ItemAt(card
));
327 if (card
== 0) { /* skip the "oss0" pseudo card device */
331 if ((device
->InitDriver() == B_OK
) && (device
->InitCheck() == B_OK
))
332 fDevices
.AddItem(device
);
337 if (fDevices
.CountItems())
348 if (rootEntry
!= NULL
)
349 root
.SetTo(rootEntry
);
350 else if (rootPath
!= NULL
) {
351 root
.SetTo(rootPath
);
353 PRINT(("Error in OpenSoundAddOn::RecursiveScan null params\n"));
359 while (root
.GetNextEntry(&entry
) > B_ERROR
) {
361 if (entry
.IsDirectory()) {
363 entry
.GetPath(&path
);
364 OpenSoundDevice
*device
= new OpenSoundDevice(path
.Path() + strlen(rootPath
), path
.Path());
366 if (device
->InitCheck() == B_OK
)
367 fDevices
.AddItem(device
);
380 OpenSoundAddOn::SaveSettings(void)
384 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) == B_OK
) {
385 path
.Append(SETTINGS_FILE
);
386 BFile
file(path
.Path(), B_READ_WRITE
| B_CREATE_FILE
| B_ERASE_FILE
);
387 if (file
.InitCheck() == B_OK
)
388 fSettings
.Flatten(&file
);
394 OpenSoundAddOn::LoadSettings(void)
397 fSettings
.MakeEmpty();
400 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) == B_OK
) {
401 path
.Append(SETTINGS_FILE
);
402 BFile
file(path
.Path(), B_READ_ONLY
);
403 if ((file
.InitCheck() == B_OK
) && (fSettings
.Unflatten(&file
) == B_OK
))
405 PRINT_OBJECT(fSettings
);
407 PRINT(("Error unflattening settings file %s\n", path
.Path()));
414 OpenSoundAddOn::RegisterMediaFormats(void)
417 // register non-raw audio formats to the Media Kit
418 #ifdef ENABLE_NON_RAW_SUPPORT
419 OpenSoundDevice::register_media_formats();