1 /* 2 * OpenSound media addon for BeOS and Haiku 3 * 4 * Copyright (c) 2007, François Revol (revol@free.fr) 5 * Distributed under the terms of the MIT License. 6 * 7 * Based on MultiAudio media addon 8 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) 9 */ 10 #include "OpenSoundAddOn.h" 11 12 #include <MediaDefs.h> 13 #include <MediaAddOn.h> 14 #include <Errors.h> 15 #include <Node.h> 16 #include <Mime.h> 17 #include <StorageDefs.h> 18 #include <Path.h> 19 #include <Directory.h> 20 #include <Entry.h> 21 #include <FindDirectory.h> 22 #include <Debug.h> 23 #include <errno.h> 24 25 #include "OpenSoundNode.h" 26 #include "OpenSoundDevice.h" 27 #include "OpenSoundDeviceEngine.h" 28 29 #include <limits.h> 30 #include <stdio.h> 31 #include <string.h> 32 33 #include "debug.h" 34 35 #define MULTI_SAVE 36 37 38 // instantiation function 39 extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) { 40 CALLED(); 41 return new OpenSoundAddOn(image); 42 } 43 44 // -------------------------------------------------------- // 45 // ctor/dtor 46 // -------------------------------------------------------- // 47 48 OpenSoundAddOn::~OpenSoundAddOn() 49 { 50 CALLED(); 51 52 void *device = NULL; 53 for (int32 i = 0; (device = fDevices.ItemAt(i)); i++) 54 delete (OpenSoundDevice *)device; 55 56 SaveSettings(); 57 } 58 59 OpenSoundAddOn::OpenSoundAddOn(image_id image) : 60 BMediaAddOn(image), 61 fDevices() 62 { 63 CALLED(); 64 fInitCheckStatus = B_NO_INIT; 65 66 /* unix paths */ 67 if (RecursiveScan("/dev/oss/") != B_OK) 68 return; 69 /* 70 if (RecursiveScan("/dev/audio/oss/") != B_OK) 71 return; 72 */ 73 74 LoadSettings(); 75 76 fInitCheckStatus = B_OK; 77 } 78 79 // -------------------------------------------------------- // 80 // BMediaAddOn impl 81 // -------------------------------------------------------- // 82 83 status_t OpenSoundAddOn::InitCheck( 84 const char ** out_failure_text) 85 { 86 CALLED(); 87 return B_OK; 88 } 89 90 int32 OpenSoundAddOn::CountFlavors() 91 { 92 CALLED(); 93 PRINT(("%d flavours\n", fDevices.CountItems())); 94 return fDevices.CountItems(); 95 } 96 97 status_t OpenSoundAddOn::GetFlavorAt( 98 int32 n, 99 const flavor_info ** out_info) 100 { 101 CALLED(); 102 if (n < 0 || n > fDevices.CountItems() - 1) { 103 fprintf(stderr, "<- B_BAD_INDEX\n"); 104 return B_BAD_INDEX; 105 } 106 107 OpenSoundDevice *device = (OpenSoundDevice *) fDevices.ItemAt(n); 108 109 flavor_info * infos = new flavor_info[1]; 110 OpenSoundNode::GetFlavor(&infos[0], n); 111 infos[0].name = device->fCardInfo.longname; 112 (*out_info) = infos; 113 return B_OK; 114 } 115 116 BMediaNode * OpenSoundAddOn::InstantiateNodeFor( 117 const flavor_info * info, 118 BMessage * config, 119 status_t * out_error) 120 { 121 CALLED(); 122 123 OpenSoundDevice *device = (OpenSoundDevice*)fDevices.ItemAt( 124 info->internal_id); 125 if (device == NULL) { 126 *out_error = B_ERROR; 127 return NULL; 128 } 129 130 #ifdef MULTI_SAVE 131 if (fSettings.FindMessage(device->fCardInfo.longname, config) == B_OK) { 132 fSettings.RemoveData(device->fCardInfo.longname); 133 } 134 #endif 135 136 OpenSoundNode * node = 137 new OpenSoundNode(this, 138 device->fCardInfo.longname, 139 device, 140 info->internal_id, 141 config); 142 if (node == 0) { 143 *out_error = B_NO_MEMORY; 144 fprintf(stderr, "<- B_NO_MEMORY\n"); 145 } else { 146 *out_error = node->InitCheck(); 147 } 148 return node; 149 } 150 151 status_t 152 OpenSoundAddOn::GetConfigurationFor(BMediaNode * your_node, BMessage * into_message) 153 { 154 CALLED(); 155 #ifdef MULTI_SAVE 156 { 157 into_message = new BMessage(); 158 OpenSoundNode * node = dynamic_cast<OpenSoundNode*>(your_node); 159 if (node == 0) { 160 fprintf(stderr, "<- B_BAD_TYPE\n"); 161 return B_BAD_TYPE; 162 } 163 if (node->GetConfigurationFor(into_message) == B_OK) { 164 fSettings.AddMessage(your_node->Name(), into_message); 165 } 166 return B_OK; 167 } 168 #endif 169 // currently never called by the media kit. Seems it is not implemented. 170 OpenSoundNode * node = dynamic_cast<OpenSoundNode*>(your_node); 171 if (node == 0) { 172 fprintf(stderr, "<- B_BAD_TYPE\n"); 173 return B_BAD_TYPE; 174 } 175 return node->GetConfigurationFor(into_message); 176 } 177 178 179 bool OpenSoundAddOn::WantsAutoStart() 180 { 181 CALLED(); 182 return false; 183 } 184 185 status_t OpenSoundAddOn::AutoStart( 186 int in_count, 187 BMediaNode ** out_node, 188 int32 * out_internal_id, 189 bool * out_has_more) 190 { 191 CALLED(); 192 return B_OK; 193 } 194 195 status_t 196 OpenSoundAddOn::RecursiveScan(char* rootPath, BEntry *rootEntry) 197 { 198 status_t err; 199 int mixer; 200 oss_sysinfo sysinfo; 201 oss_card_info cardinfo; 202 int card, i, j; 203 BList devs; 204 205 CALLED(); 206 207 mixer = open(OSS_MIXER_DEV, O_RDWR); 208 if (mixer < 0) { 209 // try to rescan 210 BFile fDevFS("/dev/.", B_WRITE_ONLY); 211 const char *drv = "oss_loader"; 212 fDevFS.Write(drv, strlen(drv)); 213 mixer = open(OSS_MIXER_DEV, O_RDWR); 214 if (mixer < 0) { 215 err = errno; 216 goto err0; 217 } 218 } 219 220 if (ioctl(mixer, SNDCTL_SYSINFO, &sysinfo) < 0) { 221 err = errno; 222 goto err1; 223 } 224 225 PRINT(("OSS: %s %s (0x%08X)\n", sysinfo.product, sysinfo.version, sysinfo.versionnum)); 226 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)); 227 228 /* construct an empty SoundDevice per card */ 229 230 for (card = 0; card < sysinfo.numcards; card++) { 231 cardinfo.card = card; 232 if (ioctl(mixer, SNDCTL_CARDINFO, &cardinfo) < 0) { 233 err = errno; 234 goto err1; 235 } 236 OpenSoundDevice *device = new OpenSoundDevice(&cardinfo); 237 if (device) 238 devs.AddItem(device); 239 else { 240 err = ENOMEM; 241 goto err1; 242 } 243 } 244 245 /* Add its audio engines to it */ 246 247 for (i = 0; i < sysinfo.numaudioengines; i++) { 248 oss_audioinfo audioinfo; 249 audioinfo.dev = i; 250 if (ioctl(mixer, SNDCTL_ENGINEINFO, &audioinfo, sizeof(oss_audioinfo)) < 0) { 251 err = errno; 252 goto err1; 253 } 254 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)); 255 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(audioinfo.card_number)); 256 if (device) 257 device->AddEngine(&audioinfo); 258 } 259 260 /* Add its mixers to it */ 261 262 for (i = 0; i < sysinfo.nummixers; i++) { 263 oss_mixerinfo mixerinfo; 264 mixerinfo.dev = i; 265 if (ioctl(mixer, SNDCTL_MIXERINFO, &mixerinfo) < 0) { 266 err = errno; 267 goto err1; 268 } 269 PRINT(("OSS: mixer[%d]: card=%d\n", i, mixerinfo.card_number)); 270 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(mixerinfo.card_number)); 271 if (device) 272 device->AddMixer(&mixerinfo); 273 } 274 275 /* resolve engine chains of shadow engines */ 276 277 for (card = 0; card < sysinfo.numcards; card++) { 278 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(card)); 279 if (!device) 280 continue; 281 for (i = 0; i < device->CountEngines(); i++) { 282 OpenSoundDeviceEngine *engine = device->EngineAt(i); 283 if (engine) { 284 if (engine->Info()->next_play_engine) { 285 for (j = 0; j < device->CountEngines(); j++) { 286 OpenSoundDeviceEngine *next = device->EngineAt(j); 287 if (!next || (engine == next)) 288 continue; 289 if (next->Info()->dev == engine->Info()->next_play_engine) { 290 PRINT(("OSS: engine[%d].next_play = engine[%d]\n", i, j)); 291 engine->fNextPlay = next; 292 break; 293 } 294 } 295 } 296 if (engine->Info()->next_rec_engine) { 297 for (j = 0; j < device->CountEngines(); j++) { 298 OpenSoundDeviceEngine *next = device->EngineAt(j); 299 if (!next || (engine == next)) 300 continue; 301 if (next->Info()->dev == engine->Info()->next_rec_engine) { 302 PRINT(("OSS: engine[%d].next_rec = engine[%d]\n", i, j)); 303 engine->fNextRec = next; 304 break; 305 } 306 } 307 } 308 } 309 } 310 } 311 312 /* copy correctly initialized devs to fDevices */ 313 314 for (card = 0; card < sysinfo.numcards; card++) { 315 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(card)); 316 if (device) { 317 if (card == 0) { /* skip the "oss0" pseudo card device */ 318 delete device; 319 continue; 320 } 321 if ((device->InitDriver() == B_OK) && (device->InitCheck() == B_OK)) 322 fDevices.AddItem(device); 323 else 324 delete device; 325 } 326 } 327 if (fDevices.CountItems()) 328 err = B_OK; 329 else 330 err = ENOENT; 331 err1: 332 close(mixer); 333 err0: 334 return err; 335 336 #if MA 337 BDirectory root; 338 if (rootEntry != NULL) 339 root.SetTo(rootEntry); 340 else if (rootPath != NULL) { 341 root.SetTo(rootPath); 342 } else { 343 PRINT(("Error in OpenSoundAddOn::RecursiveScan null params\n")); 344 return B_ERROR; 345 } 346 347 BEntry entry; 348 349 while (root.GetNextEntry(&entry) > B_ERROR) { 350 351 if (entry.IsDirectory()) { 352 BPath path; 353 entry.GetPath(&path); 354 OpenSoundDevice *device = new OpenSoundDevice(path.Path() + strlen(rootPath), path.Path()); 355 if (device) { 356 if (device->InitCheck() == B_OK) 357 fDevices.AddItem(device); 358 else 359 delete device; 360 } 361 } 362 } 363 364 return B_OK; 365 #endif 366 } 367 368 369 void 370 OpenSoundAddOn::SaveSettings(void) 371 { 372 CALLED(); 373 BPath path; 374 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 375 path.Append(SETTINGS_FILE); 376 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 377 if (file.InitCheck() == B_OK) 378 fSettings.Flatten(&file); 379 } 380 } 381 382 383 void 384 OpenSoundAddOn::LoadSettings(void) 385 { 386 CALLED(); 387 fSettings.MakeEmpty(); 388 389 BPath path; 390 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 391 path.Append(SETTINGS_FILE); 392 BFile file(path.Path(), B_READ_ONLY); 393 if ((file.InitCheck() == B_OK) && (fSettings.Unflatten(&file) == B_OK)) 394 { 395 PRINT_OBJECT(fSettings); 396 } else { 397 PRINT(("Error unflattening settings file %s\n", path.Path())); 398 } 399 } 400 } 401 402 403 void 404 OpenSoundAddOn::RegisterMediaFormats(void) 405 { 406 CALLED(); 407 // register non-raw audio formats to the Media Kit 408 #ifdef ENABLE_NON_RAW_SUPPORT 409 OpenSoundDevice::register_media_formats(); 410 #endif 411 412 413 } 414