Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
2a91e3f9
Commit
2a91e3f9
authored
Aug 01, 2002
by
Robert Lunnon
Committed by
Alexandre Julliard
Aug 01, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Preliminary audio driver for Solaris Libaudioio.
parent
7cae201e
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
2612 additions
and
3 deletions
+2612
-3
configure
configure
+187
-2
configure.ac
configure.ac
+11
-1
Makefile.in
dlls/Makefile.in
+8
-0
.cvsignore
dlls/winmm/wineaudioio/.cvsignore
+3
-0
Makefile.in
dlls/winmm/wineaudioio/Makefile.in
+18
-0
audio.c
dlls/winmm/wineaudioio/audio.c
+2282
-0
audioio.c
dlls/winmm/wineaudioio/audioio.c
+95
-0
wineaudioio.drv.spec
dlls/winmm/wineaudioio/wineaudioio.drv.spec
+2
-0
config.h.in
include/config.h.in
+6
-0
No files found.
configure
View file @
2a91e3f9
...
...
@@ -9483,6 +9483,187 @@ done
AUDIOIOLIBS
=
""
for
ac_header
in
libaudioio.h
do
as_ac_Header
=
`
echo
"ac_cv_header_
$ac_header
"
|
$as_tr_sh
`
if
eval
"test
\"\$
{
$as_ac_Header
+set}
\"
= set"
;
then
echo
"
$as_me
:
$LINENO
: checking for
$ac_header
"
>
&5
echo
$ECHO_N
"checking for
$ac_header
...
$ECHO_C
"
>
&6
if
eval
"test
\"\$
{
$as_ac_Header
+set}
\"
= set"
;
then
echo
$ECHO_N
"(cached)
$ECHO_C
"
>
&6
fi
echo
"
$as_me
:
$LINENO
: result:
`
eval echo
'${'
$as_ac_Header
'}'
`
"
>
&5
echo
"
${
ECHO_T
}
`
eval echo
'${'
$as_ac_Header
'}'
`
"
>
&6
else
# Is the header compilable?
echo
"
$as_me
:
$LINENO
: checking
$ac_header
usability"
>
&5
echo
$ECHO_N
"checking
$ac_header
usability...
$ECHO_C
"
>
&6
cat
>
conftest.
$ac_ext
<<
_ACEOF
#line
$LINENO
"configure"
#include "confdefs.h"
$ac_includes_default
#include <
$ac_header
>
_ACEOF
rm
-f
conftest.
$ac_objext
if
{
(
eval echo
"
$as_me
:
$LINENO
:
\"
$ac_compile
\"
"
)
>
&5
(
eval
$ac_compile
)
2>&5
ac_status
=
$?
echo
"
$as_me
:
$LINENO
:
\$
? =
$ac_status
"
>
&5
(
exit
$ac_status
)
;
}
&&
{
ac_try
=
'test -s conftest.$ac_objext'
{
(
eval echo
"
$as_me
:
$LINENO
:
\"
$ac_try
\"
"
)
>
&5
(
eval
$ac_try
)
2>&5
ac_status
=
$?
echo
"
$as_me
:
$LINENO
:
\$
? =
$ac_status
"
>
&5
(
exit
$ac_status
)
;
}
;
}
;
then
ac_header_compiler
=
yes
else
echo
"
$as_me
: failed program was:"
>
&5
cat
conftest.
$ac_ext
>
&5
ac_header_compiler
=
no
fi
rm
-f
conftest.
$ac_objext
conftest.
$ac_ext
echo
"
$as_me
:
$LINENO
: result:
$ac_header_compiler
"
>
&5
echo
"
${
ECHO_T
}
$ac_header_compiler
"
>
&6
# Is the header present?
echo
"
$as_me
:
$LINENO
: checking
$ac_header
presence"
>
&5
echo
$ECHO_N
"checking
$ac_header
presence...
$ECHO_C
"
>
&6
cat
>
conftest.
$ac_ext
<<
_ACEOF
#line
$LINENO
"configure"
#include "confdefs.h"
#include <
$ac_header
>
_ACEOF
if
{
(
eval echo
"
$as_me
:
$LINENO
:
\"
$ac_cpp
conftest.
$ac_ext
\"
"
)
>
&5
(
eval
$ac_cpp
conftest.
$ac_ext
)
2>conftest.er1
ac_status
=
$?
egrep
-v
'^ *\+'
conftest.er1
>
conftest.err
rm
-f
conftest.er1
cat
conftest.err
>
&5
echo
"
$as_me
:
$LINENO
:
\$
? =
$ac_status
"
>
&5
(
exit
$ac_status
)
;
}
>
/dev/null
;
then
if
test
-s
conftest.err
;
then
ac_cpp_err
=
$ac_c_preproc_warn_flag
else
ac_cpp_err
=
fi
else
ac_cpp_err
=
yes
fi
if
test
-z
"
$ac_cpp_err
"
;
then
ac_header_preproc
=
yes
else
echo
"
$as_me
: failed program was:"
>
&5
cat
conftest.
$ac_ext
>
&5
ac_header_preproc
=
no
fi
rm
-f
conftest.err conftest.
$ac_ext
echo
"
$as_me
:
$LINENO
: result:
$ac_header_preproc
"
>
&5
echo
"
${
ECHO_T
}
$ac_header_preproc
"
>
&6
# So? What about this header?
case
$ac_header_compiler
:
$ac_header_preproc
in
yes
:no
)
{
echo
"
$as_me
:
$LINENO
: WARNING:
$ac_header
: accepted by the compiler, rejected by the preprocessor!"
>
&5
echo
"
$as_me
: WARNING:
$ac_header
: accepted by the compiler, rejected by the preprocessor!"
>
&2
;
}
{
echo
"
$as_me
:
$LINENO
: WARNING:
$ac_header
: proceeding with the preprocessor's result"
>
&5
echo
"
$as_me
: WARNING:
$ac_header
: proceeding with the preprocessor's result"
>
&2
;
}
;;
no:yes
)
{
echo
"
$as_me
:
$LINENO
: WARNING:
$ac_header
: present but cannot be compiled"
>
&5
echo
"
$as_me
: WARNING:
$ac_header
: present but cannot be compiled"
>
&2
;
}
{
echo
"
$as_me
:
$LINENO
: WARNING:
$ac_header
: check for missing prerequisite headers?"
>
&5
echo
"
$as_me
: WARNING:
$ac_header
: check for missing prerequisite headers?"
>
&2
;
}
{
echo
"
$as_me
:
$LINENO
: WARNING:
$ac_header
: proceeding with the preprocessor's result"
>
&5
echo
"
$as_me
: WARNING:
$ac_header
: proceeding with the preprocessor's result"
>
&2
;
}
;;
esac
echo
"
$as_me
:
$LINENO
: checking for
$ac_header
"
>
&5
echo
$ECHO_N
"checking for
$ac_header
...
$ECHO_C
"
>
&6
if
eval
"test
\"\$
{
$as_ac_Header
+set}
\"
= set"
;
then
echo
$ECHO_N
"(cached)
$ECHO_C
"
>
&6
else
eval
"
$as_ac_Header
=
$ac_header_preproc
"
fi
echo
"
$as_me
:
$LINENO
: result:
`
eval echo
'${'
$as_ac_Header
'}'
`
"
>
&5
echo
"
${
ECHO_T
}
`
eval echo
'${'
$as_ac_Header
'}'
`
"
>
&6
fi
if
test
`
eval echo
'${'
$as_ac_Header
'}'
`
=
yes
;
then
cat
>>
confdefs.h
<<
_ACEOF
#define `echo "HAVE_
$ac_header
" |
$as_tr_cpp
` 1
_ACEOF
echo
"
$as_me
:
$LINENO
: checking for AudioIOGetVersion in -laudioio"
>
&5
echo
$ECHO_N
"checking for AudioIOGetVersion in -laudioio...
$ECHO_C
"
>
&6
if
test
"
${
ac_cv_lib_audioio_AudioIOGetVersion
+set
}
"
=
set
;
then
echo
$ECHO_N
"(cached)
$ECHO_C
"
>
&6
else
ac_check_lib_save_LIBS
=
$LIBS
LIBS
=
"-laudioio
$LIBS
"
cat
>
conftest.
$ac_ext
<<
_ACEOF
#line
$LINENO
"configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char AudioIOGetVersion ();
#ifdef F77_DUMMY_MAIN
# ifdef __cplusplus
extern "C"
# endif
int F77_DUMMY_MAIN() { return 1; }
#endif
int
main ()
{
AudioIOGetVersion ();
;
return 0;
}
_ACEOF
rm
-f
conftest.
$ac_objext
conftest
$ac_exeext
if
{
(
eval echo
"
$as_me
:
$LINENO
:
\"
$ac_link
\"
"
)
>
&5
(
eval
$ac_link
)
2>&5
ac_status
=
$?
echo
"
$as_me
:
$LINENO
:
\$
? =
$ac_status
"
>
&5
(
exit
$ac_status
)
;
}
&&
{
ac_try
=
'test -s conftest$ac_exeext'
{
(
eval echo
"
$as_me
:
$LINENO
:
\"
$ac_try
\"
"
)
>
&5
(
eval
$ac_try
)
2>&5
ac_status
=
$?
echo
"
$as_me
:
$LINENO
:
\$
? =
$ac_status
"
>
&5
(
exit
$ac_status
)
;
}
;
}
;
then
ac_cv_lib_audioio_AudioIOGetVersion
=
yes
else
echo
"
$as_me
: failed program was:"
>
&5
cat
conftest.
$ac_ext
>
&5
ac_cv_lib_audioio_AudioIOGetVersion
=
no
fi
rm
-f
conftest.
$ac_objext
conftest
$ac_exeext
conftest.
$ac_ext
LIBS
=
$ac_check_lib_save_LIBS
fi
echo
"
$as_me
:
$LINENO
: result:
$ac_cv_lib_audioio_AudioIOGetVersion
"
>
&5
echo
"
${
ECHO_T
}
$ac_cv_lib_audioio_AudioIOGetVersion
"
>
&6
if
test
$ac_cv_lib_audioio_AudioIOGetVersion
=
yes
;
then
AUDIOIOLIBS
=
"-laudioio"
cat
>>
confdefs.h
<<
\
_ACEOF
#define HAVE_LIBAUDIOIO 1
_ACEOF
fi
fi
done
echo
"
$as_me
:
$LINENO
: checking whether mmap64 works defined as mmap"
>
&5
echo
$ECHO_N
"checking whether mmap64 works defined as mmap...
$ECHO_C
"
>
&6
if
test
"
${
ac_cv_mmap64_works
+set
}
"
=
set
;
then
...
...
@@ -11617,6 +11798,7 @@ done
for
ac_header
in
\
arpa/inet.h
\
arpa/nameser.h
\
...
...
@@ -11625,6 +11807,7 @@ for ac_header in \
float.h
\
ieeefp.h
\
io.h
\
libaudioio.h
\
libio.h
\
libutil.h
\
link.h
\
...
...
@@ -13810,7 +13993,7 @@ MAKE_DLL_RULES=dlls/Makedll.rules
MAKE_PROG_RULES
=
programs/Makeprog.rules
ac_config_files
=
"
$ac_config_files
Make.rules dlls/Makedll.rules programs/Makeprog.rules Makefile debugger/Makefile dlls/Makefile dlls/advapi32/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/netapi32/Makefile dlls/ntdll/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/wine
nas/Makefile dlls/winmm/wineart
s/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile tsx11/Makefile unicode/Makefile"
ac_config_files
=
"
$ac_config_files
Make.rules dlls/Makedll.rules programs/Makeprog.rules Makefile debugger/Makefile dlls/Makefile dlls/advapi32/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/netapi32/Makefile dlls/ntdll/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/wine
arts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winena
s/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile tsx11/Makefile unicode/Makefile"
cat
>
confcache
<<
\
_ACEOF
...
...
@@ -14378,8 +14561,9 @@ do
"dlls/winmm/midimap/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/midimap/Makefile" ;;
"dlls/winmm/wavemap/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/wavemap/Makefile" ;;
"dlls/winmm/winealsa/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/winealsa/Makefile" ;;
"dlls/winmm/winenas/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/winenas/Makefile" ;;
"dlls/winmm/winearts/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/winearts/Makefile" ;;
"dlls/winmm/wineaudioio/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/wineaudioio/Makefile" ;;
"dlls/winmm/winenas/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/winenas/Makefile" ;;
"dlls/winmm/wineoss/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winmm/wineoss/Makefile" ;;
"dlls/winnls/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winnls/Makefile" ;;
"dlls/winsock/Makefile" ) CONFIG_FILES="
$CONFIG_FILES
dlls/winsock/Makefile" ;;
...
...
@@ -14618,6 +14802,7 @@ s,@ARTSLIBS@,$ARTSLIBS,;t t
s,@ARTSINCL@,
$ARTSINCL
,;t t
s,@ALSALIBS@,
$ALSALIBS
,;t t
s,@NASLIBS@,
$NASLIBS
,;t t
s,@AUDIOIOLIBS@,
$AUDIOIOLIBS
,;t t
s,@DLLWRAP@,
$DLLWRAP
,;t t
s,@ac_ct_DLLWRAP@,
$ac_ct_DLLWRAP
,;t t
s,@DLLIBS@,
$DLLIBS
,;t t
...
...
configure.ac
View file @
2a91e3f9
...
...
@@ -577,6 +577,14 @@ AC_CHECK_HEADERS(audio/audiolib.h,
NASLIBS="-laudio -lXt \$(X_LIBS) \$(XLIB)"],,
[-lXt $X_LIBS -lXext -lX11 $X_EXTRA_LIBS])])
dnl **** Check for libaudioio (which can be used to get solaris audio support) ****
AC_SUBST(AUDIOIOLIBS,"")
AC_CHECK_HEADERS(libaudioio.h,
[AC_CHECK_LIB(audioio,AudioIOGetVersion,
[AUDIOIOLIBS="-laudioio"
AC_DEFINE(HAVE_LIBAUDIOIO, 1, [Define if you have libaudioIO])])])
dnl **** Check for broken glibc mmap64 ****
AC_CACHE_CHECK( [whether mmap64 works defined as mmap], ac_cv_mmap64_works,
...
...
@@ -922,6 +930,7 @@ AC_CHECK_HEADERS(\
float.h \
ieeefp.h \
io.h \
libaudioio.h \
libio.h \
libutil.h \
link.h \
...
...
@@ -1412,8 +1421,9 @@ dlls/winmm/mciwave/Makefile
dlls/winmm/midimap/Makefile
dlls/winmm/wavemap/Makefile
dlls/winmm/winealsa/Makefile
dlls/winmm/winenas/Makefile
dlls/winmm/winearts/Makefile
dlls/winmm/wineaudioio/Makefile
dlls/winmm/winenas/Makefile
dlls/winmm/wineoss/Makefile
dlls/winnls/Makefile
dlls/winsock/Makefile
...
...
dlls/Makefile.in
View file @
2a91e3f9
...
...
@@ -98,6 +98,7 @@ BASEDIRS = \
winmm/wavemap
\
winmm/winealsa
\
winmm/winearts
\
winmm/wineaudioio
\
winmm/winenas
\
winmm/wineoss
\
winnls
\
...
...
@@ -241,6 +242,7 @@ all: \
windebug.dll$(DLLEXT)
\
winealsa.drv$(DLLEXT)
\
winearts.drv$(DLLEXT)
\
wineaudioio.drv$(DLLEXT)
\
winedos.dll$(DLLEXT)
\
winemp3.acm$(DLLEXT)
\
winenas.drv$(DLLEXT)
\
...
...
@@ -509,6 +511,9 @@ winealsa.drv$(DLLEXT): winmm/winealsa/winealsa.drv$(DLLEXT)
winearts.drv$(DLLEXT)
:
winmm/winearts/winearts.drv$(DLLEXT)
$(RM)
$@
&&
$(LN_S)
winmm/winearts/winearts.drv
$(DLLEXT)
$@
wineaudioio.drv$(DLLEXT)
:
winmm/wineaudioio/wineaudioio.drv$(DLLEXT)
$(RM)
$@
&&
$(LN_S)
winmm/wineaudioio/wineaudioio.drv
$(DLLEXT)
$@
winedos.dll$(DLLEXT)
:
winedos/winedos.dll$(DLLEXT)
$(RM)
$@
&&
$(LN_S)
winedos/winedos.dll
$(DLLEXT)
$@
...
...
@@ -636,6 +641,7 @@ version/version.dll$(DLLEXT): version
win32s/w32skrnl.dll$(DLLEXT)
:
win32s
winmm/winealsa/winealsa.drv$(DLLEXT)
:
winmm/winealsa
winmm/winearts/winearts.drv$(DLLEXT)
:
winmm/winearts
winmm/wineaudioio/wineaudioio.drv$(DLLEXT)
:
winmm/wineaudioio
winedos/winedos.dll$(DLLEXT)
:
winedos
msacm/winemp3/winemp3.acm$(DLLEXT)
:
msacm/winemp3
winmm/winenas/winenas.drv$(DLLEXT)
:
winmm/winenas
...
...
@@ -734,6 +740,7 @@ version/__install__: version.dll$(DLLEXT)
win32s/__install__
:
w32skrnl.dll$(DLLEXT)
winmm/winealsa/__install__
:
winealsa.drv$(DLLEXT)
winmm/winearts/__install__
:
winearts.drv$(DLLEXT)
winmm/wineaudioio/__install__
:
wineaudioio.drv$(DLLEXT)
winedos/__install__
:
winedos.dll$(DLLEXT)
msacm/winemp3/__install__
:
winemp3.acm$(DLLEXT)
winmm/winenas/__install__
:
winenas.drv$(DLLEXT)
...
...
@@ -849,6 +856,7 @@ winmm/midimap: winmm.dll$(DLLEXT) user32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kern
winmm/wavemap
:
msacm32.dll$(DLLEXT) winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
winmm/winealsa
:
winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT)
winmm/winearts
:
winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
winmm/wineaudioio
:
winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT)
winmm/winenas
:
winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
winmm/wineoss
:
winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
winmm
:
user32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
...
...
dlls/winmm/wineaudioio/.cvsignore
0 → 100644
View file @
2a91e3f9
Makefile
wineaudioio.drv.dbg.c
wineaudioio.drv.spec.c
dlls/winmm/wineaudioio/Makefile.in
0 → 100644
View file @
2a91e3f9
TOPSRCDIR
=
@top_srcdir@
TOPOBJDIR
=
../../..
SRCDIR
=
@srcdir@
VPATH
=
@srcdir@
MODULE
=
wineaudioio.drv
IMPORTS
=
winmm user32 kernel32 ntdll
EXTRALIBS
=
@AUDIOIOLIBS@
LDDLLFLAGS
=
@LDDLLFLAGS@
SYMBOLFILE
=
$(MODULE)
.tmp.o
C_SRCS
=
\
audio.c
\
audioio.c
@MAKE_DLL_RULES@
### Dependencies:
dlls/winmm/wineaudioio/audio.c
0 → 100644
View file @
2a91e3f9
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* Wine Driver for Libaudioio
* Derived from the Wine OSS Sample Driver
* Copyright 1994 Martin Ayotte
* 1999 Eric Pouech (async playing in waveOut/waveIn)
* 2000 Eric Pouech (loops in waveOut)
* 2002 Robert Lunnon (Modifications for libaudioio)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Note large hacks done to effectively disable DSound altogether
* Also Input is not yet working (Lots more work to be done there)
* But this does make a reasonable output driver for solaris untill the arts driver comes up to speed
*/
/*
* FIXME:
* pause in waveOut does not work correctly
* full duplex (in/out) is not working (device is opened twice for Out
* and In) (OSS is known for its poor duplex capabilities, alsa is
* better)
*/
/*#define EMULATE_SB16*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifdef HAVE_LIBAUDIOIO_H
#include <libaudioio.h>
#endif
#include "windef.h"
#include "wingdi.h"
#include "winerror.h"
#include "wine/winuser16.h"
#include "mmddk.h"
#include "dsound.h"
#include "dsdriver.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
wave
);
#ifdef HAVE_LIBAUDIOIO
/* Allow 1% deviation for sample rates (some ES137x cards) */
#define NEAR_MATCH(rate1,rate2) (((100*((int)(rate1)-(int)(rate2)))/(rate1))==0)
#define SOUND_DEV "/dev/audio"
#define DEFAULT_FRAGMENT_SIZE 4096
#define MAX_WAVEOUTDRV (1)
#define MAX_WAVEINDRV (1)
/* state diagram for waveOut writing:
*
* +---------+-------------+---------------+---------------------------------+
* | state | function | event | new state |
* +---------+-------------+---------------+---------------------------------+
* | | open() | | STOPPED |
* | PAUSED | write() | | PAUSED |
* | STOPPED | write() | <thrd create> | PLAYING |
* | PLAYING | write() | HEADER | PLAYING |
* | (other) | write() | <error> | |
* | (any) | pause() | PAUSING | PAUSED |
* | PAUSED | restart() | RESTARTING | PLAYING (if no thrd => STOPPED) |
* | (any) | reset() | RESETTING | STOPPED |
* | (any) | close() | CLOSING | CLOSED |
* +---------+-------------+---------------+---------------------------------+
*/
/* states of the playing device */
#define WINE_WS_PLAYING 0
#define WINE_WS_PAUSED 1
#define WINE_WS_STOPPED 2
#define WINE_WS_CLOSED 3
/* events to be send to device */
#define WINE_WM_PAUSING (WM_USER + 1)
#define WINE_WM_RESTARTING (WM_USER + 2)
#define WINE_WM_RESETTING (WM_USER + 3)
#define WINE_WM_CLOSING (WM_USER + 4)
#define WINE_WM_HEADER (WM_USER + 5)
#define WINE_WM_FIRST WINE_WM_PAUSING
#define WINE_WM_LAST WINE_WM_HEADER
typedef
struct
{
int
msg
;
DWORD
param
;
}
WWO_MSG
;
typedef
struct
{
int
unixdev
;
volatile
int
state
;
/* one of the WINE_WS_ manifest constants */
DWORD
dwFragmentSize
;
/* size of OSS buffer fragment */
WAVEOPENDESC
waveDesc
;
WORD
wFlags
;
PCMWAVEFORMAT
format
;
LPWAVEHDR
lpQueuePtr
;
/* start of queued WAVEHDRs (waiting to be notified) */
LPWAVEHDR
lpPlayPtr
;
/* start of not yet fully played buffers */
LPWAVEHDR
lpLoopPtr
;
/* pointer of first buffer in loop, if any */
DWORD
dwLoops
;
/* private copy of loop counter */
DWORD
dwLastFragDone
;
/* time in ms, when last played fragment will be actually played */
DWORD
dwPlayedTotal
;
/* number of bytes played since opening */
/* info on current lpQueueHdr->lpWaveHdr */
DWORD
dwOffCurrHdr
;
/* offset in lpPlayPtr->lpData for fragments */
DWORD
dwRemain
;
/* number of bytes to write to end the current fragment */
/* synchronization stuff */
HANDLE
hThread
;
DWORD
dwThreadID
;
HANDLE
hEvent
;
#define WWO_RING_BUFFER_SIZE 30
WWO_MSG
messages
[
WWO_RING_BUFFER_SIZE
];
int
msg_tosave
;
int
msg_toget
;
HANDLE
msg_event
;
CRITICAL_SECTION
msg_crst
;
WAVEOUTCAPSA
caps
;
/* DirectSound stuff */
LPBYTE
mapping
;
DWORD
maplen
;
}
WINE_WAVEOUT
;
typedef
struct
{
int
unixdev
;
volatile
int
state
;
DWORD
dwFragmentSize
;
/* OpenSound '/dev/dsp' give us that size */
WAVEOPENDESC
waveDesc
;
WORD
wFlags
;
PCMWAVEFORMAT
format
;
LPWAVEHDR
lpQueuePtr
;
DWORD
dwTotalRecorded
;
WAVEINCAPSA
caps
;
BOOL
bTriggerSupport
;
/* synchronization stuff */
HANDLE
hThread
;
DWORD
dwThreadID
;
HANDLE
hEvent
;
}
WINE_WAVEIN
;
static
WINE_WAVEOUT
WOutDev
[
MAX_WAVEOUTDRV
];
static
WINE_WAVEIN
WInDev
[
MAX_WAVEINDRV
];
static
DWORD
wodDsCreate
(
UINT
wDevID
,
PIDSDRIVER
*
drv
);
/*======================================================================*
* Low level WAVE implementation *
*======================================================================*/
SampleSpec_t
spec
[
2
];
LONG
LIBAUDIOIO_WaveInit
(
void
)
{
int
audio
;
int
smplrate
;
int
samplesize
=
16
;
int
dsp_stereo
=
1
;
int
bytespersmpl
;
int
caps
;
int
mask
;
int
i
;
int
audio_fd
;
int
mode
;
TRACE
(
"Init ENTERED rate = %d
\n
"
,
spec
[
PLAYBACK
].
rate
);
spec
[
RECORD
].
channels
=
spec
[
PLAYBACK
].
channels
=
2
;
spec
[
RECORD
].
max_blocks
=
spec
[
PLAYBACK
].
max_blocks
=
16
;
spec
[
RECORD
].
rate
=
spec
[
PLAYBACK
].
rate
=
44100
;
spec
[
RECORD
].
encoding
=
spec
[
PLAYBACK
].
encoding
=
ENCODE_PCM
;
spec
[
RECORD
].
precision
=
spec
[
PLAYBACK
].
precision
=
16
;
spec
[
RECORD
].
endian
=
spec
[
PLAYBACK
].
endian
=
ENDIAN_INTEL
;
spec
[
RECORD
].
disable_threads
=
spec
[
PLAYBACK
].
disable_threads
=
1
;
spec
[
RECORD
].
type
=
spec
[
PLAYBACK
].
type
=
TYPE_SIGNED
;
// in 16 bit mode this is what typical PC hardware expects
mode
=
O_WRONLY
|
O_NDELAY
;
/* start with output device */
/* initialize all device handles to -1 */
for
(
i
=
0
;
i
<
MAX_WAVEOUTDRV
;
++
i
)
{
WOutDev
[
i
].
unixdev
=
-
1
;
}
/* FIXME: only one device is supported */
memset
(
&
WOutDev
[
0
].
caps
,
0
,
sizeof
(
WOutDev
[
0
].
caps
));
/* FIXME: some programs compare this string against the content of the registry
* for MM drivers. The names have to match in order for the program to work
* (e.g. MS win9x mplayer.exe)
*/
#ifdef EMULATE_SB16
WOutDev
[
0
].
caps
.
wMid
=
0x0002
;
WOutDev
[
0
].
caps
.
wPid
=
0x0104
;
strcpy
(
WOutDev
[
0
].
caps
.
szPname
,
"SB16 Wave Out"
);
#else
WOutDev
[
0
].
caps
.
wMid
=
0x00FF
;
/* Manufac ID */
WOutDev
[
0
].
caps
.
wPid
=
0x0001
;
/* Product ID */
/* strcpy(WOutDev[0].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/
strcpy
(
WOutDev
[
0
].
caps
.
szPname
,
"CS4236/37/38"
);
#endif
WOutDev
[
0
].
caps
.
vDriverVersion
=
0x0100
;
WOutDev
[
0
].
caps
.
dwFormats
=
0x00000000
;
WOutDev
[
0
].
caps
.
dwSupport
=
WAVECAPS_VOLUME
;
/*
* Libaudioio works differently, you tell it what spec audio you want to write and it
* Guarantees to match it by converting to the final format on the fly
*So we dont need to read back and compare
*/
bytespersmpl
=
spec
[
PLAYBACK
].
precision
/
8
;
WOutDev
[
0
].
caps
.
wChannels
=
spec
[
PLAYBACK
].
channels
;
/* Fixme: Libaudioio 0.2 doesn't support balance yet (Libaudioio 0.3 does so this must be fixed later)*/
/* if (WOutDev[0].caps.wChannels > 1) WOutDev[0].caps.dwSupport |= WAVECAPS_LRVOLUME;*/
TRACE
(
"Init sammplerate= %d
\n
"
,
spec
[
PLAYBACK
].
rate
);
smplrate
=
spec
[
PLAYBACK
].
rate
;
/*
* We have set up the data format to be 16 bit signed in intel format
* For Big Endian machines libaudioio will convert the data to bigendian for us
*/
WOutDev
[
0
].
caps
.
dwFormats
|=
WAVE_FORMAT_4M16
;
if
(
WOutDev
[
0
].
caps
.
wChannels
>
1
)
WOutDev
[
0
].
caps
.
dwFormats
|=
WAVE_FORMAT_4S16
;
/* Don't understand this yet, but I dont think this functionality is portable, leave here for future evaluation
* if (IOCTL(audio, SNDCTL_DSP_GETCAPS, caps) == 0) {
* TRACE("OSS dsp out caps=%08X\n", caps);
* if ((caps & DSP_CAP_REALTIME) && !(caps & DSP_CAP_BATCH)) {
* WOutDev[0].caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
* }
*/
/* well, might as well use the DirectSound cap flag for something */
/* if ((caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
* !(caps & DSP_CAP_BATCH))
* WOutDev[0].caps.dwSupport |= WAVECAPS_DIRECTSOUND;
* }
*/
/*
* Note that libaudioio audio capture is not proven yet, in our open call
* set the spec for input audio the same as for output
*/
TRACE
(
"out dwFormats = %08lX, dwSupport = %08lX
\n
"
,
WOutDev
[
0
].
caps
.
dwFormats
,
WOutDev
[
0
].
caps
.
dwSupport
);
for
(
i
=
0
;
i
<
MAX_WAVEINDRV
;
++
i
)
{
WInDev
[
i
].
unixdev
=
-
1
;
}
memset
(
&
WInDev
[
0
].
caps
,
0
,
sizeof
(
WInDev
[
0
].
caps
));
#ifdef EMULATE_SB16
WInDev
[
0
].
caps
.
wMid
=
0x0002
;
WInDev
[
0
].
caps
.
wPid
=
0x0004
;
strcpy
(
WInDev
[
0
].
caps
.
szPname
,
"SB16 Wave In"
);
#else
WInDev
[
0
].
caps
.
wMid
=
0x00FF
;
/* Manufac ID */
WInDev
[
0
].
caps
.
wPid
=
0x0001
;
/* Product ID */
strcpy
(
WInDev
[
0
].
caps
.
szPname
,
"OpenSoundSystem WAVIN Driver"
);
#endif
WInDev
[
0
].
caps
.
dwFormats
=
0x00000000
;
WInDev
[
0
].
caps
.
wChannels
=
spec
[
RECORD
].
channels
;
WInDev
[
0
].
bTriggerSupport
=
TRUE
;
/* Maybe :-) */
bytespersmpl
=
spec
[
RECORD
].
precision
/
8
;
smplrate
=
spec
[
RECORD
].
rate
;
WInDev
[
0
].
caps
.
dwFormats
|=
WAVE_FORMAT_4M16
;
if
(
WInDev
[
0
].
caps
.
wChannels
>
1
)
WInDev
[
0
].
caps
.
dwFormats
|=
WAVE_FORMAT_4S16
;
TRACE
(
"in dwFormats = %08lX
\n
"
,
WInDev
[
0
].
caps
.
dwFormats
);
return
0
;
}
/**************************************************************************
* LIBAUDIOIO_NotifyClient [internal]
*/
static
DWORD
LIBAUDIOIO_NotifyClient
(
UINT
wDevID
,
WORD
wMsg
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"wDevID = %04X wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX
\n
"
,
wDevID
,
wMsg
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
WOM_OPEN
:
case
WOM_CLOSE
:
case
WOM_DONE
:
if
(
wDevID
>=
MAX_WAVEOUTDRV
)
return
MCIERR_INTERNAL
;
if
(
WOutDev
[
wDevID
].
wFlags
!=
DCB_NULL
&&
!
DriverCallback
(
WOutDev
[
wDevID
].
waveDesc
.
dwCallback
,
WOutDev
[
wDevID
].
wFlags
,
WOutDev
[
wDevID
].
waveDesc
.
hWave
,
wMsg
,
WOutDev
[
wDevID
].
waveDesc
.
dwInstance
,
dwParam1
,
dwParam2
))
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_NOERROR
;
}
break
;
case
WIM_OPEN
:
case
WIM_CLOSE
:
case
WIM_DATA
:
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MCIERR_INTERNAL
;
if
(
WInDev
[
wDevID
].
wFlags
!=
DCB_NULL
&&
!
DriverCallback
(
WInDev
[
wDevID
].
waveDesc
.
dwCallback
,
WInDev
[
wDevID
].
wFlags
,
WInDev
[
wDevID
].
waveDesc
.
hWave
,
wMsg
,
WInDev
[
wDevID
].
waveDesc
.
dwInstance
,
dwParam1
,
dwParam2
))
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_NOERROR
;
}
break
;
default:
FIXME
(
"Unknown CB message %u
\n
"
,
wMsg
);
break
;
}
return
0
;
}
/*======================================================================*
* Low level WAVE OUT implementation *
*======================================================================*/
/**************************************************************************
* wodPlayer_WriteFragments [internal]
*
* wodPlayer helper. Writes as many fragments as it can to unixdev.
* Returns TRUE in case of buffer underrun.
*/
static
BOOL
wodPlayer_WriteFragments
(
WINE_WAVEOUT
*
wwo
)
{
LPWAVEHDR
lpWaveHdr
;
LPBYTE
lpData
;
int
count
;
TRACE
(
"wodPlayer_WriteFragments sammplerate= %d
\n
"
,
spec
[
PLAYBACK
].
rate
);
for
(;;)
{
/*
* Libaudioio doesn't buffer the same way as linux, you can write data is any block size
*And libaudioio just tracks the number of blocks in the streams queue to control latency
*/
if
(
!
AudioIOCheckWriteReady
())
return
FALSE
;
/* Returns false if you have execeeded your specified latency (No space left)*/
lpWaveHdr
=
wwo
->
lpPlayPtr
;
if
(
!
lpWaveHdr
)
{
if
(
wwo
->
dwRemain
>
0
&&
/* still data to send to complete current fragment */
wwo
->
dwLastFragDone
&&
/* first fragment has been played */
AudioIOCheckUnderrun
())
{
/* done with all waveOutWrite()' fragments */
/* FIXME: should do better handling here */
WARN
(
"Oooch, buffer underrun !
\n
"
);
return
TRUE
;
/* force resetting of waveOut device */
}
return
FALSE
;
/* wait a bit */
}
if
(
wwo
->
dwOffCurrHdr
==
0
)
{
TRACE
(
"Starting a new wavehdr %p of %ld bytes
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
dwBufferLength
);
if
(
lpWaveHdr
->
dwFlags
&
WHDR_BEGINLOOP
)
{
if
(
wwo
->
lpLoopPtr
)
{
WARN
(
"Already in a loop. Discarding loop on this header (%p)
\n
"
,
lpWaveHdr
);
}
else
{
TRACE
(
"Starting loop (%ldx) with %p
\n
"
,
lpWaveHdr
->
dwLoops
,
lpWaveHdr
);
wwo
->
lpLoopPtr
=
lpWaveHdr
;
/* Windows does not touch WAVEHDR.dwLoops,
* so we need to make an internal copy */
wwo
->
dwLoops
=
lpWaveHdr
->
dwLoops
;
}
}
}
lpData
=
lpWaveHdr
->
lpData
;
/* finish current wave hdr ? */
if
(
wwo
->
dwOffCurrHdr
+
wwo
->
dwRemain
>=
lpWaveHdr
->
dwBufferLength
)
{
DWORD
toWrite
=
lpWaveHdr
->
dwBufferLength
-
wwo
->
dwOffCurrHdr
;
/* write end of current wave hdr */
count
=
AudioIOWrite
(
lpData
+
wwo
->
dwOffCurrHdr
,
toWrite
);
TRACE
(
"write(%p[%5lu], %5lu) => %d
\n
"
,
lpData
,
wwo
->
dwOffCurrHdr
,
toWrite
,
count
);
if
(
count
>
0
||
toWrite
==
0
)
{
DWORD
tc
=
GetTickCount
();
if
(
wwo
->
dwLastFragDone
/* + guard time ?? */
<
tc
)
wwo
->
dwLastFragDone
=
tc
;
wwo
->
dwLastFragDone
+=
(
toWrite
*
1000
)
/
wwo
->
format
.
wf
.
nAvgBytesPerSec
;
lpWaveHdr
->
reserved
=
wwo
->
dwLastFragDone
;
TRACE
(
"Tagging hdr %p with %08lx
\n
"
,
lpWaveHdr
,
wwo
->
dwLastFragDone
);
/* WAVEHDR written, go to next one */
if
((
lpWaveHdr
->
dwFlags
&
WHDR_ENDLOOP
)
&&
wwo
->
lpLoopPtr
)
{
if
(
--
wwo
->
dwLoops
>
0
)
{
wwo
->
lpPlayPtr
=
wwo
->
lpLoopPtr
;
}
else
{
/* last one played */
if
(
wwo
->
lpLoopPtr
!=
lpWaveHdr
&&
(
lpWaveHdr
->
dwFlags
&
WHDR_BEGINLOOP
))
{
FIXME
(
"Correctly handled case ? (ending loop buffer also starts a new loop)
\n
"
);
/* shall we consider the END flag for the closing loop or for
* the opening one or for both ???
* code assumes for closing loop only
*/
wwo
->
lpLoopPtr
=
lpWaveHdr
;
}
else
{
wwo
->
lpLoopPtr
=
NULL
;
}
wwo
->
lpPlayPtr
=
lpWaveHdr
->
lpNext
;
}
}
else
{
wwo
->
lpPlayPtr
=
lpWaveHdr
->
lpNext
;
}
wwo
->
dwOffCurrHdr
=
0
;
if
((
wwo
->
dwRemain
-=
count
)
==
0
)
{
wwo
->
dwRemain
=
wwo
->
dwFragmentSize
;
}
}
continue
;
/* try to go to use next wavehdr */
}
else
{
count
=
AudioIOWrite
(
lpData
+
wwo
->
dwOffCurrHdr
,
wwo
->
dwRemain
);
TRACE
(
"write(%p[%5lu], %5lu) => %d
\n
"
,
lpData
,
wwo
->
dwOffCurrHdr
,
wwo
->
dwRemain
,
count
);
if
(
count
>
0
)
{
DWORD
tc
=
GetTickCount
();
if
(
wwo
->
dwLastFragDone
/* + guard time ?? */
<
tc
)
wwo
->
dwLastFragDone
=
tc
;
wwo
->
dwLastFragDone
+=
(
wwo
->
dwRemain
*
1000
)
/
wwo
->
format
.
wf
.
nAvgBytesPerSec
;
TRACE
(
"Tagging frag with %08lx
\n
"
,
wwo
->
dwLastFragDone
);
wwo
->
dwOffCurrHdr
+=
count
;
wwo
->
dwRemain
=
wwo
->
dwFragmentSize
;
}
}
}
}
int
wodPlayer_Message
(
WINE_WAVEOUT
*
wwo
,
int
msg
,
DWORD
param
)
{
TRACE
(
"wodPlayerMessage sammplerate= %d msg=%d
\n
"
,
spec
[
PLAYBACK
].
rate
,
msg
);
EnterCriticalSection
(
&
wwo
->
msg_crst
);
if
((
wwo
->
msg_tosave
==
wwo
->
msg_toget
)
/* buffer overflow ? */
&&
(
wwo
->
messages
[
wwo
->
msg_toget
].
msg
))
{
ERR
(
"buffer overflow !?
\n
"
);
LeaveCriticalSection
(
&
wwo
->
msg_crst
);
return
0
;
}
wwo
->
messages
[
wwo
->
msg_tosave
].
msg
=
msg
;
wwo
->
messages
[
wwo
->
msg_tosave
].
param
=
param
;
wwo
->
msg_tosave
++
;
if
(
wwo
->
msg_tosave
>
WWO_RING_BUFFER_SIZE
-
1
)
wwo
->
msg_tosave
=
0
;
LeaveCriticalSection
(
&
wwo
->
msg_crst
);
/* signal a new message */
SetEvent
(
wwo
->
msg_event
);
return
1
;
}
int
wodPlayer_RetrieveMessage
(
WINE_WAVEOUT
*
wwo
,
int
*
msg
,
DWORD
*
param
)
{
EnterCriticalSection
(
&
wwo
->
msg_crst
);
if
(
wwo
->
msg_toget
==
wwo
->
msg_tosave
)
/* buffer empty ? */
{
LeaveCriticalSection
(
&
wwo
->
msg_crst
);
return
0
;
}
*
msg
=
wwo
->
messages
[
wwo
->
msg_toget
].
msg
;
wwo
->
messages
[
wwo
->
msg_toget
].
msg
=
0
;
*
param
=
wwo
->
messages
[
wwo
->
msg_toget
].
param
;
wwo
->
msg_toget
++
;
if
(
wwo
->
msg_toget
>
WWO_RING_BUFFER_SIZE
-
1
)
wwo
->
msg_toget
=
0
;
LeaveCriticalSection
(
&
wwo
->
msg_crst
);
return
1
;
}
/**************************************************************************
* wodPlayer_Notify [internal]
*
* wodPlayer helper. Notifies (and remove from queue) all the wavehdr which content
* have been played (actually to speaker, not to unixdev fd).
*/
static
void
wodPlayer_Notify
(
WINE_WAVEOUT
*
wwo
,
WORD
uDevID
,
BOOL
force
)
{
LPWAVEHDR
lpWaveHdr
;
DWORD
tc
=
GetTickCount
();
while
(
wwo
->
lpQueuePtr
&&
(
force
||
(
wwo
->
lpQueuePtr
!=
wwo
->
lpPlayPtr
&&
wwo
->
lpQueuePtr
!=
wwo
->
lpLoopPtr
)))
{
lpWaveHdr
=
wwo
->
lpQueuePtr
;
if
(
lpWaveHdr
->
reserved
>
tc
&&
!
force
)
break
;
wwo
->
dwPlayedTotal
+=
lpWaveHdr
->
dwBufferLength
;
wwo
->
lpQueuePtr
=
lpWaveHdr
->
lpNext
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
TRACE
(
"Notifying client with %p
\n
"
,
lpWaveHdr
);
if
(
LIBAUDIOIO_NotifyClient
(
uDevID
,
WOM_DONE
,
(
DWORD
)
lpWaveHdr
,
0
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
}
}
}
/**************************************************************************
* wodPlayer_Reset [internal]
*
* wodPlayer helper. Resets current output stream.
*/
static
void
wodPlayer_Reset
(
WINE_WAVEOUT
*
wwo
,
WORD
uDevID
,
BOOL
reset
)
{
/* updates current notify list */
wodPlayer_Notify
(
wwo
,
uDevID
,
FALSE
);
/* flush all possible output */
/*
*FIXME In the original code I think this aborted IO. With Libaudioio you have to wait
* The following function just blocks untill I/O is complete
* There is possibly a way to abort the blocks buffered in streams
* but this approach seems to work OK
*/
AudioIOFlush
();
wwo
->
dwOffCurrHdr
=
0
;
wwo
->
dwRemain
=
wwo
->
dwFragmentSize
;
if
(
reset
)
{
/* empty notify list */
wodPlayer_Notify
(
wwo
,
uDevID
,
TRUE
);
wwo
->
lpPlayPtr
=
wwo
->
lpQueuePtr
=
wwo
->
lpLoopPtr
=
NULL
;
wwo
->
state
=
WINE_WS_STOPPED
;
wwo
->
dwPlayedTotal
=
0
;
}
else
{
/* FIXME: this is not accurate when looping, but can be do better ? */
wwo
->
lpPlayPtr
=
(
wwo
->
lpLoopPtr
)
?
wwo
->
lpLoopPtr
:
wwo
->
lpQueuePtr
;
wwo
->
state
=
WINE_WS_PAUSED
;
}
}
/**************************************************************************
* wodPlayer [internal]
*/
static
DWORD
CALLBACK
wodPlayer
(
LPVOID
pmt
)
{
WORD
uDevID
=
(
DWORD
)
pmt
;
WINE_WAVEOUT
*
wwo
=
(
WINE_WAVEOUT
*
)
&
WOutDev
[
uDevID
];
WAVEHDR
*
lpWaveHdr
;
DWORD
dwSleepTime
;
int
msg
;
DWORD
param
;
DWORD
tc
;
BOOL
had_msg
;
wwo
->
state
=
WINE_WS_STOPPED
;
wwo
->
dwLastFragDone
=
0
;
wwo
->
dwOffCurrHdr
=
0
;
wwo
->
dwRemain
=
wwo
->
dwFragmentSize
;
wwo
->
lpQueuePtr
=
wwo
->
lpPlayPtr
=
wwo
->
lpLoopPtr
=
NULL
;
wwo
->
dwPlayedTotal
=
0
;
TRACE
(
"imhere[0]
\n
"
);
SetEvent
(
wwo
->
hEvent
);
for
(;;)
{
/* wait for dwSleepTime or an event in thread's queue
* FIXME:
* - is wait time calculation optimal ?
* - these 100 ms parts should be changed, but Eric reports
* that the wodPlayer thread might lock up if we use INFINITE
* (strange !), so I better don't change that now... */
if
(
wwo
->
state
!=
WINE_WS_PLAYING
)
dwSleepTime
=
100
;
else
{
tc
=
GetTickCount
();
if
(
tc
<
wwo
->
dwLastFragDone
)
{
/* calculate sleep time depending on when the last fragment
will be played */
dwSleepTime
=
(
wwo
->
dwLastFragDone
-
tc
)
*
7
/
10
;
if
(
dwSleepTime
>
100
)
dwSleepTime
=
100
;
}
else
dwSleepTime
=
0
;
}
TRACE
(
"imhere[1] tc = %08lx
\n
"
,
GetTickCount
());
if
(
dwSleepTime
)
WaitForSingleObject
(
wwo
->
msg_event
,
dwSleepTime
);
TRACE
(
"imhere[2] (q=%p p=%p) tc = %08lx
\n
"
,
wwo
->
lpQueuePtr
,
wwo
->
lpPlayPtr
,
GetTickCount
());
had_msg
=
FALSE
;
while
(
wodPlayer_RetrieveMessage
(
wwo
,
&
msg
,
&
param
))
{
had_msg
=
TRUE
;
switch
(
msg
)
{
case
WINE_WM_PAUSING
:
wodPlayer_Reset
(
wwo
,
uDevID
,
FALSE
);
wwo
->
state
=
WINE_WS_PAUSED
;
SetEvent
(
wwo
->
hEvent
);
break
;
case
WINE_WM_RESTARTING
:
wwo
->
state
=
WINE_WS_PLAYING
;
SetEvent
(
wwo
->
hEvent
);
break
;
case
WINE_WM_HEADER
:
lpWaveHdr
=
(
LPWAVEHDR
)
param
;
/* insert buffer at the end of queue */
{
LPWAVEHDR
*
wh
;
for
(
wh
=
&
(
wwo
->
lpQueuePtr
);
*
wh
;
wh
=
&
((
*
wh
)
->
lpNext
));
*
wh
=
lpWaveHdr
;
}
if
(
!
wwo
->
lpPlayPtr
)
wwo
->
lpPlayPtr
=
lpWaveHdr
;
if
(
wwo
->
state
==
WINE_WS_STOPPED
)
wwo
->
state
=
WINE_WS_PLAYING
;
break
;
case
WINE_WM_RESETTING
:
wodPlayer_Reset
(
wwo
,
uDevID
,
TRUE
);
SetEvent
(
wwo
->
hEvent
);
break
;
case
WINE_WM_CLOSING
:
/* sanity check: this should not happen since the device must have been reset before */
if
(
wwo
->
lpQueuePtr
||
wwo
->
lpPlayPtr
)
ERR
(
"out of sync
\n
"
);
wwo
->
hThread
=
0
;
wwo
->
state
=
WINE_WS_CLOSED
;
SetEvent
(
wwo
->
hEvent
);
ExitThread
(
0
);
/* shouldn't go here */
default:
FIXME
(
"unknown message %d
\n
"
,
msg
);
break
;
}
if
(
wwo
->
state
==
WINE_WS_PLAYING
)
{
wodPlayer_WriteFragments
(
wwo
);
}
wodPlayer_Notify
(
wwo
,
uDevID
,
FALSE
);
}
if
(
!
had_msg
)
{
/* if we've received a msg we've just done this so we
won't repeat it */
if
(
wwo
->
state
==
WINE_WS_PLAYING
)
{
wodPlayer_WriteFragments
(
wwo
);
}
wodPlayer_Notify
(
wwo
,
uDevID
,
FALSE
);
}
}
ExitThread
(
0
);
/* just for not generating compilation warnings... should never be executed */
return
0
;
}
/**************************************************************************
* wodGetDevCaps [internal]
*/
static
DWORD
wodGetDevCaps
(
WORD
wDevID
,
LPWAVEOUTCAPSA
lpCaps
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpCaps
,
dwSize
);
if
(
lpCaps
==
NULL
)
return
MMSYSERR_NOTENABLED
;
if
(
wDevID
>=
MAX_WAVEOUTDRV
)
{
TRACE
(
"MAX_WAVOUTDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
memcpy
(
lpCaps
,
&
WOutDev
[
wDevID
].
caps
,
min
(
dwSize
,
sizeof
(
*
lpCaps
)));
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodOpen [internal]
*/
static
DWORD
wodOpen
(
WORD
wDevID
,
LPWAVEOPENDESC
lpDesc
,
DWORD
dwFlags
)
{
int
audio
;
int
format
;
int
sample_rate
;
int
dsp_stereo
;
int
fragment_size
;
int
audio_fragment
;
WINE_WAVEOUT
*
wwo
;
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpDesc
,
dwFlags
);
if
(
lpDesc
==
NULL
)
{
WARN
(
"Invalid Parameter !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
if
(
wDevID
>=
MAX_WAVEOUTDRV
)
{
TRACE
(
"MAX_WAVOUTDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
/* only PCM format is supported so far... */
if
(
lpDesc
->
lpFormat
->
wFormatTag
!=
WAVE_FORMAT_PCM
||
lpDesc
->
lpFormat
->
nChannels
==
0
||
lpDesc
->
lpFormat
->
nSamplesPerSec
==
0
)
{
WARN
(
"Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
WAVERR_BADFORMAT
;
}
if
(
dwFlags
&
WAVE_FORMAT_QUERY
)
{
TRACE
(
"Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
MMSYSERR_NOERROR
;
}
wwo
=
&
WOutDev
[
wDevID
];
if
((
dwFlags
&
WAVE_DIRECTSOUND
)
&&
!
(
wwo
->
caps
.
dwSupport
&
WAVECAPS_DIRECTSOUND
))
/* not supported, ignore it */
dwFlags
&=
~
WAVE_DIRECTSOUND
;
if
(
access
(
SOUND_DEV
,
0
)
!=
0
)
return
MMSYSERR_NOTENABLED
;
audio
=
AudioIOOpenX
(
O_WRONLY
|
O_NDELAY
,
&
spec
[
PLAYBACK
],
&
spec
[
PLAYBACK
]);
if
(
audio
==
-
1
)
{
WARN
(
"can't open sound device %s (%s)!
\n
"
,
SOUND_DEV
,
strerror
(
errno
));
return
MMSYSERR_ALLOCATED
;
}
/* fcntl(audio, F_SETFD, 1); *//* set close on exec flag - Dunno about this (RL)*/
wwo
->
unixdev
=
audio
;
wwo
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
memcpy
(
&
wwo
->
waveDesc
,
lpDesc
,
sizeof
(
WAVEOPENDESC
));
memcpy
(
&
wwo
->
format
,
lpDesc
->
lpFormat
,
sizeof
(
PCMWAVEFORMAT
));
if
(
wwo
->
format
.
wBitsPerSample
==
0
)
{
WARN
(
"Resetting zeroed wBitsPerSample
\n
"
);
wwo
->
format
.
wBitsPerSample
=
8
*
(
wwo
->
format
.
wf
.
nAvgBytesPerSec
/
wwo
->
format
.
wf
.
nSamplesPerSec
)
/
wwo
->
format
.
wf
.
nChannels
;
}
if
(
dwFlags
&
WAVE_DIRECTSOUND
)
{
if
(
wwo
->
caps
.
dwSupport
&
WAVECAPS_SAMPLEACCURATE
)
/* we have realtime DirectSound, fragments just waste our time,
* but a large buffer is good, so choose 64KB (32 * 2^11) */
audio_fragment
=
0x0020000B
;
else
/* to approximate realtime, we must use small fragments,
* let's try to fragment the above 64KB (256 * 2^8) */
audio_fragment
=
0x01000008
;
}
else
{
/* shockwave player uses only 4 1k-fragments at a rate of 22050 bytes/sec
* thus leading to 46ms per fragment, and a turnaround time of 185ms
*/
/* 16 fragments max, 2^10=1024 bytes per fragment */
audio_fragment
=
0x000F000A
;
}
sample_rate
=
wwo
->
format
.
wf
.
nSamplesPerSec
;
dsp_stereo
=
(
wwo
->
format
.
wf
.
nChannels
>
1
)
?
1
:
0
;
/*Set the sample rate*/
spec
[
PLAYBACK
].
rate
=
sample_rate
;
/*And the size and signedness*/
spec
[
PLAYBACK
].
precision
=
(
wwo
->
format
.
wBitsPerSample
);
if
(
spec
[
PLAYBACK
].
precision
==
16
)
spec
[
PLAYBACK
].
type
=
TYPE_SIGNED
;
else
spec
[
PLAYBACK
].
type
=
TYPE_UNSIGNED
;
spec
[
PLAYBACK
].
channels
=
(
wwo
->
format
.
wf
.
nChannels
);
spec
[
PLAYBACK
].
encoding
=
ENCODE_PCM
;
spec
[
PLAYBACK
].
endian
=
ENDIAN_INTEL
;
spec
[
PLAYBACK
].
max_blocks
=
16
;
/*FIXME This is the libaudioio equivalent to fragments, it controls latency*/
audio
=
AudioIOOpenX
(
O_WRONLY
|
O_NDELAY
,
&
spec
[
PLAYBACK
],
&
spec
[
PLAYBACK
]);
if
(
audio
==
-
1
)
{
WARN
(
"can't open sound device %s (%s)!
\n
"
,
SOUND_DEV
,
strerror
(
errno
));
return
MMSYSERR_ALLOCATED
;
}
/* fcntl(audio, F_SETFD, 1); *//* set close on exec flag */
wwo
->
unixdev
=
audio
;
/* even if we set fragment size above, read it again, just in case */
wwo
->
dwFragmentSize
=
DEFAULT_FRAGMENT_SIZE
;
wwo
->
msg_toget
=
0
;
wwo
->
msg_tosave
=
0
;
wwo
->
msg_event
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
memset
(
wwo
->
messages
,
0
,
sizeof
(
WWO_MSG
)
*
WWO_RING_BUFFER_SIZE
);
InitializeCriticalSection
(
&
wwo
->
msg_crst
);
if
(
!
(
dwFlags
&
WAVE_DIRECTSOUND
))
{
wwo
->
hEvent
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
wwo
->
hThread
=
CreateThread
(
NULL
,
0
,
wodPlayer
,
(
LPVOID
)(
DWORD
)
wDevID
,
0
,
&
(
wwo
->
dwThreadID
));
WaitForSingleObject
(
wwo
->
hEvent
,
INFINITE
);
}
else
{
wwo
->
hEvent
=
INVALID_HANDLE_VALUE
;
wwo
->
hThread
=
INVALID_HANDLE_VALUE
;
wwo
->
dwThreadID
=
0
;
}
TRACE
(
"fd=%d fragmentSize=%ld
\n
"
,
wwo
->
unixdev
,
wwo
->
dwFragmentSize
);
if
(
wwo
->
dwFragmentSize
%
wwo
->
format
.
wf
.
nBlockAlign
)
ERR
(
"Fragment doesn't contain an integral number of data blocks
\n
"
);
TRACE
(
"wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!
\n
"
,
wwo
->
format
.
wBitsPerSample
,
wwo
->
format
.
wf
.
nAvgBytesPerSec
,
wwo
->
format
.
wf
.
nSamplesPerSec
,
wwo
->
format
.
wf
.
nChannels
,
wwo
->
format
.
wf
.
nBlockAlign
);
if
(
LIBAUDIOIO_NotifyClient
(
wDevID
,
WOM_OPEN
,
0L
,
0L
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodClose [internal]
*/
static
DWORD
wodClose
(
WORD
wDevID
)
{
DWORD
ret
=
MMSYSERR_NOERROR
;
WINE_WAVEOUT
*
wwo
;
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
wwo
=
&
WOutDev
[
wDevID
];
if
(
wwo
->
lpQueuePtr
)
{
WARN
(
"buffers still playing !
\n
"
);
ret
=
WAVERR_STILLPLAYING
;
}
else
{
TRACE
(
"imhere[3-close]
\n
"
);
if
(
wwo
->
hEvent
!=
INVALID_HANDLE_VALUE
)
{
wodPlayer_Message
(
wwo
,
WINE_WM_CLOSING
,
0
);
WaitForSingleObject
(
wwo
->
hEvent
,
INFINITE
);
CloseHandle
(
wwo
->
hEvent
);
}
if
(
wwo
->
mapping
)
{
munmap
(
wwo
->
mapping
,
wwo
->
maplen
);
wwo
->
mapping
=
NULL
;
}
AudioIOClose
();
wwo
->
unixdev
=
-
1
;
wwo
->
dwFragmentSize
=
0
;
if
(
LIBAUDIOIO_NotifyClient
(
wDevID
,
WOM_CLOSE
,
0L
,
0L
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
ret
=
MMSYSERR_INVALPARAM
;
}
}
return
ret
;
}
/**************************************************************************
* wodWrite [internal]
*
*/
static
DWORD
wodWrite
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
/* first, do the sanity checks... */
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad dev ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
if
(
lpWaveHdr
->
lpData
==
NULL
||
!
(
lpWaveHdr
->
dwFlags
&
WHDR_PREPARED
))
return
WAVERR_UNPREPARED
;
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwFlags
|=
WHDR_INQUEUE
;
lpWaveHdr
->
lpNext
=
0
;
TRACE
(
"imhere[3-HEADER]
\n
"
);
wodPlayer_Message
(
&
WOutDev
[
wDevID
],
WINE_WM_HEADER
,
(
DWORD
)
lpWaveHdr
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodPrepare [internal]
*/
static
DWORD
wodPrepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
|=
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodUnprepare [internal]
*/
static
DWORD
wodUnprepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodPause [internal]
*/
static
DWORD
wodPause
(
WORD
wDevID
)
{
TRACE
(
"(%u);!
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
TRACE
(
"imhere[3-PAUSING]
\n
"
);
wodPlayer_Message
(
&
WOutDev
[
wDevID
],
WINE_WM_PAUSING
,
0
);
WaitForSingleObject
(
WOutDev
[
wDevID
].
hEvent
,
INFINITE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodRestart [internal]
*/
static
DWORD
wodRestart
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
if
(
WOutDev
[
wDevID
].
state
==
WINE_WS_PAUSED
)
{
TRACE
(
"imhere[3-RESTARTING]
\n
"
);
wodPlayer_Message
(
&
WOutDev
[
wDevID
],
WINE_WM_RESTARTING
,
0
);
WaitForSingleObject
(
WOutDev
[
wDevID
].
hEvent
,
INFINITE
);
}
/* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
/* FIXME: Myst crashes with this ... hmm -MM
if (LIBAUDIOIO_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
WARN("can't notify client !\n");
return MMSYSERR_INVALPARAM;
}
*/
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodReset [internal]
*/
static
DWORD
wodReset
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
TRACE
(
"imhere[3-RESET]
\n
"
);
wodPlayer_Message
(
&
WOutDev
[
wDevID
],
WINE_WM_RESETTING
,
0
);
WaitForSingleObject
(
WOutDev
[
wDevID
].
hEvent
,
INFINITE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodGetPosition [internal]
*/
static
DWORD
wodGetPosition
(
WORD
wDevID
,
LPMMTIME
lpTime
,
DWORD
uSize
)
{
int
time
;
DWORD
val
;
WINE_WAVEOUT
*
wwo
;
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpTime
,
uSize
);
if
(
wDevID
>=
MAX_WAVEOUTDRV
||
WOutDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
if
(
lpTime
==
NULL
)
return
MMSYSERR_INVALPARAM
;
wwo
=
&
WOutDev
[
wDevID
];
val
=
wwo
->
dwPlayedTotal
;
TRACE
(
"wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu
\n
"
,
lpTime
->
wType
,
wwo
->
format
.
wBitsPerSample
,
wwo
->
format
.
wf
.
nSamplesPerSec
,
wwo
->
format
.
wf
.
nChannels
,
wwo
->
format
.
wf
.
nAvgBytesPerSec
);
TRACE
(
"dwTotalPlayed=%lu
\n
"
,
val
);
switch
(
lpTime
->
wType
)
{
case
TIME_BYTES
:
lpTime
->
u
.
cb
=
val
;
TRACE
(
"TIME_BYTES=%lu
\n
"
,
lpTime
->
u
.
cb
);
break
;
case
TIME_SAMPLES
:
lpTime
->
u
.
sample
=
val
*
8
/
wwo
->
format
.
wBitsPerSample
;
TRACE
(
"TIME_SAMPLES=%lu
\n
"
,
lpTime
->
u
.
sample
);
break
;
case
TIME_SMPTE
:
time
=
val
/
(
wwo
->
format
.
wf
.
nAvgBytesPerSec
/
1000
);
lpTime
->
u
.
smpte
.
hour
=
time
/
108000
;
time
-=
lpTime
->
u
.
smpte
.
hour
*
108000
;
lpTime
->
u
.
smpte
.
min
=
time
/
1800
;
time
-=
lpTime
->
u
.
smpte
.
min
*
1800
;
lpTime
->
u
.
smpte
.
sec
=
time
/
30
;
time
-=
lpTime
->
u
.
smpte
.
sec
*
30
;
lpTime
->
u
.
smpte
.
frame
=
time
;
lpTime
->
u
.
smpte
.
fps
=
30
;
TRACE
(
"TIME_SMPTE=%02u:%02u:%02u:%02u
\n
"
,
lpTime
->
u
.
smpte
.
hour
,
lpTime
->
u
.
smpte
.
min
,
lpTime
->
u
.
smpte
.
sec
,
lpTime
->
u
.
smpte
.
frame
);
break
;
default:
FIXME
(
"Format %d not supported ! use TIME_MS !
\n
"
,
lpTime
->
wType
);
lpTime
->
wType
=
TIME_MS
;
case
TIME_MS
:
lpTime
->
u
.
ms
=
val
/
(
wwo
->
format
.
wf
.
nAvgBytesPerSec
/
1000
);
TRACE
(
"TIME_MS=%lu
\n
"
,
lpTime
->
u
.
ms
);
break
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodGetVolume [internal]
*/
static
DWORD
wodGetVolume
(
WORD
wDevID
,
LPDWORD
lpdwVol
)
{
int
mixer
;
int
vol
,
bal
;
DWORD
left
,
right
;
TRACE
(
"(%u, %p);
\n
"
,
wDevID
,
lpdwVol
);
if
(
lpdwVol
==
NULL
)
return
MMSYSERR_NOTENABLED
;
vol
=
AudioIOGetPlaybackVolume
();
bal
=
AudioIOGetPlaybackBalance
();
if
(
bal
<
0
)
{
left
=
vol
;
right
=-
(
vol
*
(
-
100
+
bal
)
/
100
);
}
else
{
right
=
vol
;
left
=
(
vol
*
(
100
-
bal
)
/
100
);
}
*
lpdwVol
=
((
left
*
0xFFFFl
)
/
100
)
+
(((
right
*
0xFFFFl
)
/
100
)
<<
16
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodSetVolume [internal]
*/
static
DWORD
wodSetVolume
(
WORD
wDevID
,
DWORD
dwParam
)
{
int
mixer
;
int
volume
,
bal
;
DWORD
left
,
right
;
TRACE
(
"(%u, %08lX);
\n
"
,
wDevID
,
dwParam
);
left
=
(
LOWORD
(
dwParam
)
*
100
)
/
0xFFFFl
;
right
=
(
HIWORD
(
dwParam
)
*
100
)
/
0xFFFFl
;
volume
=
max
(
left
,
right
);
bal
=
min
(
left
,
right
);
bal
=
bal
*
100
/
volume
;
if
(
right
>
left
)
bal
=-
100
+
bal
;
else
bal
=
100
-
bal
;
AudioIOSetPlaybackVolume
(
volume
);
AudioIOSetPlaybackBalance
(
bal
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodGetNumDevs [internal]
*/
static
DWORD
wodGetNumDevs
(
void
)
{
DWORD
ret
=
1
;
/* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
int
audio
=
open
(
SOUND_DEV
,
O_WRONLY
|
O_NDELAY
,
0
);
if
(
audio
==
-
1
)
{
if
(
errno
!=
EBUSY
)
ret
=
0
;
}
else
{
close
(
audio
);
}
TRACE
(
"NumDrivers = %d
\n
"
,
ret
);
return
ret
;
}
/**************************************************************************
* wodMessage (WINEOSS.7)
*/
DWORD
WINAPI
LIBAUDIOIO_wodMessage
(
UINT
wDevID
,
UINT
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"(%u, %04X, %08lX, %08lX, %08lX);
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
DRVM_INIT
:
case
DRVM_EXIT
:
case
DRVM_ENABLE
:
case
DRVM_DISABLE
:
/* FIXME: Pretend this is supported */
return
0
;
case
WODM_OPEN
:
return
wodOpen
(
wDevID
,
(
LPWAVEOPENDESC
)
dwParam1
,
dwParam2
);
case
WODM_CLOSE
:
return
wodClose
(
wDevID
);
case
WODM_WRITE
:
return
wodWrite
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WODM_PAUSE
:
return
wodPause
(
wDevID
);
case
WODM_GETPOS
:
return
wodGetPosition
(
wDevID
,
(
LPMMTIME
)
dwParam1
,
dwParam2
);
case
WODM_BREAKLOOP
:
return
MMSYSERR_NOTSUPPORTED
;
case
WODM_PREPARE
:
return
wodPrepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WODM_UNPREPARE
:
return
wodUnprepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WODM_GETDEVCAPS
:
return
wodGetDevCaps
(
wDevID
,
(
LPWAVEOUTCAPSA
)
dwParam1
,
dwParam2
);
case
WODM_GETNUMDEVS
:
return
wodGetNumDevs
();
case
WODM_GETPITCH
:
return
MMSYSERR_NOTSUPPORTED
;
case
WODM_SETPITCH
:
return
MMSYSERR_NOTSUPPORTED
;
case
WODM_GETPLAYBACKRATE
:
return
MMSYSERR_NOTSUPPORTED
;
case
WODM_SETPLAYBACKRATE
:
return
MMSYSERR_NOTSUPPORTED
;
case
WODM_GETVOLUME
:
return
wodGetVolume
(
wDevID
,
(
LPDWORD
)
dwParam1
);
case
WODM_SETVOLUME
:
return
wodSetVolume
(
wDevID
,
dwParam1
);
case
WODM_RESTART
:
return
wodRestart
(
wDevID
);
case
WODM_RESET
:
return
wodReset
(
wDevID
);
case
DRV_QUERYDSOUNDIFACE
:
return
wodDsCreate
(
wDevID
,
(
PIDSDRIVER
*
)
dwParam1
);
default:
FIXME
(
"unknown message %d!
\n
"
,
wMsg
);
}
return
MMSYSERR_NOTSUPPORTED
;
}
/*======================================================================*
* Low level DSOUND implementation *
* While I have tampered somewhat with this code it is wholely unlikely that it works
* Elsewhere the driver returns Not Implemented for DIrectSound
* While it may be possible to map the sound device on Solaris
* Doing so would bypass the libaudioio library and therefore break any conversions
* that the libaudioio sample specification converter is doing
* **** All this is untested so far
*======================================================================*/
typedef
struct
IDsDriverImpl
IDsDriverImpl
;
typedef
struct
IDsDriverBufferImpl
IDsDriverBufferImpl
;
struct
IDsDriverImpl
{
/* IUnknown fields */
ICOM_VFIELD
(
IDsDriver
);
DWORD
ref
;
/* IDsDriverImpl fields */
UINT
wDevID
;
IDsDriverBufferImpl
*
primary
;
};
struct
IDsDriverBufferImpl
{
/* IUnknown fields */
ICOM_VFIELD
(
IDsDriverBuffer
);
DWORD
ref
;
/* IDsDriverBufferImpl fields */
IDsDriverImpl
*
drv
;
DWORD
buflen
;
};
static
HRESULT
DSDB_MapPrimary
(
IDsDriverBufferImpl
*
dsdb
)
{
WINE_WAVEOUT
*
wwo
=
&
(
WOutDev
[
dsdb
->
drv
->
wDevID
]);
if
(
!
wwo
->
mapping
)
{
wwo
->
mapping
=
mmap
(
NULL
,
wwo
->
maplen
,
PROT_WRITE
,
MAP_SHARED
,
wwo
->
unixdev
,
0
);
if
(
wwo
->
mapping
==
(
LPBYTE
)
-
1
)
{
ERR
(
"(%p): Could not map sound device for direct access (errno=%d)
\n
"
,
dsdb
,
errno
);
return
DSERR_GENERIC
;
}
TRACE
(
"(%p): sound device has been mapped for direct access at %p, size=%ld
\n
"
,
dsdb
,
wwo
->
mapping
,
wwo
->
maplen
);
/* for some reason, es1371 and sblive! sometimes have junk in here. */
memset
(
wwo
->
mapping
,
0
,
wwo
->
maplen
);
/* clear it, or we get junk noise */
}
return
DS_OK
;
}
static
HRESULT
DSDB_UnmapPrimary
(
IDsDriverBufferImpl
*
dsdb
)
{
WINE_WAVEOUT
*
wwo
=
&
(
WOutDev
[
dsdb
->
drv
->
wDevID
]);
if
(
wwo
->
mapping
)
{
if
(
munmap
(
wwo
->
mapping
,
wwo
->
maplen
)
<
0
)
{
ERR
(
"(%p): Could not unmap sound device (errno=%d)
\n
"
,
dsdb
,
errno
);
return
DSERR_GENERIC
;
}
wwo
->
mapping
=
NULL
;
TRACE
(
"(%p): sound device unmapped
\n
"
,
dsdb
);
}
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_QueryInterface
(
PIDSDRIVERBUFFER
iface
,
REFIID
riid
,
LPVOID
*
ppobj
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
FIXME
(
"(): stub!
\n
"
);
return
DSERR_UNSUPPORTED
;
}
static
ULONG
WINAPI
IDsDriverBufferImpl_AddRef
(
PIDSDRIVERBUFFER
iface
)
{
ICOM_THIS
(
IDsDriverBufferImpl
,
iface
);
This
->
ref
++
;
return
This
->
ref
;
}
static
ULONG
WINAPI
IDsDriverBufferImpl_Release
(
PIDSDRIVERBUFFER
iface
)
{
ICOM_THIS
(
IDsDriverBufferImpl
,
iface
);
if
(
--
This
->
ref
)
return
This
->
ref
;
if
(
This
==
This
->
drv
->
primary
)
This
->
drv
->
primary
=
NULL
;
DSDB_UnmapPrimary
(
This
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
return
0
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_Lock
(
PIDSDRIVERBUFFER
iface
,
LPVOID
*
ppvAudio1
,
LPDWORD
pdwLen1
,
LPVOID
*
ppvAudio2
,
LPDWORD
pdwLen2
,
DWORD
dwWritePosition
,
DWORD
dwWriteLen
,
DWORD
dwFlags
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
/* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
* and that we don't support secondary buffers, this method will never be called */
TRACE
(
"(%p): stub
\n
"
,
iface
);
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_Unlock
(
PIDSDRIVERBUFFER
iface
,
LPVOID
pvAudio1
,
DWORD
dwLen1
,
LPVOID
pvAudio2
,
DWORD
dwLen2
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
TRACE
(
"(%p): stub
\n
"
,
iface
);
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_SetFormat
(
PIDSDRIVERBUFFER
iface
,
LPWAVEFORMATEX
pwfx
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
TRACE
(
"(%p,%p)
\n
"
,
iface
,
pwfx
);
/* On our request (GetDriverDesc flags), DirectSound has by now used
* waveOutClose/waveOutOpen to set the format...
* unfortunately, this means our mmap() is now gone...
* so we need to somehow signal to our DirectSound implementation
* that it should completely recreate this HW buffer...
* this unexpected error code should do the trick... */
return
DSERR_BUFFERLOST
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_SetFrequency
(
PIDSDRIVERBUFFER
iface
,
DWORD
dwFreq
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
TRACE
(
"(%p,%ld): stub
\n
"
,
iface
,
dwFreq
);
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_SetVolumePan
(
PIDSDRIVERBUFFER
iface
,
PDSVOLUMEPAN
pVolPan
)
{
/* ICOM_THIS(IDsDriverBufferImpl,iface); */
FIXME
(
"(%p,%p): stub!
\n
"
,
iface
,
pVolPan
);
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_SetPosition
(
PIDSDRIVERBUFFER
iface
,
DWORD
dwNewPos
)
{
/* ICOM_THIS(IDsDriverImpl,iface); */
TRACE
(
"(%p,%ld): stub
\n
"
,
iface
,
dwNewPos
);
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_GetPosition
(
PIDSDRIVERBUFFER
iface
,
LPDWORD
lpdwPlay
,
LPDWORD
lpdwWrite
)
{
ICOM_THIS
(
IDsDriverBufferImpl
,
iface
);
// count_info info;
DWORD
ptr
;
TRACE
(
"(%p)
\n
"
,
iface
);
if
(
WOutDev
[
This
->
drv
->
wDevID
].
unixdev
==
-
1
)
{
ERR
(
"device not open, but accessing?
\n
"
);
return
DSERR_UNINITIALIZED
;
}
/*Libaudioio doesn't support this (Yet anyway)*/
return
DSERR_UNSUPPORTED
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_Play
(
PIDSDRIVERBUFFER
iface
,
DWORD
dwRes1
,
DWORD
dwRes2
,
DWORD
dwFlags
)
{
ICOM_THIS
(
IDsDriverBufferImpl
,
iface
);
#if 0
int enable = PCM_ENABLE_OUTPUT;
TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags);
if (ioctl(WOutDev[This->drv->wDevID].unixdev, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
ERR("ioctl failed (%d)\n", errno);
return DSERR_GENERIC;
}
#endif
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverBufferImpl_Stop
(
PIDSDRIVERBUFFER
iface
)
{
ICOM_THIS
(
IDsDriverBufferImpl
,
iface
);
int
enable
=
0
;
#if 0
TRACE("(%p)\n",iface);
/* no more playing */
if (ioctl(WOutDev[This->drv->wDevID].unixdev, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
ERR("ioctl failed (%d)\n", errno);
return DSERR_GENERIC;
}
#endif
#if 0
/* the play position must be reset to the beginning of the buffer */
if (ioctl(WOutDev[This->drv->wDevID].unixdev, SNDCTL_DSP_RESET, 0) < 0) {
ERR("ioctl failed (%d)\n", errno);
return DSERR_GENERIC;
}
#endif
/* Most OSS drivers just can't stop the playback without closing the device...
* so we need to somehow signal to our DirectSound implementation
* that it should completely recreate this HW buffer...
* this unexpected error code should do the trick... */
return
DSERR_BUFFERLOST
;
}
static
ICOM_VTABLE
(
IDsDriverBuffer
)
dsdbvt
=
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IDsDriverBufferImpl_QueryInterface
,
IDsDriverBufferImpl_AddRef
,
IDsDriverBufferImpl_Release
,
IDsDriverBufferImpl_Lock
,
IDsDriverBufferImpl_Unlock
,
IDsDriverBufferImpl_SetFormat
,
IDsDriverBufferImpl_SetFrequency
,
IDsDriverBufferImpl_SetVolumePan
,
IDsDriverBufferImpl_SetPosition
,
IDsDriverBufferImpl_GetPosition
,
IDsDriverBufferImpl_Play
,
IDsDriverBufferImpl_Stop
};
static
HRESULT
WINAPI
IDsDriverImpl_QueryInterface
(
PIDSDRIVER
iface
,
REFIID
riid
,
LPVOID
*
ppobj
)
{
/* ICOM_THIS(IDsDriverImpl,iface); */
FIXME
(
"(%p): stub!
\n
"
,
iface
);
return
DSERR_UNSUPPORTED
;
}
static
ULONG
WINAPI
IDsDriverImpl_AddRef
(
PIDSDRIVER
iface
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
This
->
ref
++
;
return
This
->
ref
;
}
static
ULONG
WINAPI
IDsDriverImpl_Release
(
PIDSDRIVER
iface
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
if
(
--
This
->
ref
)
return
This
->
ref
;
HeapFree
(
GetProcessHeap
(),
0
,
This
);
return
0
;
}
static
HRESULT
WINAPI
IDsDriverImpl_GetDriverDesc
(
PIDSDRIVER
iface
,
PDSDRIVERDESC
pDesc
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
TRACE
(
"(%p,%p)
\n
"
,
iface
,
pDesc
);
pDesc
->
dwFlags
=
DSDDESC_DOMMSYSTEMOPEN
|
DSDDESC_DOMMSYSTEMSETFORMAT
|
DSDDESC_USESYSTEMMEMORY
|
DSDDESC_DONTNEEDPRIMARYLOCK
;
strcpy
(
pDesc
->
szDesc
,
"WineOSS DirectSound Driver"
);
strcpy
(
pDesc
->
szDrvName
,
"wineoss.drv"
);
pDesc
->
dnDevNode
=
WOutDev
[
This
->
wDevID
].
waveDesc
.
dnDevNode
;
pDesc
->
wVxdId
=
0
;
pDesc
->
wReserved
=
0
;
pDesc
->
ulDeviceNum
=
This
->
wDevID
;
pDesc
->
dwHeapType
=
DSDHEAP_NOHEAP
;
pDesc
->
pvDirectDrawHeap
=
NULL
;
pDesc
->
dwMemStartAddress
=
0
;
pDesc
->
dwMemEndAddress
=
0
;
pDesc
->
dwMemAllocExtra
=
0
;
pDesc
->
pvReserved1
=
NULL
;
pDesc
->
pvReserved2
=
NULL
;
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverImpl_Open
(
PIDSDRIVER
iface
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
int
enable
=
0
;
TRACE
(
"(%p)
\n
"
,
iface
);
/* make sure the card doesn't start playing before we want it to */
#if 0
if (ioctl(WOutDev[This->wDevID].unixdev, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
ERR("ioctl failed (%d)\n", errno);
return DSERR_GENERIC;
}
#endif
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverImpl_Close
(
PIDSDRIVER
iface
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
TRACE
(
"(%p)
\n
"
,
iface
);
if
(
This
->
primary
)
{
ERR
(
"problem with DirectSound: primary not released
\n
"
);
return
DSERR_GENERIC
;
}
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverImpl_GetCaps
(
PIDSDRIVER
iface
,
PDSDRIVERCAPS
pCaps
)
{
/* ICOM_THIS(IDsDriverImpl,iface); */
TRACE
(
"(%p,%p)
\n
"
,
iface
,
pCaps
);
memset
(
pCaps
,
0
,
sizeof
(
*
pCaps
));
/* FIXME: need to check actual capabilities */
pCaps
->
dwFlags
=
DSCAPS_PRIMARYMONO
|
DSCAPS_PRIMARYSTEREO
|
DSCAPS_PRIMARY8BIT
|
DSCAPS_PRIMARY16BIT
;
pCaps
->
dwPrimaryBuffers
=
1
;
/* the other fields only apply to secondary buffers, which we don't support
* (unless we want to mess with wavetable synthesizers and MIDI) */
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverImpl_CreateSoundBuffer
(
PIDSDRIVER
iface
,
LPWAVEFORMATEX
pwfx
,
DWORD
dwFlags
,
DWORD
dwCardAddress
,
LPDWORD
pdwcbBufferSize
,
LPBYTE
*
ppbBuffer
,
LPVOID
*
ppvObj
)
{
ICOM_THIS
(
IDsDriverImpl
,
iface
);
IDsDriverBufferImpl
**
ippdsdb
=
(
IDsDriverBufferImpl
**
)
ppvObj
;
HRESULT
err
;
// audio_buf_info info;
int
enable
=
0
;
TRACE
(
"(%p,%p,%lx,%lx)
\n
"
,
iface
,
pwfx
,
dwFlags
,
dwCardAddress
);
/* we only support primary buffers */
if
(
!
(
dwFlags
&
DSBCAPS_PRIMARYBUFFER
))
return
DSERR_UNSUPPORTED
;
if
(
This
->
primary
)
return
DSERR_ALLOCATED
;
if
(
dwFlags
&
(
DSBCAPS_CTRLFREQUENCY
|
DSBCAPS_CTRLPAN
))
return
DSERR_CONTROLUNAVAIL
;
*
ippdsdb
=
(
IDsDriverBufferImpl
*
)
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
IDsDriverBufferImpl
));
if
(
*
ippdsdb
==
NULL
)
return
DSERR_OUTOFMEMORY
;
ICOM_VTBL
(
*
ippdsdb
)
=
&
dsdbvt
;
(
*
ippdsdb
)
->
ref
=
1
;
(
*
ippdsdb
)
->
drv
=
This
;
/* check how big the DMA buffer is now */
#if 0
if (ioctl(WOutDev[This->wDevID].unixdev, SNDCTL_DSP_GETOSPACE, &info) < 0) {
ERR("ioctl failed (%d)\n", errno);
HeapFree(GetProcessHeap(),0,*ippdsdb);
*ippdsdb = NULL;
return DSERR_GENERIC;
}
#endif
WOutDev
[
This
->
wDevID
].
maplen
=
64
*
1024
;
// Map 64 K at a time
#if 0
(*ippdsdb)->buflen = info.fragstotal * info.fragsize;
#endif
/* map the DMA buffer */
err
=
DSDB_MapPrimary
(
*
ippdsdb
);
if
(
err
!=
DS_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
*
ippdsdb
);
*
ippdsdb
=
NULL
;
return
err
;
}
/* primary buffer is ready to go */
*
pdwcbBufferSize
=
WOutDev
[
This
->
wDevID
].
maplen
;
*
ppbBuffer
=
WOutDev
[
This
->
wDevID
].
mapping
;
/* some drivers need some extra nudging after mapping */
#if 0
if (ioctl(WOutDev[This->wDevID].unixdev, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
ERR("ioctl failed (%d)\n", errno);
return DSERR_GENERIC;
}
#endif
This
->
primary
=
*
ippdsdb
;
return
DS_OK
;
}
static
HRESULT
WINAPI
IDsDriverImpl_DuplicateSoundBuffer
(
PIDSDRIVER
iface
,
PIDSDRIVERBUFFER
pBuffer
,
LPVOID
*
ppvObj
)
{
/* ICOM_THIS(IDsDriverImpl,iface); */
TRACE
(
"(%p,%p): stub
\n
"
,
iface
,
pBuffer
);
return
DSERR_INVALIDCALL
;
}
static
ICOM_VTABLE
(
IDsDriver
)
dsdvt
=
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IDsDriverImpl_QueryInterface
,
IDsDriverImpl_AddRef
,
IDsDriverImpl_Release
,
IDsDriverImpl_GetDriverDesc
,
IDsDriverImpl_Open
,
IDsDriverImpl_Close
,
IDsDriverImpl_GetCaps
,
IDsDriverImpl_CreateSoundBuffer
,
IDsDriverImpl_DuplicateSoundBuffer
};
static
DWORD
wodDsCreate
(
UINT
wDevID
,
PIDSDRIVER
*
drv
)
{
IDsDriverImpl
**
idrv
=
(
IDsDriverImpl
**
)
drv
;
/* the HAL isn't much better than the HEL if we can't do mmap() */
if
(
!
(
WOutDev
[
wDevID
].
caps
.
dwSupport
&
WAVECAPS_DIRECTSOUND
))
{
ERR
(
"DirectSound flag not set
\n
"
);
MESSAGE
(
"This sound card's driver does not support direct access
\n
"
);
MESSAGE
(
"The (slower) DirectSound HEL mode will be used instead.
\n
"
);
return
MMSYSERR_NOTSUPPORTED
;
}
*
idrv
=
(
IDsDriverImpl
*
)
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
IDsDriverImpl
));
if
(
!*
idrv
)
return
MMSYSERR_NOMEM
;
ICOM_VTBL
(
*
idrv
)
=
&
dsdvt
;
(
*
idrv
)
->
ref
=
1
;
(
*
idrv
)
->
wDevID
=
wDevID
;
(
*
idrv
)
->
primary
=
NULL
;
return
MMSYSERR_NOERROR
;
}
/*======================================================================*
* Low level WAVE IN implementation *
*======================================================================*/
/**************************************************************************
* widGetDevCaps [internal]
*/
static
DWORD
widGetDevCaps
(
WORD
wDevID
,
LPWAVEINCAPSA
lpCaps
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpCaps
,
dwSize
);
if
(
lpCaps
==
NULL
)
return
MMSYSERR_NOTENABLED
;
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
TRACE
(
"MAX_WAVINDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
memcpy
(
lpCaps
,
&
WInDev
[
wDevID
].
caps
,
min
(
dwSize
,
sizeof
(
*
lpCaps
)));
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widRecorder [internal]
*/
static
DWORD
CALLBACK
widRecorder
(
LPVOID
pmt
)
{
WORD
uDevID
=
(
DWORD
)
pmt
;
WINE_WAVEIN
*
wwi
=
(
WINE_WAVEIN
*
)
&
WInDev
[
uDevID
];
WAVEHDR
*
lpWaveHdr
;
DWORD
dwSleepTime
;
MSG
msg
;
DWORD
bytesRead
;
int
fragments
;
int
fragsize
;
int
fragstotal
;
int
bytes
;
int
xs
;
LPVOID
buffer
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
wwi
->
dwFragmentSize
);
LPVOID
pOffset
=
buffer
;
PeekMessageA
(
&
msg
,
0
,
0
,
0
,
0
);
wwi
->
state
=
WINE_WS_STOPPED
;
wwi
->
dwTotalRecorded
=
0
;
SetEvent
(
wwi
->
hEvent
);
/* make sleep time to be # of ms to output a fragment */
dwSleepTime
=
(
wwi
->
dwFragmentSize
*
1000
)
/
wwi
->
format
.
wf
.
nAvgBytesPerSec
;
TRACE
(
"sleeptime=%ld ms
\n
"
,
dwSleepTime
);
for
(;
;
)
{
/* wait for dwSleepTime or an event in thread's queue */
/* FIXME: could improve wait time depending on queue state,
* ie, number of queued fragments
*/
if
(
wwi
->
lpQueuePtr
!=
NULL
&&
wwi
->
state
==
WINE_WS_PLAYING
)
{
lpWaveHdr
=
wwi
->
lpQueuePtr
;
bytes
=
fragsize
=
AudioIORecordingAvailable
();
fragments
=
fragstotal
=
1
;
TRACE
(
"info={frag=%d fsize=%d ftotal=%d bytes=%d}
\n
"
,
fragments
,
fragsize
,
fragstotal
,
bytes
);
/* read all the fragments accumulated so far */
while
((
fragments
>
0
)
&&
(
wwi
->
lpQueuePtr
))
{
fragments
--
;
if
(
lpWaveHdr
->
dwBufferLength
-
lpWaveHdr
->
dwBytesRecorded
>=
wwi
->
dwFragmentSize
)
{
/* directly read fragment in wavehdr */
bytesRead
=
AudioIORead
(
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
,
wwi
->
dwFragmentSize
);
TRACE
(
"bytesRead=%ld (direct)
\n
"
,
bytesRead
);
if
(
bytesRead
!=
(
DWORD
)
-
1
)
{
/* update number of bytes recorded in current buffer and by this device */
lpWaveHdr
->
dwBytesRecorded
+=
bytesRead
;
wwi
->
dwTotalRecorded
+=
bytesRead
;
/* buffer is full. notify client */
if
(
lpWaveHdr
->
dwBytesRecorded
==
lpWaveHdr
->
dwBufferLength
)
{
/* must copy the value of next waveHdr, because we have no idea of what
* will be done with the content of lpWaveHdr in callback
*/
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
if
(
LIBAUDIOIO_NotifyClient
(
uDevID
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
}
lpWaveHdr
=
wwi
->
lpQueuePtr
=
lpNext
;
}
}
}
else
{
/* read the fragment in a local buffer */
bytesRead
=
AudioIORead
(
buffer
,
wwi
->
dwFragmentSize
);
pOffset
=
buffer
;
TRACE
(
"bytesRead=%ld (local)
\n
"
,
bytesRead
);
/* copy data in client buffers */
while
(
bytesRead
!=
(
DWORD
)
-
1
&&
bytesRead
>
0
)
{
DWORD
dwToCopy
=
min
(
bytesRead
,
lpWaveHdr
->
dwBufferLength
-
lpWaveHdr
->
dwBytesRecorded
);
memcpy
(
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
,
pOffset
,
dwToCopy
);
/* update number of bytes recorded in current buffer and by this device */
lpWaveHdr
->
dwBytesRecorded
+=
dwToCopy
;
wwi
->
dwTotalRecorded
+=
dwToCopy
;
bytesRead
-=
dwToCopy
;
pOffset
+=
dwToCopy
;
/* client buffer is full. notify client */
if
(
lpWaveHdr
->
dwBytesRecorded
==
lpWaveHdr
->
dwBufferLength
)
{
/* must copy the value of next waveHdr, because we have no idea of what
* will be done with the content of lpWaveHdr in callback
*/
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
TRACE
(
"lpNext=%p
\n
"
,
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
if
(
LIBAUDIOIO_NotifyClient
(
uDevID
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
}
wwi
->
lpQueuePtr
=
lpWaveHdr
=
lpNext
;
if
(
!
lpNext
&&
bytesRead
)
{
/* no more buffer to copy data to, but we did read more.
* what hasn't been copied will be dropped
*/
WARN
(
"buffer under run! %lu bytes dropped.
\n
"
,
bytesRead
);
wwi
->
lpQueuePtr
=
NULL
;
break
;
}
}
}
}
}
}
MsgWaitForMultipleObjects
(
0
,
NULL
,
FALSE
,
dwSleepTime
,
QS_POSTMESSAGE
);
while
(
PeekMessageA
(
&
msg
,
0
,
WINE_WM_FIRST
,
WINE_WM_LAST
,
PM_REMOVE
))
{
TRACE
(
"msg=0x%x wParam=0x%x lParam=0x%lx
\n
"
,
msg
.
message
,
msg
.
wParam
,
msg
.
lParam
);
switch
(
msg
.
message
)
{
case
WINE_WM_PAUSING
:
wwi
->
state
=
WINE_WS_PAUSED
;
AudioIORecordingPause
();
SetEvent
(
wwi
->
hEvent
);
break
;
case
WINE_WM_RESTARTING
:
{
wwi
->
state
=
WINE_WS_PLAYING
;
if
(
wwi
->
bTriggerSupport
)
{
/* start the recording */
AudioIORecordingResume
();
}
else
{
unsigned
char
data
[
4
];
/* read 4 bytes to start the recording */
AudioIORead
(
data
,
4
);
}
SetEvent
(
wwi
->
hEvent
);
break
;
}
case
WINE_WM_HEADER
:
lpWaveHdr
=
(
LPWAVEHDR
)
msg
.
lParam
;
lpWaveHdr
->
lpNext
=
0
;
/* insert buffer at the end of queue */
{
LPWAVEHDR
*
wh
;
for
(
wh
=
&
(
wwi
->
lpQueuePtr
);
*
wh
;
wh
=
&
((
*
wh
)
->
lpNext
));
*
wh
=
lpWaveHdr
;
}
break
;
case
WINE_WM_RESETTING
:
wwi
->
state
=
WINE_WS_STOPPED
;
/* return all buffers to the app */
for
(
lpWaveHdr
=
wwi
->
lpQueuePtr
;
lpWaveHdr
;
lpWaveHdr
=
lpWaveHdr
->
lpNext
)
{
TRACE
(
"reset %p %p
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
if
(
LIBAUDIOIO_NotifyClient
(
uDevID
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
}
}
wwi
->
lpQueuePtr
=
NULL
;
SetEvent
(
wwi
->
hEvent
);
break
;
case
WINE_WM_CLOSING
:
wwi
->
hThread
=
0
;
wwi
->
state
=
WINE_WS_CLOSED
;
SetEvent
(
wwi
->
hEvent
);
HeapFree
(
GetProcessHeap
(),
0
,
buffer
);
ExitThread
(
0
);
/* shouldn't go here */
default:
FIXME
(
"unknown message %d
\n
"
,
msg
.
message
);
break
;
}
}
}
ExitThread
(
0
);
/* just for not generating compilation warnings... should never be executed */
return
0
;
}
/**************************************************************************
* widOpen [internal]
*/
static
DWORD
widOpen
(
WORD
wDevID
,
LPWAVEOPENDESC
lpDesc
,
DWORD
dwFlags
)
{
int
audio
;
int
fragment_size
;
int
sample_rate
;
int
format
;
int
dsp_stereo
;
WINE_WAVEIN
*
wwi
;
int
audio_fragment
;
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpDesc
,
dwFlags
);
if
(
lpDesc
==
NULL
)
{
WARN
(
"Invalid Parameter !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MMSYSERR_BADDEVICEID
;
/* only PCM format is supported so far... */
if
(
lpDesc
->
lpFormat
->
wFormatTag
!=
WAVE_FORMAT_PCM
||
lpDesc
->
lpFormat
->
nChannels
==
0
||
lpDesc
->
lpFormat
->
nSamplesPerSec
==
0
)
{
WARN
(
"Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
WAVERR_BADFORMAT
;
}
if
(
dwFlags
&
WAVE_FORMAT_QUERY
)
{
TRACE
(
"Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
MMSYSERR_NOERROR
;
}
if
(
access
(
SOUND_DEV
,
0
)
!=
0
)
return
MMSYSERR_NOTENABLED
;
audio
=
AudioIOOpenX
(
O_RDONLY
|
O_NDELAY
,
&
spec
[
RECORD
],
&
spec
[
RECORD
]);
if
(
audio
==
-
1
)
{
WARN
(
"can't open sound device %s (%s)!
\n
"
,
SOUND_DEV
,
strerror
(
errno
));
return
MMSYSERR_ALLOCATED
;
}
fcntl
(
audio
,
F_SETFD
,
1
);
/* set close on exec flag */
wwi
=
&
WInDev
[
wDevID
];
if
(
wwi
->
lpQueuePtr
)
{
WARN
(
"Should have an empty queue (%p)
\n
"
,
wwi
->
lpQueuePtr
);
wwi
->
lpQueuePtr
=
NULL
;
}
wwi
->
unixdev
=
audio
;
wwi
->
dwTotalRecorded
=
0
;
wwi
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
memcpy
(
&
wwi
->
waveDesc
,
lpDesc
,
sizeof
(
WAVEOPENDESC
));
memcpy
(
&
wwi
->
format
,
lpDesc
->
lpFormat
,
sizeof
(
PCMWAVEFORMAT
));
if
(
wwi
->
format
.
wBitsPerSample
==
0
)
{
WARN
(
"Resetting zeroed wBitsPerSample
\n
"
);
wwi
->
format
.
wBitsPerSample
=
8
*
(
wwi
->
format
.
wf
.
nAvgBytesPerSec
/
wwi
->
format
.
wf
.
nSamplesPerSec
)
/
wwi
->
format
.
wf
.
nChannels
;
}
spec
[
RECORD
].
rate
=
sample_rate
=
wwi
->
format
.
wf
.
nSamplesPerSec
;
dsp_stereo
=
((
spec
[
RECORD
].
channels
=
wwi
->
format
.
wf
.
nChannels
)
>
1
)
?
TRUE
:
FALSE
;
spec
[
RECORD
].
precision
=
wwi
->
format
.
wBitsPerSample
;
spec
[
RECORD
].
type
=
(
spec
[
RECORD
].
precision
==
16
)
?
TYPE_SIGNED
:
TYPE_UNSIGNED
;
/* This is actually hand tuned to work so that my SB Live:
* - does not skip
* - does not buffer too much
* when sending with the Shoutcast winamp plugin
*/
/* 7 fragments max, 2^10 = 1024 bytes per fragment */
audio_fragment
=
0x0007000A
;
fragment_size
=
4096
;
if
(
fragment_size
==
-
1
)
{
AudioIOClose
();
wwi
->
unixdev
=
-
1
;
return
MMSYSERR_NOTENABLED
;
}
wwi
->
dwFragmentSize
=
fragment_size
;
TRACE
(
"wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!
\n
"
,
wwi
->
format
.
wBitsPerSample
,
wwi
->
format
.
wf
.
nAvgBytesPerSec
,
wwi
->
format
.
wf
.
nSamplesPerSec
,
wwi
->
format
.
wf
.
nChannels
,
wwi
->
format
.
wf
.
nBlockAlign
);
wwi
->
hEvent
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
wwi
->
hThread
=
CreateThread
(
NULL
,
0
,
widRecorder
,
(
LPVOID
)(
DWORD
)
wDevID
,
0
,
&
(
wwi
->
dwThreadID
));
WaitForSingleObject
(
wwi
->
hEvent
,
INFINITE
);
if
(
LIBAUDIOIO_NotifyClient
(
wDevID
,
WIM_OPEN
,
0L
,
0L
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widClose [internal]
*/
static
DWORD
widClose
(
WORD
wDevID
)
{
WINE_WAVEIN
*
wwi
;
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't close !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
wwi
=
&
WInDev
[
wDevID
];
if
(
wwi
->
lpQueuePtr
!=
NULL
)
{
WARN
(
"still buffers open !
\n
"
);
return
WAVERR_STILLPLAYING
;
}
PostThreadMessageA
(
wwi
->
dwThreadID
,
WINE_WM_CLOSING
,
0
,
0
);
WaitForSingleObject
(
wwi
->
hEvent
,
INFINITE
);
CloseHandle
(
wwi
->
hEvent
);
AudioIOClose
();
wwi
->
unixdev
=
-
1
;
wwi
->
dwFragmentSize
=
0
;
if
(
LIBAUDIOIO_NotifyClient
(
wDevID
,
WIM_CLOSE
,
0L
,
0L
)
!=
MMSYSERR_NOERROR
)
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widAddBuffer [internal]
*/
static
DWORD
widAddBuffer
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't do it !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
!
(
lpWaveHdr
->
dwFlags
&
WHDR_PREPARED
))
{
TRACE
(
"never been prepared !
\n
"
);
return
WAVERR_UNPREPARED
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
{
TRACE
(
"header already in use !
\n
"
);
return
WAVERR_STILLPLAYING
;
}
lpWaveHdr
->
dwFlags
|=
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwBytesRecorded
=
0
;
lpWaveHdr
->
lpNext
=
NULL
;
PostThreadMessageA
(
WInDev
[
wDevID
].
dwThreadID
,
WINE_WM_HEADER
,
0
,
(
DWORD
)
lpWaveHdr
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widPrepare [internal]
*/
static
DWORD
widPrepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MMSYSERR_INVALHANDLE
;
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
|=
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
&=
~
(
WHDR_INQUEUE
|
WHDR_DONE
);
lpWaveHdr
->
dwBytesRecorded
=
0
;
TRACE
(
"header prepared !
\n
"
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widUnprepare [internal]
*/
static
DWORD
widUnprepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MMSYSERR_INVALHANDLE
;
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
&=
~
(
WHDR_PREPARED
|
WHDR_INQUEUE
);
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStart [internal]
*/
static
DWORD
widStart
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't start recording !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
PostThreadMessageA
(
WInDev
[
wDevID
].
dwThreadID
,
WINE_WM_RESTARTING
,
0
,
0
);
WaitForSingleObject
(
WInDev
[
wDevID
].
hEvent
,
INFINITE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStop [internal]
*/
static
DWORD
widStop
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't stop !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
/* FIXME: reset aint stop */
PostThreadMessageA
(
WInDev
[
wDevID
].
dwThreadID
,
WINE_WM_RESETTING
,
0
,
0
);
WaitForSingleObject
(
WInDev
[
wDevID
].
hEvent
,
INFINITE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widReset [internal]
*/
static
DWORD
widReset
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't reset !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
PostThreadMessageA
(
WInDev
[
wDevID
].
dwThreadID
,
WINE_WM_RESETTING
,
0
,
0
);
WaitForSingleObject
(
WInDev
[
wDevID
].
hEvent
,
INFINITE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widGetPosition [internal]
*/
static
DWORD
widGetPosition
(
WORD
wDevID
,
LPMMTIME
lpTime
,
DWORD
uSize
)
{
int
time
;
WINE_WAVEIN
*
wwi
;
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpTime
,
uSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
unixdev
==
-
1
)
{
WARN
(
"can't get pos !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
lpTime
==
NULL
)
return
MMSYSERR_INVALPARAM
;
wwi
=
&
WInDev
[
wDevID
];
TRACE
(
"wType=%04X !
\n
"
,
lpTime
->
wType
);
TRACE
(
"wBitsPerSample=%u
\n
"
,
wwi
->
format
.
wBitsPerSample
);
TRACE
(
"nSamplesPerSec=%lu
\n
"
,
wwi
->
format
.
wf
.
nSamplesPerSec
);
TRACE
(
"nChannels=%u
\n
"
,
wwi
->
format
.
wf
.
nChannels
);
TRACE
(
"nAvgBytesPerSec=%lu
\n
"
,
wwi
->
format
.
wf
.
nAvgBytesPerSec
);
switch
(
lpTime
->
wType
)
{
case
TIME_BYTES
:
lpTime
->
u
.
cb
=
wwi
->
dwTotalRecorded
;
TRACE
(
"TIME_BYTES=%lu
\n
"
,
lpTime
->
u
.
cb
);
break
;
case
TIME_SAMPLES
:
lpTime
->
u
.
sample
=
wwi
->
dwTotalRecorded
*
8
/
wwi
->
format
.
wBitsPerSample
;
TRACE
(
"TIME_SAMPLES=%lu
\n
"
,
lpTime
->
u
.
sample
);
break
;
case
TIME_SMPTE
:
time
=
wwi
->
dwTotalRecorded
/
(
wwi
->
format
.
wf
.
nAvgBytesPerSec
/
1000
);
lpTime
->
u
.
smpte
.
hour
=
time
/
108000
;
time
-=
lpTime
->
u
.
smpte
.
hour
*
108000
;
lpTime
->
u
.
smpte
.
min
=
time
/
1800
;
time
-=
lpTime
->
u
.
smpte
.
min
*
1800
;
lpTime
->
u
.
smpte
.
sec
=
time
/
30
;
time
-=
lpTime
->
u
.
smpte
.
sec
*
30
;
lpTime
->
u
.
smpte
.
frame
=
time
;
lpTime
->
u
.
smpte
.
fps
=
30
;
TRACE
(
"TIME_SMPTE=%02u:%02u:%02u:%02u
\n
"
,
lpTime
->
u
.
smpte
.
hour
,
lpTime
->
u
.
smpte
.
min
,
lpTime
->
u
.
smpte
.
sec
,
lpTime
->
u
.
smpte
.
frame
);
break
;
case
TIME_MS
:
lpTime
->
u
.
ms
=
wwi
->
dwTotalRecorded
/
(
wwi
->
format
.
wf
.
nAvgBytesPerSec
/
1000
);
TRACE
(
"TIME_MS=%lu
\n
"
,
lpTime
->
u
.
ms
);
break
;
default:
FIXME
(
"format not supported (%u) ! use TIME_MS !
\n
"
,
lpTime
->
wType
);
lpTime
->
wType
=
TIME_MS
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widMessage (WINEOSS.6)
*/
DWORD
WINAPI
LIBAUDIOIO_widMessage
(
WORD
wDevID
,
WORD
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"(%u, %04X, %08lX, %08lX, %08lX);
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
DRVM_INIT
:
case
DRVM_EXIT
:
case
DRVM_ENABLE
:
case
DRVM_DISABLE
:
/* FIXME: Pretend this is supported */
return
0
;
case
WIDM_OPEN
:
return
widOpen
(
wDevID
,
(
LPWAVEOPENDESC
)
dwParam1
,
dwParam2
);
case
WIDM_CLOSE
:
return
widClose
(
wDevID
);
case
WIDM_ADDBUFFER
:
return
widAddBuffer
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_PREPARE
:
return
widPrepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_UNPREPARE
:
return
widUnprepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_GETDEVCAPS
:
return
widGetDevCaps
(
wDevID
,
(
LPWAVEINCAPSA
)
dwParam1
,
dwParam2
);
case
WIDM_GETNUMDEVS
:
return
wodGetNumDevs
();
/* same number of devices in output as in input */
case
WIDM_GETPOS
:
return
widGetPosition
(
wDevID
,
(
LPMMTIME
)
dwParam1
,
dwParam2
);
case
WIDM_RESET
:
return
widReset
(
wDevID
);
case
WIDM_START
:
return
widStart
(
wDevID
);
case
WIDM_STOP
:
return
widStop
(
wDevID
);
default:
FIXME
(
"unknown message %u!
\n
"
,
wMsg
);
}
return
MMSYSERR_NOTSUPPORTED
;
}
#else
/* HAVE_LIBAUDIOIO */
/**************************************************************************
* wodMessage (WINEOSS.7)
*/
DWORD
WINAPI
LIBAUDIOIO_wodMessage
(
WORD
wDevID
,
WORD
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
FIXME
(
"(%u, %04X, %08lX, %08lX, %08lX):stub
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
return
MMSYSERR_NOTENABLED
;
}
/**************************************************************************
* widMessage (WINEOSS.6)
*/
DWORD
WINAPI
LIBAUDIOIO_widMessage
(
WORD
wDevID
,
WORD
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
FIXME
(
"(%u, %04X, %08lX, %08lX, %08lX):stub
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
return
MMSYSERR_NOTENABLED
;
}
#endif
/* HAVE_LIBAUDIOIO */
dlls/winmm/wineaudioio/audioio.c
0 → 100644
View file @
2a91e3f9
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* Wine Driver for Libaudioio
* Derived From WineOSS
* Copyright 1999 Eric Pouech
* Modifications by Robert Lunnon 2002
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "mmddk.h"
#ifdef HAVE_LIBAUDIOIO
static
struct
WINE_LIBAUDIOIO
*
audioio
=
NULL
;
extern
LONG
LIBAUDIOIO_WaveInit
(
void
);
extern
BOOL
LIBAUDIOIO_MidiInit
(
void
);
/**************************************************************************
* LIBAUDIOIO_drvOpen [internal]
*/
static
DWORD
LIBAUDIOIO_drvOpen
(
LPSTR
str
)
{
if
(
audioio
)
return
0
;
/* I know, this is ugly, but who cares... */
audioio
=
(
struct
WINE_LIBAUDIOIO
*
)
1
;
return
1
;
}
/**************************************************************************
* LIBAUDIOIO_drvClose [internal]
*/
static
DWORD
LIBAUDIOIO_drvClose
(
DWORD
dwDevID
)
{
if
(
audioio
)
{
audioio
=
NULL
;
return
1
;
}
return
0
;
}
#endif
/**************************************************************************
* DriverProc
*/
LONG
CALLBACK
LIBAUDIOIO_DriverProc
(
DWORD
dwDevID
,
HDRVR
hDriv
,
DWORD
wMsg
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
/* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
/* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
switch
(
wMsg
)
{
#ifdef HAVE_LIBAUDIOIO
case
DRV_LOAD
:
LIBAUDIOIO_WaveInit
();
#ifdef HAVE_LIBAUDIOIO_MIDI
LIBAUDIOIO_MidiInit
();
#endif
return
1
;
case
DRV_FREE
:
return
1
;
case
DRV_OPEN
:
return
LIBAUDIOIO_drvOpen
((
LPSTR
)
dwParam1
);
case
DRV_CLOSE
:
return
LIBAUDIOIO_drvClose
(
dwDevID
);
case
DRV_ENABLE
:
return
1
;
case
DRV_DISABLE
:
return
1
;
case
DRV_QUERYCONFIGURE
:
return
1
;
case
DRV_CONFIGURE
:
MessageBoxA
(
0
,
"Libaudioio MultiMedia Driver !"
,
"Libaudioio Driver"
,
MB_OK
);
return
1
;
case
DRV_INSTALL
:
return
DRVCNF_RESTART
;
case
DRV_REMOVE
:
return
DRVCNF_RESTART
;
#endif
default:
return
DefDriverProc
(
dwDevID
,
hDriv
,
wMsg
,
dwParam1
,
dwParam2
);
}
}
dlls/winmm/wineaudioio/wineaudioio.drv.spec
0 → 100644
View file @
2a91e3f9
@ stdcall DriverProc(long long long long long) LIBAUDIOIO_DriverProc
@ stdcall wodMessage(long long long long long) LIBAUDIOIO_wodMessage
include/config.h.in
View file @
2a91e3f9
...
...
@@ -191,6 +191,12 @@
/* Define to 1 if you have the <jpeglib.h> header file. */
#undef HAVE_JPEGLIB_H
/* Define if you have libaudioIO */
#undef HAVE_LIBAUDIOIO
/* Define to 1 if you have the <libaudioio.h> header file. */
#undef HAVE_LIBAUDIOIO_H
/* Define if you have the curses library (-lcurses) */
#undef HAVE_LIBCURSES
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment