1 /* OpenCP Module Player 2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de> 3 * copyright (c) '04-'21 Stian Skjelstad <stian.skjelstad@gmail.com> 4 * 5 * Player devices system 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * 21 * revision history: (please note changes here) 22 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de> 23 * -first release 24 * -kb980717 Tammo Hinrichs <opencp@gmx.net> 25 * -changed INI reading of driver symbols to _dllinfo lookup 26 */ 27 28 #include "config.h" 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include "types.h" 33 #include "boot/plinkman.h" 34 #include "boot/psetting.h" 35 #include "devigen.h" 36 #include "deviplay.h" 37 #include "filesel/dirdb.h" 38 #include "filesel/filesystem.h" 39 #include "filesel/filesystem-drive.h" 40 #include "filesel/filesystem-file-mem.h" 41 #include "filesel/filesystem-setup.h" 42 #include "filesel/mdb.h" 43 #include "filesel/pfilesel.h" 44 #include "imsdev.h" 45 #include "player.h" 46 #include "stuff/compat.h" 47 #include "stuff/err.h" 48 49 int (*plrProcessKey)(uint16_t); 50 51 static struct devinfonode *plPlayerDevices; 52 static struct devinfonode *curplaydev; 53 static struct devinfonode *defplaydev; 54 static struct interfacestruct plrIntr; 55 static struct preprocregstruct plrPreprocess; 56 57 int plrBufSize; 58 59 static struct devinfonode *getdevstr(struct devinfonode *n, const char *hnd) 60 { 61 while (n) 62 { 63 if (!strcasecmp(n->handle, hnd)) 64 return n; 65 n=n->next; 66 } 67 return 0; 68 } 69 70 static void setdevice(struct devinfonode **curdev, struct devinfonode *dev) 71 { 72 if (*curdev==dev) 73 return; 74 if (*curdev) 75 { 76 if ((*curdev)->devinfo.devtype->addprocs) 77 if ((*curdev)->devinfo.devtype->addprocs->Close) 78 (*curdev)->devinfo.devtype->addprocs->Close(); 79 plrProcessKey=0; 80 (*curdev)->devinfo.devtype->Close(); 81 if (!(*curdev)->keep) 82 { 83 lnkFree((*curdev)->linkhand); 84 (*curdev)->linkhand=-1; 85 } 86 } 87 (*curdev)=0; 88 if (!dev) 89 return; 90 91 if (dev->linkhand<0) 92 { 93 char lname[22]; 94 strncpy(lname,cfGetProfileString(dev->handle, "link", ""),21); 95 dev->linkhand=lnkLink(lname); 96 if (dev->linkhand<0) 97 { 98 fprintf(stderr, "device load error\n"); 99 return; 100 } 101 dev->devinfo.devtype=(struct sounddevice *)_lnkGetSymbol(lnkReadInfoReg(dev->linkhand, "driver")); 102 if (!dev->devinfo.devtype) 103 { 104 fprintf(stderr, "device symbol error\n"); 105 lnkFree(dev->linkhand); 106 dev->linkhand=-1; 107 return; 108 } 109 } 110 111 fprintf(stderr, "%s selected...\n", dev->name); 112 if (dev->devinfo.devtype->Init(&dev->devinfo)) 113 { 114 if (dev->devinfo.devtype->addprocs) 115 if (dev->devinfo.devtype->addprocs->Init) 116 dev->devinfo.devtype->addprocs->Init(dev->handle); 117 if (dev->devinfo.devtype->addprocs) 118 if (dev->devinfo.devtype->addprocs->ProcessKey) 119 plrProcessKey=dev->devinfo.devtype->addprocs->ProcessKey; 120 (*curdev)=dev; 121 return; 122 } 123 if (*curdev) 124 if (!(*curdev)->keep) 125 { 126 lnkFree((*curdev)->linkhand); 127 (*curdev)->linkhand=-1; 128 } 129 fprintf(stderr, "device init error\n"); 130 } 131 132 static void plrSetDevice(const char *name, int def) 133 { 134 setdevice(&curplaydev, getdevstr(plPlayerDevices, name)); 135 if (def) 136 defplaydev=curplaydev; 137 } 138 139 static void plrResetDevice(void) 140 { 141 setdevice(&curplaydev, defplaydev); 142 } 143 144 struct file_devp_t 145 { 146 struct ocpfile_t head; 147 // uint32_t filesize; 148 struct devinfonode *dev; 149 }; 150 151 static void file_devp_ref (struct ocpfile_t *_self) 152 { 153 struct file_devp_t *self = (struct file_devp_t *)_self; 154 self->head.refcount++; 155 } 156 static void file_devp_unref (struct ocpfile_t *_self) 157 { 158 struct file_devp_t *self = (struct file_devp_t *)_self; 159 self->head.refcount--; 160 if (!self->head.refcount) 161 { 162 dirdbUnref (self->head.dirdb_ref, dirdb_use_file); 163 free (self); 164 } 165 } 166 167 static struct ocpfilehandle_t *file_devp_open (struct ocpfile_t *_self) 168 { 169 struct file_devp_t *self = (struct file_devp_t *)_self; 170 char *buffer = strdup (plrIntr.name); 171 struct ocpfilehandle_t *retval = mem_filehandle_open (/*self->head.parent,*/ self->head.dirdb_ref, buffer, strlen (plrIntr.name)); 172 if (!retval) 173 { 174 free (buffer); 175 } 176 return retval; 177 } 178 179 static uint64_t file_devp_filesize (struct ocpfile_t *_self) 180 { 181 return strlen (plrIntr.name); 182 } 183 184 static int file_devp_filesize_ready (struct ocpfile_t *_self) 185 { 186 return 1; 187 } 188 189 static struct ocpdir_t dir_devp; 190 191 static void dir_devp_ref (struct ocpdir_t *self) 192 { 193 } 194 static void dir_devp_unref (struct ocpdir_t *self) 195 { 196 } 197 198 struct dir_devp_handle_t 199 { 200 void (*callback_file)(void *token, struct ocpfile_t *); 201 void *token; 202 struct ocpdir_t *owner; 203 struct devinfonode *next; 204 }; 205 static ocpdirhandle_pt dir_devp_readdir_start (struct ocpdir_t *self, void (*callback_file)(void *token, struct ocpfile_t *), 206 void (*callback_dir )(void *token, struct ocpdir_t *), void *token) 207 { 208 struct dir_devp_handle_t *retval = malloc (sizeof (*retval)); 209 if (!retval) 210 { 211 return 0; 212 } 213 retval->callback_file = callback_file; 214 retval->token = token; 215 retval->owner = self; 216 retval->next = plPlayerDevices; 217 self->ref(self); 218 return retval; 219 }; 220 221 static void dir_devp_readdir_cancel (ocpdirhandle_pt _handle) 222 { 223 struct dir_devp_handle_t *handle = (struct dir_devp_handle_t *)_handle; 224 handle->owner->unref (handle->owner); 225 free (handle); 226 } 227 228 static int dir_devp_readdir_iterate (ocpdirhandle_pt _handle) 229 { 230 struct devinfonode *iter; 231 struct dir_devp_handle_t *handle = (struct dir_devp_handle_t *)_handle; 232 233 for (iter = plPlayerDevices; iter; iter = iter->next) 234 { 235 if (handle->next == iter) 236 { 237 struct file_devp_t *file = malloc (sizeof (*file)); 238 if (file) 239 { 240 char npath[64]; 241 uint32_t mdb_ref; 242 243 snprintf (npath, sizeof(npath), "%s.DEV", iter->handle); 244 245 ocpfile_t_fill (&file->head, 246 file_devp_ref, 247 file_devp_unref, 248 handle->owner, 249 file_devp_open, 250 file_devp_filesize, 251 file_devp_filesize_ready, 252 dirdbFindAndRef (handle->owner->dirdb_ref, npath, dirdb_use_file), 253 1, /* refcount */ 254 1 /* is_nodetect */); 255 /* file->filesize = iter->devinfo.mem; */ 256 file->dev = iter; 257 258 mdb_ref = mdbGetModuleReference2 (file->head.dirdb_ref, strlen (plrIntr.name)); 259 if (mdb_ref!=0xffffffff) 260 { 261 struct moduleinfostruct mi; 262 mdbGetModuleInfo(&mi, mdb_ref); 263 mi.flags1 &= ~MDB_VIRTUAL; 264 mi.channels = iter->devinfo.chan; 265 snprintf (mi.modname, sizeof(mi.modname), "%s", iter->name); 266 mi.modtype = mtDEVv; 267 mdbWriteModuleInfo (mdb_ref, &mi); 268 } 269 handle->callback_file (handle->token, &file->head); 270 file->head.unref (&file->head); 271 } 272 handle->next = iter->next; 273 return 1; 274 } 275 } 276 return 0; 277 } 278 279 static struct ocpdir_t *dir_devp_readdir_dir (struct ocpdir_t *_self, uint32_t dirdb_ref) 280 { 281 /* this can not succeed */ 282 return 0; 283 } 284 285 static struct ocpfile_t *dir_devp_readdir_file (struct ocpdir_t *_self, uint32_t dirdb_ref) 286 { 287 struct devinfonode *iter; 288 char *searchpath = 0; 289 290 uint32_t parent_dirdb_ref; 291 292 /* assertion begin */ 293 parent_dirdb_ref = dirdbGetParentAndRef (dirdb_ref, dirdb_use_file); 294 dirdbUnref (parent_dirdb_ref, dirdb_use_file); 295 if (parent_dirdb_ref != _self->dirdb_ref) 296 { 297 fprintf (stderr, "dir_devp_readdir_file: dirdb_ref->parent is not the expected value\n"); 298 return 0; 299 } 300 /* assertion end */ 301 302 dirdbGetName_internalstr (dirdb_ref, &searchpath); 303 if (!searchpath) 304 { 305 return 0; 306 } 307 308 for (iter = plPlayerDevices; iter; iter = iter->next) 309 { 310 char npath[64]; 311 struct file_devp_t *file; 312 uint32_t mdb_ref; 313 314 snprintf (npath, sizeof(npath), "%s.DEV", iter->handle); 315 316 if (strcmp (npath, searchpath)) 317 { 318 continue; 319 } 320 321 file = malloc (sizeof (*file)); 322 if (!file) 323 { 324 fprintf (stderr, "dir_devp_readdir_file: out of memory\n"); 325 return 0; 326 } 327 328 ocpfile_t_fill (&file->head, 329 file_devp_ref, 330 file_devp_unref, 331 _self, 332 file_devp_open, 333 file_devp_filesize, 334 file_devp_filesize_ready, 335 dirdbRef (dirdb_ref, dirdb_use_file), 336 1, /* refcount */ 337 1 /* is_nodetect */); 338 339 /* file->filesize = iter->devinfo.mem; */ 340 file->dev = iter; 341 342 mdb_ref = mdbGetModuleReference2 (file->head.dirdb_ref, strlen (plrIntr.name)); 343 if (mdb_ref!=0xffffffff) 344 { 345 struct moduleinfostruct mi; 346 mdbGetModuleInfo(&mi, mdb_ref); 347 mi.flags1 &= ~MDB_VIRTUAL; 348 mi.channels = iter->devinfo.chan; 349 snprintf (mi.modname, sizeof(mi.modname), "%s", iter->name); 350 mi.modtype = mtDEVv; 351 mdbWriteModuleInfo (mdb_ref, &mi); 352 } 353 354 return &file->head; 355 } 356 return 0; 357 } 358 359 static int playdevinited = 0; 360 static int playdevinit(void) 361 { 362 const char *def; 363 364 #ifdef INITCLOSE_DEBUG 365 fprintf(stderr, "playdevinit... trying to init all sound devices [sound]->playerdevices\n"); 366 #endif 367 368 playdevinited = 1; 369 370 plRegisterInterface (&plrIntr); 371 plRegisterPreprocess (&plrPreprocess); 372 373 ocpdir_t_fill (&dir_devp, 374 dir_devp_ref, 375 dir_devp_unref, 376 dmSetup->basedir, 377 dir_devp_readdir_start, 378 0, 379 dir_devp_readdir_cancel, 380 dir_devp_readdir_iterate, 381 dir_devp_readdir_dir, 382 dir_devp_readdir_file, 383 0, 384 dirdbFindAndRef (dmSetup->basedir->dirdb_ref, "devp", dirdb_use_dir), 385 0, /* refcount, not used */ 386 0, /* is_archive */ 387 0 /* is_playlist */); 388 filesystem_setup_register_dir (&dir_devp); 389 390 if (!strlen(cfGetProfileString2(cfSoundSec, "sound", "playerdevices", ""))) 391 return errOk; 392 fprintf(stderr, "playerdevices:\n"); 393 if (!deviReadDevices(cfGetProfileString2(cfSoundSec, "sound", "playerdevices", ""), &plPlayerDevices)) 394 { 395 fprintf(stderr, "could not install player devices!\n"); 396 return errGen; 397 } 398 399 curplaydev=0; 400 defplaydev=0; 401 402 def=cfGetProfileString("commandline_s", "p", cfGetProfileString2(cfSoundSec, "sound", "defplayer", "")); 403 404 if (strlen(def)) 405 plrSetDevice(def, 1); 406 else 407 if (plPlayerDevices) 408 plrSetDevice(plPlayerDevices->handle, 1); 409 410 fprintf(stderr, "\n"); 411 412 plrBufSize=cfGetProfileInt2(cfSoundSec, "sound", "plrbufsize", 100, 10); 413 if (plrBufSize <= 0) 414 { 415 plrBufSize = 1; 416 } 417 if (plrBufSize >= 5000) 418 { 419 plrBufSize = 5000; 420 } 421 422 if (!curplaydev) 423 { 424 fprintf (stderr, "Output device not set\n"); 425 return errGen; 426 } 427 428 return errOk; 429 } 430 431 static void playdevclose(void) 432 { 433 #ifdef INITCLOSE_DEBUG 434 fprintf(stderr, "playdevclose...\n"); 435 #endif 436 437 if (playdevinited) 438 { 439 filesystem_setup_unregister_dir (&dir_devp); 440 dirdbUnref (dir_devp.dirdb_ref, dirdb_use_dir); 441 442 plUnregisterInterface (&plrIntr); 443 plUnregisterPreprocess (&plrPreprocess); 444 445 playdevinited = 0; 446 } 447 448 setdevice(&curplaydev, 0); 449 450 while (plPlayerDevices) 451 { 452 struct devinfonode *o=plPlayerDevices; 453 plPlayerDevices=plPlayerDevices->next; 454 free(o); 455 } 456 } 457 458 static int plrSetDev(struct moduleinfostruct *mi, struct ocpfilehandle_t *fp) 459 { 460 char *path, *name; 461 462 if (mi->modtype != mtDEVv) 463 { 464 return 0; 465 } 466 467 dirdbGetName_internalstr (fp->dirdb_ref, &path); 468 splitpath4_malloc (path, 0, 0, &name, 0); 469 470 plrSetDevice(name, 1); 471 472 free (name); 473 474 return 0; 475 } 476 477 478 static void plrPrep(struct moduleinfostruct *m, struct ocpfilehandle_t **bp) 479 { 480 plrResetDevice(); 481 } 482 483 static struct interfacestruct plrIntr = {plrSetDev, 0, 0, "plrIntr" INTERFACESTRUCT_TAIL}; 484 static struct preprocregstruct plrPreprocess = {plrPrep PREPROCREGSTRUCT_TAIL}; 485 #ifndef SUPPORT_STATIC_PLUGINS 486 char *dllinfo = ""; 487 #endif 488 DLLEXTINFO_PREFIX struct linkinfostruct dllextinfo = {.name = "plrbase", .desc = "OpenCP Player Devices System (c) 1994-21 Niklas Beisert, Tammo Hinrichs, Stian Skjelstad", .ver = DLLVERSION, .size = 0, .Init = playdevinit, .Close = playdevclose}; 489