Author Topic: Strange behaviour in SDL2  (Read 8155 times)

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #15 on: June 28, 2023, 07:07:48 pm »
Definitely, only one internal audio device. And, as I said before, with a USB headset, I get the same doubling, with the seocnd device being locked immediately.

Dave Yeo

  • Hero Member
  • *****
  • Posts: 4630
  • Karma: +93/-1
    • View Profile
Re: Strange behaviour in SDL2
« Reply #16 on: June 29, 2023, 01:41:34 am »
Definitely, only one internal audio device. And, as I said before, with a USB headset, I get the same doubling, with the seocnd device being locked immediately.

Was the 2nd device visible in the output from prboom-plus or only on your test app? If only on your test app, could you post it?

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #17 on: June 29, 2023, 04:32:21 pm »
Yesterday, I got around to testing with a USB headset and the following are my observations:
  • SDL detects the audio devices by sending MCI_SYSINFO_QUANTITY with type set to MCI_DEVTYPE_AUDIO_AMPMIX.
    This only detects the selected default audio and it always gets two devices. Since the second is always locked, when the first is used, I suspect, the system returns one device for output and one for input. I already tried to get the device capabilities, but failed.
    I also don't whether the detection of only the default device is the expected behaviour.
  • Starting PrBoom with the USB headset plugged in, the sound is not starting sometimes. But the trick to change the master volume doesn't work here. Also, I also see Martin's observation that, when the sound starts, it will run (with occasional hickups) and not cut out, like the builtin sound card.
I really don't know whether it's any drivers fault, or whether PrBoom does things, it will get away with on other systems.

I works differently (from my experience from the past).
MCI_SYSINFO_QUANTITY, asking for MCI_DEVTYPE_AUDIO_AMPMIX will return to you as many devices as you have sound drivers installed (simplified way of saying). That's because each audio driver installation will install one MCI_DEVTYPE_AUDIO_WAVEFORM_AUDIO device (and/or potentially a MCI_DEVTYPE_SEQUENCER for MIDI) and also one MCI_DEVTYPE_AUDIO_AMPMIX device (the latter was added late in Warp 3 in order to support DART and new mixing functionality and you have to have such a device in order to play sound at all).
Therefore if you install both USB audio drivers (USBAUDIO.SYS and USBAUD2.SYS) you will be reported back two MCI_DEVTYPE_AUDIO_AMPMIX devices. If you additionally installed UNIAUD, you'd get reported three MCI_DEVTYPE_AUDIO_AMPMIX devices. You cannot tell from that response what is the default ampmix (waveform audio) device.

If you want to identify the default audio device (which is equivalent to identifiying the default ampmix device), then you will need to use MCI_SYSINFO_ITEM / MCI_SYSINFO_QUERY_DEFAULT and specify in the MCI_SYSINFO_DEFAULTDEVICE usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX.

Please note that the default ampmix (and wave audio) device would need to be set in MMPM2.INI which either happens "by hand" or better by either the selection utility that comes with the USBAUDIO installation (integrated into the Multimedia Object, look there) or by the automatic default audio device selection tool that comes with ArcaOS.
« Last Edit: June 29, 2023, 04:52:58 pm by Lars »

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #18 on: June 29, 2023, 06:35:17 pm »
I works differently (from my experience from the past).
MCI_SYSINFO_QUANTITY, asking for MCI_DEVTYPE_AUDIO_AMPMIX will return to you as many devices as you have sound drivers installed (simplified way of saying). That's because each audio driver installation will install one MCI_DEVTYPE_AUDIO_WAVEFORM_AUDIO device (and/or potentially a MCI_DEVTYPE_SEQUENCER for MIDI) and also one MCI_DEVTYPE_AUDIO_AMPMIX device (the latter was added late in Warp 3 in order to support DART and new mixing functionality and you have to have such a device in order to play sound at all).
Therefore if you install both USB audio drivers (USBAUDIO.SYS and USBAUD2.SYS) you will be reported back two MCI_DEVTYPE_AUDIO_AMPMIX devices. If you additionally installed UNIAUD, you'd get reported three MCI_DEVTYPE_AUDIO_AMPMIX devices. You cannot tell from that response what is the default ampmix (waveform audio) device.

If you want to identify the default audio device (which is equivalent to identifiying the default ampmix device), then you will need to use MCI_SYSINFO_ITEM / MCI_SYSINFO_QUERY_DEFAULT and specify in the MCI_SYSINFO_DEFAULTDEVICE usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX.

Please note that the default ampmix (and wave audio) device would need to be set in MMPM2.INI which either happens "by hand" or better by either the selection utility that comes with the USBAUDIO installation (integrated into the Multimedia Object, look there) or by the automatic default audio device selection tool that comes with ArcaOS.
SDL2 correctly wants to enumerate all known devices. The weird thing is, that it always shown two devices with the same name, even when UNIAUD is installed and the USB headset is plugged in. I switched the default setting on the Multimedia Object, but I don't seem to recall the automatic selection tool on ArcaOS, you mentioned. Where is that located?
I'm pretty positive, that I only have usbaudio.sys in config.sys, but I would have verify it, if I have access to my machine again.

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #19 on: June 30, 2023, 07:05:44 am »
Maybe you can point me to the SDL code, or I could write some sample code as obviously, something is going wrong. I have never seen what you are stating.
It would also be helpful if you posted your MMPM2.INI file (in the MMOS2 subdirectory. It's a simple text file).

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #20 on: June 30, 2023, 07:21:11 am »
I already found one error in the SDL device enumeration code.
The device index is 1-based and not 0-based:

Code: [Select]
ulDevicesNum = atol( stMCISysInfo.pszReturn );

  for( stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum; /* should be: ulNumber = 1; ulNumber <= ulDevicesNum */
       stSysInfoParams.ulNumber++ )
  {
    // Get device install name.
    stSysInfoParams.pszReturn    = &acBuf;
    stSysInfoParams.ulRetSize    = sizeof( acBuf );
    stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
    ulRC = mciSendCommand( 0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
                           &stSysInfoParams, 0 );
    if ( ulRC != NO_ERROR )
    {
      debug( "MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC );
      continue;
    }

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #21 on: June 30, 2023, 07:27:53 am »
Here is some code. Note that I am not only querying/setting the default ampmix device but at the same time, also the default audio device. Strictly speaking that is not necessary but a sensible descriptive name is only given to the audio device (during installation) and not the ampmix device. I am going the extra mile to query the ampmix device from the audio device via the audio device's first connector. Again, that is not strictly necessary.

Code: [Select]
MRESULT EXPENTRY SettingsPageProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2) {
   CHAR retBuff[256];
   CHAR ListBoxString[MAX_DEVICE_NAME+MAX_ALIAS_NAME+16];
   MCI_SYSINFO_PARMS sysParms;
   MCI_SYSINFO_DEFAULTDEVICE defDevice;
   MCI_SYSINFO_QUERY_NAME    devName;
   MCI_SYSINFO_CONPARAMS     wavConnectors;
   ULONG rc;

   switch(msg)
   {
      case WM_INITDLG:
      {
         ULONG numDevices=0;
         CHAR *endPtr = NULL;
         PDEVINFO pDevInfo = NULL;
         ULONG i=0;
         HWND hwndListBox = WinWindowFromID(hwnd,ID_LISTBOX);

         memset(retBuff,0,sizeof(retBuff));
         memset(&sysParms,0,sizeof(sysParms));
         sysParms.usDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
         sysParms.pszReturn    = retBuff;
         sysParms.ulRetSize    = sizeof(retBuff)-1;
         rc = mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT,&sysParms,0);

         numDevices = strtoul(sysParms.pszReturn,&endPtr,10);
     
         pDevInfo = (PDEVINFO)calloc(numDevices,sizeof(DEVINFO));
         WinSetWindowPtr(hwnd,QWL_USER,pDevInfo);
         if (!pDevInfo) {
            return MRFROMLONG(FALSE);
         } /* endif */
         for (i=0;i<numDevices;i++) {
            /*device numbers are 1-based (1: first device) */
            memset(&sysParms,0,sizeof(sysParms));
            sysParms.usDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
            sysParms.ulNumber     = i+1;
            sysParms.pszReturn    = retBuff;
            sysParms.ulRetSize    = sizeof(retBuff)-1;
            rc = mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME | MCI_WAIT,&sysParms,0);
           
            memset(&sysParms,0,sizeof(&sysParms));
            sysParms.pszReturn    = retBuff;
            sysParms.ulRetSize    = sizeof(retBuff)-1;
            sysParms.ulItem       = MCI_SYSINFO_QUERY_NAMES;
            sysParms.pSysInfoParm = &devName;
            memset(&devName,0,sizeof(devName));
            strcpy(devName.szInstallName,sysParms.pszReturn);
            rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);

            strcpy(pDevInfo[i].szWaveInstallName,devName.szInstallName);
            strcpy(pDevInfo[i].szWaveAliasName,devName.szAliasName);

            memset(&sysParms,0,sizeof(sysParms));
            sysParms.pszReturn    = retBuff;
            sysParms.ulRetSize    = sizeof(retBuff)-1;
            sysParms.ulItem       = MCI_SYSINFO_QUERY_CONNECTORS;
            sysParms.pSysInfoParm = &wavConnectors;
            memset(&wavConnectors,0,sizeof(wavConnectors));
            strcpy(wavConnectors.szInstallName,sysParms.pszReturn);
            rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);

            if (MCI_WAVE_STREAM_CONNECTOR == wavConnectors.ConnectorList[0].usConnectType) {
               memset(&sysParms,0,sizeof(sysParms));
               sysParms.pszReturn    = retBuff;
               sysParms.ulRetSize    = sizeof(retBuff)-1;
               sysParms.ulItem       = MCI_SYSINFO_QUERY_NAMES;
               sysParms.pSysInfoParm = &devName;
               memset(&devName,0,sizeof(devName));
               strcpy(devName.szInstallName,wavConnectors.ConnectorList[0].szToInstallName);
               rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);

               strcpy(pDevInfo[i].szAmpInstallName,devName.szInstallName);
               strcpy(pDevInfo[i].szAmpAliasName,devName.szAliasName);
            } /* endif */
            sprintf(ListBoxString,"%s (%s)",pDevInfo[i].szWaveAliasName,pDevInfo[i].szAmpAliasName);
            WinSendMsg(hwndListBox,LM_INSERTITEM,MPFROMSHORT(i),MPFROMP(ListBoxString));
            WinSendMsg(hwndListBox,LM_SETITEMHANDLE,MPFROMSHORT(i),MPFROMLONG((ULONG)(pDevInfo+i)));

            memset(&sysParms,0,sizeof(sysParms));
            sysParms.pszReturn     = retBuff;
            sysParms.ulRetSize     = sizeof(retBuff)-1;
            sysParms.ulItem        = MCI_SYSINFO_QUERY_DEFAULT;
            sysParms.pSysInfoParm  = &defDevice;
            memset(&defDevice,0,sizeof(defDevice));
            defDevice.usDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
            rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);

            if (0 == strcmp(defDevice.szInstallName,pDevInfo[i].szWaveInstallName)) {
               WinSendMsg(hwndListBox,LM_SELECTITEM,MPFROMSHORT(i),MPFROMSHORT(TRUE));
            }
         } /* endfor */
         return MRFROMLONG(TRUE);
      }
      break;

      case WM_CONTROL:
      {
         if (LN_ENTER == SHORT2FROMMP(mp1)) {
            HWND hwndListBox = HWNDFROMMP(mp2);
            SHORT i = SHORT1FROMMR(WinSendMsg(hwndListBox,LM_QUERYSELECTION,MPFROMSHORT(0),MPVOID));
            PDEVINFO pDevInfo = (PDEVINFO)PVOIDFROMMR(WinSendMsg(hwndListBox,LM_QUERYITEMHANDLE,MPFROMSHORT(i),MPVOID));
            if (!pDevInfo) {
               return MRFROMLONG(0);
            } /* endif */
           
            memset(&sysParms,0,sizeof(sysParms));
            sysParms.pszReturn     = retBuff;
            sysParms.ulRetSize     = sizeof(retBuff)-1;
            sysParms.ulItem        = MCI_SYSINFO_SET_DEFAULT;
            sysParms.pSysInfoParm  = &defDevice;
            strcpy(defDevice.szInstallName,pDevInfo->szWaveInstallName);
            defDevice.usDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
            rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);
   
            memset(&sysParms,0,sizeof(sysParms));
            sysParms.pszReturn     = retBuff;
            sysParms.ulRetSize     = sizeof(retBuff)-1;
            sysParms.ulItem        = MCI_SYSINFO_SET_DEFAULT;
            sysParms.pSysInfoParm  = &defDevice;
            strcpy(defDevice.szInstallName,pDevInfo->szAmpInstallName);
            defDevice.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
            rc = mciSendCommand(0,MCI_SYSINFO,MCI_SYSINFO_ITEM | MCI_WAIT,&sysParms,0);
         }
         return MRFROMLONG(0);
      }
      break;
« Last Edit: June 30, 2023, 07:39:37 am by Lars »

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #22 on: June 30, 2023, 10:59:47 am »
@Lars: Now we are getting somewhere. With the index beginning with 1, I'm getting two different driver names.
But now, I get a "Hardware Error" return from MCI_OPEN. If I understand the documentation correctly, one opens a device with its driver name, not with the index from the device enumeration.
Is my understanding correct?

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #23 on: June 30, 2023, 11:43:12 am »
Well, it is convoluted to say the least.

  • you need to open an audio device if you are not using DART. You need to open an amplifier device if you are using DART.
  • if not using DART there are several different ways to call MCI_OPEN:
    • you can pass a filename and MMPM will guestimate from the filename extension what device to open.
    • you can open a playlist. A playlist basically contains pointers to sound data and commands (play,end, etc.). This is kind of superseded by DART and therefore no longer all that valuable.
    • you can open a sound file via mmioOpen and pass the handle of that file. Kind of the first approach, except for you explicitely open the sound file
    • you can explicitely select a device via its device type (audio, ampmix, etc.). In that case, you would then subsequently need to call MCI_LOAD (I seem to remember) to actually load a sound file.

Note for all the mechanisms: if you have not specified a default device (in MMPM2.INI) then the "first in the list" will be picked. Potentially not what you want. You can get out of the misery by using the open mechanism via device type as that allows you to qualify a specific device (once you have built yourself a list of what devices exist).

So, you have quite some options. I'll look around at home and see if I can provide some sample code.
But you should make DART vs. non-DART the first decision. Today, for timing critical stuff, apps usually choose DART (or something that builds on top of that). But if you use DART, you will have to know the exact format the data is in (num channels, sample rate, bit depth) because you cannot make use of the autodetection features of MMPM (DART kind of bypasses parts of MMPM).
« Last Edit: June 30, 2023, 11:58:55 am by Lars »

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #24 on: June 30, 2023, 12:45:38 pm »
Hi Lars.

It uses DART. The code, I'm referencing, is in https://github.com/josch1710/SDL2-os2/blob/master/src/audio/os2/SDL_os2audio.c.

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #25 on: June 30, 2023, 01:48:47 pm »
The code is under the wrong assumption that you could pass a handle to MCI_OPEN.
The opposite is true: MCI_OPEN returns a handle that you have to use on all subsequent calls.
You will need to slightly change the design.
Ignore the handle and add a usDeviceId to the hidden/private structure and keep using that.
« Last Edit: June 30, 2023, 01:54:30 pm by Lars »

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #26 on: June 30, 2023, 02:18:13 pm »
Actually, the code uses the returned device id (if this is what you meant).
My question would be then, how to open the selected card in MCI_OPEN? What identifier is needed to say open the USB audio card instead of the internal card?

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #27 on: June 30, 2023, 03:21:59 pm »
Also, what you would need to do is build a list of devices in the SDL_DetectDevices function.
Then, the one-based device number can be the handle (again, one-based) that you use as the instance number in the MCI_OPEN call. That would allow to select between different devices.

Jochen Schäfer

  • Sr. Member
  • ****
  • Posts: 303
  • Karma: +27/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #28 on: June 30, 2023, 05:48:35 pm »
Also, what you would need to do is build a list of devices in the SDL_DetectDevices function.
Then, the one-based device number can be the handle (again, one-based) that you use as the instance number in the MCI_OPEN call. That would allow to select between different devices.
Would that one-based index also go into usDeviceID for the MCI_OPEN message or would that go elsewhere? The documentation only states usDeviceID is a return value for MCI_OPEN.

Lars

  • Hero Member
  • *****
  • Posts: 1221
  • Karma: +65/-0
    • View Profile
Re: Strange behaviour in SDL2
« Reply #29 on: June 30, 2023, 10:59:57 pm »
I will need to reread the docs. We'll continue on Slack.