Complete.Org: Mailing Lists: Archives: freeciv-dev: June 2002:
[Freeciv-Dev] Re: cygwin audio
Home

[Freeciv-Dev] Re: cygwin audio

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Subject: [Freeciv-Dev] Re: cygwin audio
From: swamp-dog@xxxxxxxxxxxx (Guy Harrison)
Date: Mon, 17 Jun 2002 10:47:48 GMT

On Sun, 9 Jun 2002 09:09:32 +0200 (MEST), Per I Mathisen
<per@xxxxxxxxxxx> wrote:

>On Sat, 8 Jun 2002, Guy Harrison wrote:
>> Anyone else here familiar with CygWin (GTK) FreeCiv compiled for X (ie
>> not MINGW)? I've added a bit of code to audio_winmm.c so that
>> ::sndPlaySound() can find the sound files (failing because it gets a
>> unix path), but it will require an option for 'configure' to allow the
>> user to force "-lwinmm". Perhaps this option already exists and I've
>> missed it. Scripts are not my strongpoint!
>
>Could you send this code as a patch to the list, please?

Sure, except it raised a larger problem hence no patch atm. I have
attached my audio_winmm.c which attempts to address both issues. The C++
comments within it serve only to supplement this post and will be
removed when I get round to figuring out how to format it correctly.

sndPlaySound() aborts the current sound in favour of the newest one
received. Result is that the end user hears only the last sound of a
given series, possibly with some seeming pops, crackles and partial
sounds as the preceeding sounds commence then are aborted. I'll come
back to this particular issue later. Needless to say, this doesn't just
affect the CygWin/XFree version, it affects the CygWin/WinAPI native
compilation also.

First, a general issue. How is the Freeciv "virtual soundcard" supposed
to behave? Obviously from the code it can initialise & terminate plus
play & stop sounds. What else - suppose it got handed a series of
lengthy sounds in a particular turn that wouldn't be completed by the
end of that turn?

Before you answer, back to the specific WinAPI problem. The MSDN docs
reveal a SND_NOSTOP flag. In the case where a sound is currently playing
then FALSE is immediately returned and the current sound is left
playing, otherwise the new sound is commenced and TRUE is returned.
So...

sndPlaySound(fullpath,flags);

...can be replaced with...

while (!sndPlaySound(fullpath,flags | SND_NOSTOP)
  Sleep(foo)
;

My concern is now clear. This trivial fix is going to block the main
thread for the duration "sounds-queued-this-turn -1".

There's yet one more problem. Ironically I used it as the solution! The
above does not work at all under NT. The SND_NOSTOP flag is completely
ignored and TRUE is always returned. Until now I could only suspect it
worked for Win9x only. Sorry for not replying earlier - I wanted to find
out. I've just had confirmation it does work under Win95 so it almost
certainly will work for Win98. XP is an unknown factor. Test code sent
was...

#include <windows.h>
#include <mmsystem.h>
#include <iostream>

using std::cout; using std::endl;

int
main(int,char *argv[])
{const TCHAR    a[]             ="./a.wav",
                                b[]             ="./b.wav";
 const UINT             f               (SND_ASYNC | SND_NODEFAULT);
 BOOL                   ra,
                                rb;
 unsigned               ran             (0),
                                rbn             (0);
 char p[20];

// std::strcpy(p,a);
 while (!(ra = ::sndPlaySound(a,f | SND_NOWAIT | SND_NOSTOP))) {
   ::Sleep(125);
   ran += 1;
   cout<<'A';cout.flush();
 }
// std::strcpy(p,b);
 while (!(rb = ::sndPlaySound(b,f | SND_NOWAIT | SND_NOSTOP))) {
   ::Sleep(125);
   rbn += 1;
   cout<<'B';cout.flush();
 }

 cout << "RA=" << ra << '(' << ran << ")\n"
          << "RB=" << rb << '(' << rbn << ')'
          << endl
 ;

 ::Sleep(3000);
 return 0;
}

Win95 played both files and correctly issued 'B' characters for the
duration of time that "a.wav" played. With NT you just hear "b.wav",
TRUE is returned and neither loop is entered. Above code compiled with
C++ Builder (to eliminate possibility of CygWin and/or gcc bug).


There's one possible fix for NT. An audio thread. It can be implemented
in one of two ways. Either have one dedicated thread or one transient
thread for each sound played. I've chosen the latter and while everybody
shudders I'll explain why not the former...

Theoretically, one thread makes sense. It can be initialised by
audio_plugin->init() and killed by audio_plugin->shutdown() but I
suspect communicating with it is going to require yet more windows code.
I don't believe CygWin has completely working pthread yet and unless I'm
mistaken I doubt the CygWin "-mno-cygwin" compilation could use it if it
had. I couldn't code it in any case - I'm a windoze programmer.
Secondly, it would have to be absolutely guaranteed that if civclient
died it could take out that thread with it. For those unfamiliar with
windows the reason is "last man standing"="main thread". We're only
talking about one *single* WinAPI call here and look how much trouble it
is causing.

The latter solution can be kept entirely within audio_winmm.c and has no
impact on the unix version whatsoever which can only be good.
Additionally I think we can use this NT solution across the board thus
dispense with both the runtime OS version checking and
"sounds-queued-this-turn -1" blocking that would otherwise be required
for a dual solution. Win9x doesn't thread too good but NT handles it
transparently even on my ancient 233P2 - and it does so with all the
blank "b_", "f_" and "w_" prefixed stdsounds.spec tags now assigned to
lengthy (some seconds long) wav files. Should civclient crash the audio
threads will automatically die as they complete.

audio_winmm.c attached.

Comments welcome, especially on the as yet unsolved issue of how to stop
all these pending sound threads when the need arises. TerminateThread()
is too much trouble. Consequently I'm considering another volatile
'lo_abort', and again there is no requirement for thread synch-ing so
still no CRITICAL_SECTION required.

static DWORD WINAPI
sndPlaySound_Thread(LPVOID fullpath)
{TCHAR  bp              [MAX_PATH];

 strcpy(bp,fullpath);
 lo_return = TRUE;

/*~~~*/
 if (lo_abort)
        return whatever
 ;
/*~~~*/

 return sndPlaySound(bp,SND_SYNC | SND_NODEFAULT)
        ? EXIT_SUCCESS
        : EXIT_FAILURE
  ;
}

...which stop() can set in conjunction with a single sndPlaySound(0,0).


-- 
swamp-dog@xxxxxxxxxxxx

Attachment: audio_winmm.c
Description: Binary data


[Prev in Thread] Current Thread [Next in Thread]