home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ioctlapi.zip / appsrc.zip / mixerapi.c < prev    next >
C/C++ Source or Header  |  1999-11-16  |  7KB  |  258 lines

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