home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Multimed / Multimed.zip / lbmix04.zip / PipeMix / Source / mixerapi.c < prev    next >
C/C++ Source or Header  |  2000-03-09  |  6KB  |  224 lines

  1. //-----------------------------------------------------------------------------
  2. // Freeware.  This file may be used freely to promote the ioctl90 mixer API.
  3. //-----------------------------------------------------------------------------
  4.  
  5. // mixerapi.c
  6.  
  7. /* Modified by Lesha Bogdanow:
  8.    Removed fprintfs, added check for CALLBACKREG function presence,
  9.    Moved PddName[] to global vars, modified to autodetect only if not set initially
  10. */
  11.  
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <process.h>
  15. #include <signal.h>
  16. #include <memory.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <io.h>
  20.  
  21. #define USE_OS2_TOOLKIT_HEADERS
  22. #define INCL_DOSPROCESS      // DosSleep
  23. #define INCL_DOSDEVICES      // DosDevIOCtl 
  24. #define INCL_DOSFILEMGR      // DosDevIOCtl 
  25. #define INCL_DOSSEMAPHORES   // Semaphore values
  26. #define INCL_DOSDATETIME     // Timer support
  27. #define INCL_DOSERRORS       // DOS error values
  28. #include <os2.h>
  29.  
  30. #include "pddname.h"
  31. #include "ioctl90.h"
  32. #include "mixerapi.h"
  33.  
  34. HFILE hDriver = 0;
  35. NPFN  CallbackFunc = NULL;
  36. HEV   hevCallback = 0;
  37. BOOL  fCallbackThreadAlive = FALSE;
  38. char  szPddName [14]="\0";  // "\\DEV\\12345678"
  39.  
  40. HFILE DevOpen (char *ddName)
  41. {
  42.    ULONG ulRC;
  43.    ULONG OpenFlags;
  44.    ULONG OpenMode;
  45.    ULONG ulFileSize      = 0;
  46.    ULONG ulFileAttribute = 0;
  47.    ULONG ulActionTaken   = 0;
  48.    HFILE hPdd            = 0;
  49.  
  50.    OpenFlags = OPEN_ACTION_OPEN_IF_EXISTS;   // Do not create file
  51.  
  52.    OpenMode  = OPEN_ACCESS_READWRITE +       // Read/Write file
  53.                OPEN_SHARE_DENYNONE +         // Non-exclusive access
  54.                OPEN_FLAGS_FAIL_ON_ERROR;     // No system popups on errors
  55.  
  56.    ulRC = DosOpen (ddName,          // in
  57.                    &hPdd,           //    out (handle)
  58.                    &ulActionTaken,  //    out
  59.                    ulFileSize,      // in
  60.                    ulFileAttribute, // in
  61.                    OpenFlags,       // in
  62.                    OpenMode,        // in
  63.                    NULL);           // in
  64.  
  65.    if (ulRC != 0)
  66.       hPdd = 0;
  67.  
  68.    return (hPdd);
  69. }
  70.  
  71.  
  72. ULONG mixerapiIOCTL90 (USHORT usFunc, PVOID pv, ULONG ulSizeofPV)
  73. {
  74.    ULONG ulRC;
  75.    ULONG ulSize;
  76.  
  77.    ulSize = ulSizeofPV;
  78.  
  79.    ulRC = DosDevIOCtl 
  80.       (hDriver,            // Device Handle
  81.        0x90,               // Category (user defined >= 0x80)
  82.        usFunc,             // Function (User defined function >= 0x40)
  83.        NULL,               // in      Address of parm data (not used)
  84.        0,                  // in      Max size of parm data structure
  85.        NULL,               // in out  Actual size of parm data structure
  86.        pv,                 // in      Address of command data
  87.        ulSize,             // in      Maximum size of command data
  88.        &ulSize);           // in out  Size of command data returned
  89.  
  90.    return (ulRC);
  91. }
  92.  
  93.  
  94. // Function runs as independent thread
  95. //
  96. // Thread is used for callbacks from audio device driver.
  97. // Audio device driver posts an event semaphore each time
  98. // something changes.  With the notification, multiple mixer
  99. // client applications can track each others settings.
  100. void CallbackThreadFunc (void *arglist)
  101. {
  102.    ULONG ulRC;
  103.    ULONG ulZero = 0;
  104.  
  105.    // Give semaphore handle to PDD so it can post the sem
  106.    ulRC = mixerapiIOCTL90 (CALLBACKREG, &hevCallback, sizeof(hevCallback));
  107.    if (ulRC != 0)
  108.    {
  109.       // Could get here if PDD does not implement callback support
  110.       _endthread ();
  111.    }
  112.  
  113.    // Loop forever - spending most of our time blocked.
  114.    // When the PDD handles a mixer change, it will post
  115.    // the semaphore - causing this thread to wake up.
  116.  
  117.    // Primary thread sets this callback address to NULL 
  118.    // when it wants this thread to terminate
  119.    while (CallbackFunc)
  120.    {
  121.       ulRC = DosWaitEventSem (hevCallback, (ULONG)SEM_INDEFINITE_WAIT);
  122.  
  123.       if (ulRC != 0) break;
  124.  
  125.       // Call the client function (inform of mixer change)
  126.       if (CallbackFunc)
  127.          CallbackFunc();
  128.    }
  129.  
  130.    // Tell PDD that we no longer want to receive callbacks.
  131.    ulRC = mixerapiIOCTL90 (CALLBACKREG, &ulZero, sizeof(ulZero));
  132.  
  133.    // Inform primary thread that we are gone
  134.    fCallbackThreadAlive = FALSE;
  135.    _endthread ();
  136. }
  137.  
  138.  
  139. void mixerapiDeInit (void)
  140. {
  141.    ULONG ulRC;
  142.    ULONG ulPostCount;
  143.  
  144.    // Tell callback thread to terminate
  145.    CallbackFunc = NULL; 
  146.  
  147.    // While callback thread is still alive
  148.    while (fCallbackThreadAlive)
  149.    {
  150.       // Post semaphore so that callback thread gets a chance to run
  151.       // Only need to post the sem if it isn't already posted
  152.       ulRC = DosQueryEventSem (hevCallback, &ulPostCount);
  153.       if (ulRC != 0) break;
  154.  
  155.       if (ulPostCount == 0)
  156.       {
  157.          ulRC = DosPostEventSem (hevCallback);
  158.  
  159.          // When post the sem, must also reset it or it will post forever
  160.          ulRC = DosResetEventSem (hevCallback, &ulPostCount);
  161.       }
  162.  
  163.       // Let other threads run (hevCallback will be cleared by other thread)
  164.       DosSleep (1);
  165.    }
  166.  
  167.    if (hevCallback)
  168.    {
  169.       // We are done with the sem
  170.       ulRC = DosCloseEventSem (hevCallback);
  171.       hevCallback = 0;
  172.    }
  173.  
  174.    if (hDriver != 0)
  175.    {
  176.       DosClose (hDriver);
  177.       hDriver = 0;
  178.    }
  179. }
  180.  
  181.  
  182. ULONG mixerapiInit (NPFN npfnCallback)
  183. {
  184.    ULONG    ulRC;
  185.    unsigned char ApiMap[256];
  186.  
  187.    if (!*szPddName) {
  188.       strcpy (szPddName, "\\DEV\\");
  189.       ulRC = GetAudioPDDName (&szPddName[5]);
  190.       if (ulRC != 0) return (ulRC);
  191.       }
  192.  
  193.    hDriver = DevOpen (szPddName);
  194.  
  195.    if (hDriver == 0) ulRC = 1;
  196.    else
  197.    {
  198.       ulRC=mixerapiIOCTL90(GETAPIMAP,ApiMap,256);
  199.       if (ulRC) return ulRC;
  200.       if (ApiMap[CALLBACKREG])
  201.       {
  202.          ulRC = 0;
  203.          CallbackFunc = npfnCallback;
  204.  
  205.          // Create shared ring-3/ring-0 event semaphore.
  206.          // Device driver posts this semaphore when other mixer applications
  207.          // make changes to the mixer.  The semaphore must be created "shared".
  208.          ulRC = DosCreateEventSem (NULL, &hevCallback, DC_SEM_SHARED, FALSE);
  209.          if (ulRC != 0) hevCallback = 0;
  210.          else
  211.          {
  212.             fCallbackThreadAlive = TRUE;
  213.             if (_beginthread (CallbackThreadFunc, NULL, 32*1024, NULL) == -1)
  214.             {
  215.                CallbackFunc = NULL;
  216.                ulRC = 1;
  217.             }
  218.          }
  219.       }
  220.    }
  221.  
  222.    return (ulRC);
  223. }
  224.