mirror of https://github.com/encounter/SDL.git
Merge audio capture work back into the mainline.
This commit is contained in:
commit
2da1ec8354
|
@ -120,6 +120,7 @@ test/testbounds
|
||||||
test/torturethread
|
test/torturethread
|
||||||
test/testdisplayinfo
|
test/testdisplayinfo
|
||||||
test/testqsort
|
test/testqsort
|
||||||
|
test/testaudiocapture
|
||||||
test/*.exe
|
test/*.exe
|
||||||
test/*.dSYM
|
test/*.dSYM
|
||||||
buildbot
|
buildbot
|
||||||
|
|
2
BUGS.txt
2
BUGS.txt
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Bugs are now managed in the SDL bug tracker, here:
|
Bugs are now managed in the SDL bug tracker, here:
|
||||||
|
|
||||||
http://bugzilla.libsdl.org/
|
https://bugzilla.libsdl.org/
|
||||||
|
|
||||||
You may report bugs there, and search to see if a given issue has already
|
You may report bugs there, and search to see if a given issue has already
|
||||||
been reported, discussed, and maybe even fixed.
|
been reported, discussed, and maybe even fixed.
|
||||||
|
|
|
@ -81,7 +81,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -174,9 +174,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -208,7 +208,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -159,9 +159,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -73,7 +73,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -174,9 +174,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -287,7 +287,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -420,9 +420,6 @@
|
||||||
<ClInclude Include="..\..\include\SDL_clipboard.h">
|
<ClInclude Include="..\..\include\SDL_clipboard.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h">
|
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -81,7 +81,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
<ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
<ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -174,9 +174,6 @@
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -294,7 +294,6 @@
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h" />
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendline.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendline.h" />
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendpoint.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendpoint.h" />
|
||||||
|
|
|
@ -230,7 +230,6 @@
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendfillrect.h" />
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendline.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendline.h" />
|
||||||
<ClInclude Include="..\..\src\render\software\SDL_blendpoint.h" />
|
<ClInclude Include="..\..\src\render\software\SDL_blendpoint.h" />
|
||||||
|
|
|
@ -771,10 +771,6 @@
|
||||||
RelativePath="..\..\src\audio\SDL_audiodev_c.h"
|
RelativePath="..\..\src\audio\SDL_audiodev_c.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\audio\SDL_audiomem.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\audio\SDL_audiotypecvt.c"
|
RelativePath="..\..\src\audio\SDL_audiotypecvt.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -376,7 +376,6 @@
|
||||||
FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audio.c; sourceTree = "<group>"; };
|
FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audio.c; sourceTree = "<group>"; };
|
||||||
FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audio_c.h; sourceTree = "<group>"; };
|
FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audio_c.h; sourceTree = "<group>"; };
|
||||||
FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = "<group>"; };
|
FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = "<group>"; };
|
||||||
FD99B9490DD52EDC00FB1D6B /* SDL_audiomem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiomem.h; sourceTree = "<group>"; };
|
|
||||||
FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = "<group>"; };
|
FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = "<group>"; };
|
||||||
FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = "<group>"; };
|
FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = "<group>"; };
|
||||||
FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = "<group>"; };
|
FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = "<group>"; };
|
||||||
|
@ -795,7 +794,6 @@
|
||||||
FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */,
|
FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */,
|
||||||
FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */,
|
FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */,
|
||||||
FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */,
|
FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */,
|
||||||
FD99B9490DD52EDC00FB1D6B /* SDL_audiomem.h */,
|
|
||||||
FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */,
|
FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */,
|
||||||
FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */,
|
FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */,
|
||||||
FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */,
|
FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */,
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
04BD002812E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; };
|
04BD002812E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; };
|
||||||
04BD002912E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; };
|
04BD002912E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; };
|
||||||
04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
||||||
04BD002B12E6671800899322 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; };
|
|
||||||
04BD002C12E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; };
|
04BD002C12E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; };
|
||||||
04BD002D12E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; };
|
04BD002D12E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; };
|
||||||
04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
||||||
|
@ -218,7 +217,6 @@
|
||||||
04BD024412E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; };
|
04BD024412E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; };
|
||||||
04BD024512E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; };
|
04BD024512E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; };
|
||||||
04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
||||||
04BD024712E6671800899322 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; };
|
|
||||||
04BD024812E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; };
|
04BD024812E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; };
|
||||||
04BD024912E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; };
|
04BD024912E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; };
|
||||||
04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
||||||
|
@ -563,7 +561,6 @@
|
||||||
DB313F7617554B71006C0E22 /* SDL_coreaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDA112E6671700899322 /* SDL_coreaudio.h */; };
|
DB313F7617554B71006C0E22 /* SDL_coreaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDA112E6671700899322 /* SDL_coreaudio.h */; };
|
||||||
DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB512E6671700899322 /* SDL_audio_c.h */; };
|
DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB512E6671700899322 /* SDL_audio_c.h */; };
|
||||||
DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; };
|
||||||
DB313F7917554B71006C0E22 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; };
|
|
||||||
DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; };
|
||||||
DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC412E6671700899322 /* SDL_wave.h */; };
|
DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC412E6671700899322 /* SDL_wave.h */; };
|
||||||
DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDD612E6671700899322 /* blank_cursor.h */; };
|
DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDD612E6671700899322 /* blank_cursor.h */; };
|
||||||
|
@ -864,7 +861,6 @@
|
||||||
04BDFDB612E6671700899322 /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = "<group>"; };
|
04BDFDB612E6671700899322 /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = "<group>"; };
|
||||||
04BDFDB712E6671700899322 /* SDL_audiodev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiodev.c; sourceTree = "<group>"; };
|
04BDFDB712E6671700899322 /* SDL_audiodev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiodev.c; sourceTree = "<group>"; };
|
||||||
04BDFDB812E6671700899322 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiodev_c.h; sourceTree = "<group>"; };
|
04BDFDB812E6671700899322 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiodev_c.h; sourceTree = "<group>"; };
|
||||||
04BDFDB912E6671700899322 /* SDL_audiomem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiomem.h; sourceTree = "<group>"; };
|
|
||||||
04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = "<group>"; };
|
04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = "<group>"; };
|
||||||
04BDFDBB12E6671700899322 /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = "<group>"; };
|
04BDFDBB12E6671700899322 /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = "<group>"; };
|
||||||
04BDFDC212E6671700899322 /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = "<group>"; };
|
04BDFDC212E6671700899322 /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = "<group>"; };
|
||||||
|
@ -1307,7 +1303,6 @@
|
||||||
04BDFDB612E6671700899322 /* SDL_audiocvt.c */,
|
04BDFDB612E6671700899322 /* SDL_audiocvt.c */,
|
||||||
04BDFDB712E6671700899322 /* SDL_audiodev.c */,
|
04BDFDB712E6671700899322 /* SDL_audiodev.c */,
|
||||||
04BDFDB812E6671700899322 /* SDL_audiodev_c.h */,
|
04BDFDB812E6671700899322 /* SDL_audiodev_c.h */,
|
||||||
04BDFDB912E6671700899322 /* SDL_audiomem.h */,
|
|
||||||
04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */,
|
04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */,
|
||||||
04BDFDBB12E6671700899322 /* SDL_mixer.c */,
|
04BDFDBB12E6671700899322 /* SDL_mixer.c */,
|
||||||
04BDFDC212E6671700899322 /* SDL_sysaudio.h */,
|
04BDFDC212E6671700899322 /* SDL_sysaudio.h */,
|
||||||
|
@ -1840,7 +1835,6 @@
|
||||||
04BD001912E6671800899322 /* SDL_coreaudio.h in Headers */,
|
04BD001912E6671800899322 /* SDL_coreaudio.h in Headers */,
|
||||||
04BD002712E6671800899322 /* SDL_audio_c.h in Headers */,
|
04BD002712E6671800899322 /* SDL_audio_c.h in Headers */,
|
||||||
04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */,
|
04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */,
|
||||||
04BD002B12E6671800899322 /* SDL_audiomem.h in Headers */,
|
|
||||||
04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */,
|
04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */,
|
||||||
04BD003612E6671800899322 /* SDL_wave.h in Headers */,
|
04BD003612E6671800899322 /* SDL_wave.h in Headers */,
|
||||||
04BD004212E6671800899322 /* blank_cursor.h in Headers */,
|
04BD004212E6671800899322 /* blank_cursor.h in Headers */,
|
||||||
|
@ -1996,7 +1990,6 @@
|
||||||
04BD024312E6671800899322 /* SDL_audio_c.h in Headers */,
|
04BD024312E6671800899322 /* SDL_audio_c.h in Headers */,
|
||||||
04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */,
|
04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */,
|
||||||
AAC070FD195606770073DCDF /* SDL_opengles2_gl2.h in Headers */,
|
AAC070FD195606770073DCDF /* SDL_opengles2_gl2.h in Headers */,
|
||||||
04BD024712E6671800899322 /* SDL_audiomem.h in Headers */,
|
|
||||||
04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */,
|
04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */,
|
||||||
04BD025212E6671800899322 /* SDL_wave.h in Headers */,
|
04BD025212E6671800899322 /* SDL_wave.h in Headers */,
|
||||||
04BD025D12E6671800899322 /* blank_cursor.h in Headers */,
|
04BD025D12E6671800899322 /* blank_cursor.h in Headers */,
|
||||||
|
@ -2151,7 +2144,6 @@
|
||||||
DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */,
|
DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */,
|
||||||
DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */,
|
DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */,
|
||||||
AAC070FE195606770073DCDF /* SDL_opengles2_gl2.h in Headers */,
|
AAC070FE195606770073DCDF /* SDL_opengles2_gl2.h in Headers */,
|
||||||
DB313F7917554B71006C0E22 /* SDL_audiomem.h in Headers */,
|
|
||||||
DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */,
|
DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */,
|
||||||
DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */,
|
DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */,
|
||||||
DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */,
|
DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */,
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
<!-- Allow writing to external storage -->
|
<!-- Allow writing to external storage -->
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<!-- if you want to capture audio, uncomment this. -->
|
||||||
|
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
|
||||||
|
|
||||||
<!-- Create a Java class extending SDLActivity and place it in a
|
<!-- Create a Java class extending SDLActivity and place it in a
|
||||||
directory under src matching the package, e.g.
|
directory under src matching the package, e.g.
|
||||||
src/com/gamemaker/game/MyGame.java
|
src/com/gamemaker/game/MyGame.java
|
||||||
|
|
|
@ -59,6 +59,7 @@ public class SDLActivity extends Activity {
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
protected static AudioTrack mAudioTrack;
|
protected static AudioTrack mAudioTrack;
|
||||||
|
protected static AudioRecord mAudioRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL before loading the native shared libraries.
|
* This method is called by SDL before loading the native shared libraries.
|
||||||
|
@ -106,6 +107,7 @@ public class SDLActivity extends Activity {
|
||||||
mJoystickHandler = null;
|
mJoystickHandler = null;
|
||||||
mSDLThread = null;
|
mSDLThread = null;
|
||||||
mAudioTrack = null;
|
mAudioTrack = null;
|
||||||
|
mAudioRecord = null;
|
||||||
mExitCalledFromJava = false;
|
mExitCalledFromJava = false;
|
||||||
mBrokenLibraries = false;
|
mBrokenLibraries = false;
|
||||||
mIsPaused = false;
|
mIsPaused = false;
|
||||||
|
@ -544,7 +546,7 @@ public class SDLActivity extends Activity {
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL using JNI.
|
* This method is called by SDL using JNI.
|
||||||
*/
|
*/
|
||||||
public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
||||||
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
||||||
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
||||||
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
||||||
|
@ -623,13 +625,72 @@ public class SDLActivity extends Activity {
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL using JNI.
|
* This method is called by SDL using JNI.
|
||||||
*/
|
*/
|
||||||
public static void audioQuit() {
|
public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
||||||
|
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
||||||
|
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
||||||
|
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
||||||
|
|
||||||
|
Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||||
|
|
||||||
|
// Let the user pick a larger buffer if they really want -- but ye
|
||||||
|
// gods they probably shouldn't, the minimums are horrifyingly high
|
||||||
|
// latency already
|
||||||
|
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
||||||
|
|
||||||
|
if (mAudioRecord == null) {
|
||||||
|
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
|
||||||
|
channelConfig, audioFormat, desiredFrames * frameSize);
|
||||||
|
|
||||||
|
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
|
||||||
|
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
|
||||||
|
Log.e(TAG, "Failed during initialization of AudioRecord");
|
||||||
|
mAudioRecord.release();
|
||||||
|
mAudioRecord = null;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAudioRecord.startRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This method is called by SDL using JNI. */
|
||||||
|
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
|
||||||
|
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
||||||
|
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||||
|
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This method is called by SDL using JNI. */
|
||||||
|
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
|
||||||
|
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
||||||
|
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||||
|
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** This method is called by SDL using JNI. */
|
||||||
|
public static void audioClose() {
|
||||||
if (mAudioTrack != null) {
|
if (mAudioTrack != null) {
|
||||||
mAudioTrack.stop();
|
mAudioTrack.stop();
|
||||||
|
mAudioTrack.release();
|
||||||
mAudioTrack = null;
|
mAudioTrack = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This method is called by SDL using JNI. */
|
||||||
|
public static void captureClose() {
|
||||||
|
if (mAudioRecord != null) {
|
||||||
|
mAudioRecord.stop();
|
||||||
|
mAudioRecord.release();
|
||||||
|
mAudioRecord = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -278,7 +278,8 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
|
||||||
* protect data structures that it accesses by calling SDL_LockAudio()
|
* protect data structures that it accesses by calling SDL_LockAudio()
|
||||||
* and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL
|
* and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL
|
||||||
* pointer here, and call SDL_QueueAudio() with some frequency, to queue
|
* pointer here, and call SDL_QueueAudio() with some frequency, to queue
|
||||||
* more audio samples to be played.
|
* more audio samples to be played (or for capture devices, call
|
||||||
|
* SDL_DequeueAudio() with some frequency, to obtain audio samples).
|
||||||
* - \c desired->userdata is passed as the first parameter to your callback
|
* - \c desired->userdata is passed as the first parameter to your callback
|
||||||
* function. If you passed a NULL callback, this value is ignored.
|
* function. If you passed a NULL callback, this value is ignored.
|
||||||
*
|
*
|
||||||
|
@ -482,6 +483,10 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
|
||||||
/**
|
/**
|
||||||
* Queue more audio on non-callback devices.
|
* Queue more audio on non-callback devices.
|
||||||
*
|
*
|
||||||
|
* (If you are looking to retrieve queued audio from a non-callback capture
|
||||||
|
* device, you want SDL_DequeueAudio() instead. This will return -1 to
|
||||||
|
* signify an error if you use it with capture devices.)
|
||||||
|
*
|
||||||
* SDL offers two ways to feed audio to the device: you can either supply a
|
* SDL offers two ways to feed audio to the device: you can either supply a
|
||||||
* callback that SDL triggers with some frequency to obtain more audio
|
* callback that SDL triggers with some frequency to obtain more audio
|
||||||
* (pull method), or you can supply no callback, and then SDL will expect
|
* (pull method), or you can supply no callback, and then SDL will expect
|
||||||
|
@ -516,21 +521,76 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len);
|
extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dequeue more audio on non-callback devices.
|
||||||
|
*
|
||||||
|
* (If you are looking to queue audio for output on a non-callback playback
|
||||||
|
* device, you want SDL_QueueAudio() instead. This will always return 0
|
||||||
|
* if you use it with playback devices.)
|
||||||
|
*
|
||||||
|
* SDL offers two ways to retrieve audio from a capture device: you can
|
||||||
|
* either supply a callback that SDL triggers with some frequency as the
|
||||||
|
* device records more audio data, (push method), or you can supply no
|
||||||
|
* callback, and then SDL will expect you to retrieve data at regular
|
||||||
|
* intervals (pull method) with this function.
|
||||||
|
*
|
||||||
|
* There are no limits on the amount of data you can queue, short of
|
||||||
|
* exhaustion of address space. Data from the device will keep queuing as
|
||||||
|
* necessary without further intervention from you. This means you will
|
||||||
|
* eventually run out of memory if you aren't routinely dequeueing data.
|
||||||
|
*
|
||||||
|
* Capture devices will not queue data when paused; if you are expecting
|
||||||
|
* to not need captured audio for some length of time, use
|
||||||
|
* SDL_PauseAudioDevice() to stop the capture device from queueing more
|
||||||
|
* data. This can be useful during, say, level loading times. When
|
||||||
|
* unpaused, capture devices will start queueing data from that point,
|
||||||
|
* having flushed any capturable data available while paused.
|
||||||
|
*
|
||||||
|
* This function is thread-safe, but dequeueing from the same device from
|
||||||
|
* two threads at once does not promise which thread will dequeued data
|
||||||
|
* first.
|
||||||
|
*
|
||||||
|
* You may not dequeue audio from a device that is using an
|
||||||
|
* application-supplied callback; doing so returns an error. You have to use
|
||||||
|
* the audio callback, or dequeue audio with this function, but not both.
|
||||||
|
*
|
||||||
|
* You should not call SDL_LockAudio() on the device before queueing; SDL
|
||||||
|
* handles locking internally for this function.
|
||||||
|
*
|
||||||
|
* \param dev The device ID from which we will dequeue audio.
|
||||||
|
* \param data A pointer into where audio data should be copied.
|
||||||
|
* \param len The number of bytes (not samples!) to which (data) points.
|
||||||
|
* \return number of bytes dequeued, which could be less than requested.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetQueuedAudioSize
|
||||||
|
* \sa SDL_ClearQueuedAudio
|
||||||
|
*/
|
||||||
|
extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of bytes of still-queued audio.
|
* Get the number of bytes of still-queued audio.
|
||||||
*
|
*
|
||||||
* This is the number of bytes that have been queued for playback with
|
* For playback device:
|
||||||
* SDL_QueueAudio(), but have not yet been sent to the hardware.
|
|
||||||
*
|
*
|
||||||
* Once we've sent it to the hardware, this function can not decide the exact
|
* This is the number of bytes that have been queued for playback with
|
||||||
* byte boundary of what has been played. It's possible that we just gave the
|
* SDL_QueueAudio(), but have not yet been sent to the hardware. This
|
||||||
* hardware several kilobytes right before you called this function, but it
|
* number may shrink at any time, so this only informs of pending data.
|
||||||
* hasn't played any of it yet, or maybe half of it, etc.
|
*
|
||||||
|
* Once we've sent it to the hardware, this function can not decide the
|
||||||
|
* exact byte boundary of what has been played. It's possible that we just
|
||||||
|
* gave the hardware several kilobytes right before you called this
|
||||||
|
* function, but it hasn't played any of it yet, or maybe half of it, etc.
|
||||||
|
*
|
||||||
|
* For capture devices:
|
||||||
|
*
|
||||||
|
* This is the number of bytes that have been captured by the device and
|
||||||
|
* are waiting for you to dequeue. This number may grow at any time, so
|
||||||
|
* this only informs of the lower-bound of available data.
|
||||||
*
|
*
|
||||||
* You may not queue audio on a device that is using an application-supplied
|
* You may not queue audio on a device that is using an application-supplied
|
||||||
* callback; calling this function on such a device always returns 0.
|
* callback; calling this function on such a device always returns 0.
|
||||||
* You have to use the audio callback or queue audio with SDL_QueueAudio(),
|
* You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use
|
||||||
* but not both.
|
* the audio callback, but not both.
|
||||||
*
|
*
|
||||||
* You should not call SDL_LockAudio() on the device before querying; SDL
|
* You should not call SDL_LockAudio() on the device before querying; SDL
|
||||||
* handles locking internally for this function.
|
* handles locking internally for this function.
|
||||||
|
@ -544,10 +604,17 @@ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *da
|
||||||
extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
|
extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drop any queued audio data waiting to be sent to the hardware.
|
* Drop any queued audio data. For playback devices, this is any queued data
|
||||||
|
* still waiting to be submitted to the hardware. For capture devices, this
|
||||||
|
* is any data that was queued by the device that hasn't yet been dequeued by
|
||||||
|
* the application.
|
||||||
*
|
*
|
||||||
* Immediately after this call, SDL_GetQueuedAudioSize() will return 0 and
|
* Immediately after this call, SDL_GetQueuedAudioSize() will return 0. For
|
||||||
* the hardware will start playing silence if more audio isn't queued.
|
* playback devices, the hardware will start playing silence if more audio
|
||||||
|
* isn't queued. Unpaused capture devices will start filling the queue again
|
||||||
|
* as soon as they have more data available (which, depending on the state
|
||||||
|
* of the hardware and the thread, could be before this function call
|
||||||
|
* returns!).
|
||||||
*
|
*
|
||||||
* This will not prevent playback of queued audio that's already been sent
|
* This will not prevent playback of queued audio that's already been sent
|
||||||
* to the hardware, as we can not undo that, so expect there to be some
|
* to the hardware, as we can not undo that, so expect there to be some
|
||||||
|
@ -557,8 +624,8 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
|
||||||
*
|
*
|
||||||
* You may not queue audio on a device that is using an application-supplied
|
* You may not queue audio on a device that is using an application-supplied
|
||||||
* callback; calling this function on such a device is always a no-op.
|
* callback; calling this function on such a device is always a no-op.
|
||||||
* You have to use the audio callback or queue audio with SDL_QueueAudio(),
|
* You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use
|
||||||
* but not both.
|
* the audio callback, but not both.
|
||||||
*
|
*
|
||||||
* You should not call SDL_LockAudio() on the device before clearing the
|
* You should not call SDL_LockAudio() on the device before clearing the
|
||||||
* queue; SDL handles locking internally for this function.
|
* queue; SDL handles locking internally for this function.
|
||||||
|
|
|
@ -418,10 +418,6 @@
|
||||||
RelativePath="..\..\..\..\src\audio\SDL_audiodev_c.h"
|
RelativePath="..\..\..\..\src\audio\SDL_audiodev_c.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\..\src\audio\SDL_audiomem.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\..\src\audio\SDL_audiotypecvt.c"
|
RelativePath="..\..\..\..\src\audio\SDL_audiotypecvt.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -113,7 +113,6 @@
|
||||||
<ClInclude Include="..\..\..\..\src\SDL_assert_c.h" />
|
<ClInclude Include="..\..\..\..\src\SDL_assert_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\SDL_error_c.h" />
|
<ClInclude Include="..\..\..\..\src\SDL_error_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -123,9 +123,6 @@
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>src\audio</Filter>
|
<Filter>src\audio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>src\audio</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>src\audio</Filter>
|
<Filter>src\audio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -115,7 +115,6 @@
|
||||||
<ClInclude Include="..\..\..\..\src\SDL_assert_c.h" />
|
<ClInclude Include="..\..\..\..\src\SDL_assert_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\SDL_error_c.h" />
|
<ClInclude Include="..\..\..\..\src\SDL_error_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiomem.h" />
|
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_sysaudio.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_sysaudio.h" />
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_wave.h" />
|
<ClInclude Include="..\..\..\..\src\audio\SDL_wave.h" />
|
||||||
|
|
|
@ -123,9 +123,6 @@
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h">
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audiodev_c.h">
|
||||||
<Filter>src\audio</Filter>
|
<Filter>src\audio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audiomem.h">
|
|
||||||
<Filter>src\audio</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h">
|
<ClInclude Include="..\..\..\..\src\audio\SDL_audio_c.h">
|
||||||
<Filter>src\audio</Filter>
|
<Filter>src\audio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -127,7 +127,6 @@
|
||||||
4DBB70D75469728B342373E8 /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
4DBB70D75469728B342373E8 /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
||||||
48886D482B5239D2429E422D /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
48886D482B5239D2429E422D /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
||||||
227E138737440F101016545F /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
227E138737440F101016545F /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
||||||
5C3C744F22823D470BED10D6 /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../src/audio/SDL_audiomem.h"; sourceTree = "<group>"; };
|
|
||||||
0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
||||||
77537CFB490A3599736F3830 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
77537CFB490A3599736F3830 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
||||||
591062475F93492D625F7D3B /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
591062475F93492D625F7D3B /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
||||||
|
@ -369,7 +368,6 @@
|
||||||
4DBB70D75469728B342373E8 /* SDL_audiocvt.c */,
|
4DBB70D75469728B342373E8 /* SDL_audiocvt.c */,
|
||||||
48886D482B5239D2429E422D /* SDL_audiodev.c */,
|
48886D482B5239D2429E422D /* SDL_audiodev.c */,
|
||||||
227E138737440F101016545F /* SDL_audiodev_c.h */,
|
227E138737440F101016545F /* SDL_audiodev_c.h */,
|
||||||
5C3C744F22823D470BED10D6 /* SDL_audiomem.h */,
|
|
||||||
0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */,
|
0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */,
|
||||||
77537CFB490A3599736F3830 /* SDL_mixer.c */,
|
77537CFB490A3599736F3830 /* SDL_mixer.c */,
|
||||||
591062475F93492D625F7D3B /* SDL_sysaudio.h */,
|
591062475F93492D625F7D3B /* SDL_sysaudio.h */,
|
||||||
|
|
|
@ -146,7 +146,6 @@
|
||||||
2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
||||||
5D2936CF698D392735D76E9E /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
5D2936CF698D392735D76E9E /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
||||||
1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
||||||
14AA3D784A5D4B873D657338 /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../../src/audio/SDL_audiomem.h"; sourceTree = "<group>"; };
|
|
||||||
76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
||||||
748562A8151756FF3FE91679 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
748562A8151756FF3FE91679 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
||||||
7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
||||||
|
@ -425,7 +424,6 @@
|
||||||
2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */,
|
2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */,
|
||||||
5D2936CF698D392735D76E9E /* SDL_audiodev.c */,
|
5D2936CF698D392735D76E9E /* SDL_audiodev.c */,
|
||||||
1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */,
|
1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */,
|
||||||
14AA3D784A5D4B873D657338 /* SDL_audiomem.h */,
|
|
||||||
76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */,
|
76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */,
|
||||||
748562A8151756FF3FE91679 /* SDL_mixer.c */,
|
748562A8151756FF3FE91679 /* SDL_mixer.c */,
|
||||||
7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */,
|
7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */,
|
||||||
|
|
|
@ -146,7 +146,6 @@
|
||||||
07B907294E82663A7E91738C /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
07B907294E82663A7E91738C /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = "<group>"; };
|
||||||
5AAD4B726237251050431873 /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
5AAD4B726237251050431873 /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = "<group>"; };
|
||||||
15895798549516351860492E /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
15895798549516351860492E /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = "<group>"; };
|
||||||
0D3062CE47BF5D5934AB598D /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../../src/audio/SDL_audiomem.h"; sourceTree = "<group>"; };
|
|
||||||
5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = "<group>"; };
|
||||||
2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = "<group>"; };
|
||||||
09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = "<group>"; };
|
||||||
|
@ -425,7 +424,6 @@
|
||||||
07B907294E82663A7E91738C /* SDL_audiocvt.c */,
|
07B907294E82663A7E91738C /* SDL_audiocvt.c */,
|
||||||
5AAD4B726237251050431873 /* SDL_audiodev.c */,
|
5AAD4B726237251050431873 /* SDL_audiodev.c */,
|
||||||
15895798549516351860492E /* SDL_audiodev_c.h */,
|
15895798549516351860492E /* SDL_audiodev_c.h */,
|
||||||
0D3062CE47BF5D5934AB598D /* SDL_audiomem.h */,
|
|
||||||
5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */,
|
5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */,
|
||||||
2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */,
|
2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */,
|
||||||
09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */,
|
09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */,
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_audio_c.h"
|
#include "SDL_audio_c.h"
|
||||||
#include "SDL_audiomem.h"
|
|
||||||
#include "SDL_sysaudio.h"
|
#include "SDL_sysaudio.h"
|
||||||
#include "../thread/SDL_systhread.h"
|
#include "../thread/SDL_systhread.h"
|
||||||
|
|
||||||
|
@ -34,25 +33,21 @@
|
||||||
static SDL_AudioDriver current_audio;
|
static SDL_AudioDriver current_audio;
|
||||||
static SDL_AudioDevice *open_devices[16];
|
static SDL_AudioDevice *open_devices[16];
|
||||||
|
|
||||||
/* !!! FIXME: These are wordy and unlocalized... */
|
|
||||||
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
|
|
||||||
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not all of these will be compiled and linked in, but it's convenient
|
* Not all of these will be compiled and linked in, but it's convenient
|
||||||
* to have a complete list here and saves yet-another block of #ifdefs...
|
* to have a complete list here and saves yet-another block of #ifdefs...
|
||||||
* Please see bootstrap[], below, for the actual #ifdef mess.
|
* Please see bootstrap[], below, for the actual #ifdef mess.
|
||||||
*/
|
*/
|
||||||
|
extern AudioBootStrap PULSEAUDIO_bootstrap;
|
||||||
|
extern AudioBootStrap ALSA_bootstrap;
|
||||||
|
extern AudioBootStrap SNDIO_bootstrap;
|
||||||
extern AudioBootStrap BSD_AUDIO_bootstrap;
|
extern AudioBootStrap BSD_AUDIO_bootstrap;
|
||||||
extern AudioBootStrap DSP_bootstrap;
|
extern AudioBootStrap DSP_bootstrap;
|
||||||
extern AudioBootStrap ALSA_bootstrap;
|
|
||||||
extern AudioBootStrap PULSEAUDIO_bootstrap;
|
|
||||||
extern AudioBootStrap QSAAUDIO_bootstrap;
|
extern AudioBootStrap QSAAUDIO_bootstrap;
|
||||||
extern AudioBootStrap SUNAUDIO_bootstrap;
|
extern AudioBootStrap SUNAUDIO_bootstrap;
|
||||||
extern AudioBootStrap ARTS_bootstrap;
|
extern AudioBootStrap ARTS_bootstrap;
|
||||||
extern AudioBootStrap ESD_bootstrap;
|
extern AudioBootStrap ESD_bootstrap;
|
||||||
extern AudioBootStrap NACLAUD_bootstrap;
|
extern AudioBootStrap NACLAUDIO_bootstrap;
|
||||||
extern AudioBootStrap NAS_bootstrap;
|
extern AudioBootStrap NAS_bootstrap;
|
||||||
extern AudioBootStrap XAUDIO2_bootstrap;
|
extern AudioBootStrap XAUDIO2_bootstrap;
|
||||||
extern AudioBootStrap DSOUND_bootstrap;
|
extern AudioBootStrap DSOUND_bootstrap;
|
||||||
|
@ -60,18 +55,13 @@ extern AudioBootStrap WINMM_bootstrap;
|
||||||
extern AudioBootStrap PAUDIO_bootstrap;
|
extern AudioBootStrap PAUDIO_bootstrap;
|
||||||
extern AudioBootStrap HAIKUAUDIO_bootstrap;
|
extern AudioBootStrap HAIKUAUDIO_bootstrap;
|
||||||
extern AudioBootStrap COREAUDIO_bootstrap;
|
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||||
extern AudioBootStrap SNDMGR_bootstrap;
|
extern AudioBootStrap DISKAUDIO_bootstrap;
|
||||||
extern AudioBootStrap DISKAUD_bootstrap;
|
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
||||||
extern AudioBootStrap DUMMYAUD_bootstrap;
|
|
||||||
extern AudioBootStrap DCAUD_bootstrap;
|
|
||||||
extern AudioBootStrap DART_bootstrap;
|
|
||||||
extern AudioBootStrap NDSAUD_bootstrap;
|
|
||||||
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
||||||
extern AudioBootStrap ANDROIDAUD_bootstrap;
|
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||||
extern AudioBootStrap PSPAUD_bootstrap;
|
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||||
extern AudioBootStrap SNDIO_bootstrap;
|
extern AudioBootStrap SNDIO_bootstrap;
|
||||||
extern AudioBootStrap EmscriptenAudio_bootstrap;
|
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||||
|
|
||||||
|
|
||||||
/* Available audio drivers */
|
/* Available audio drivers */
|
||||||
static const AudioBootStrap *const bootstrap[] = {
|
static const AudioBootStrap *const bootstrap[] = {
|
||||||
|
@ -103,7 +93,7 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
&ESD_bootstrap,
|
&ESD_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_NACL
|
#if SDL_AUDIO_DRIVER_NACL
|
||||||
&NACLAUD_bootstrap,
|
&NACLAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_NAS
|
#if SDL_AUDIO_DRIVER_NAS
|
||||||
&NAS_bootstrap,
|
&NAS_bootstrap,
|
||||||
|
@ -127,22 +117,22 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
&COREAUDIO_bootstrap,
|
&COREAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_DISK
|
#if SDL_AUDIO_DRIVER_DISK
|
||||||
&DISKAUD_bootstrap,
|
&DISKAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_DUMMY
|
#if SDL_AUDIO_DRIVER_DUMMY
|
||||||
&DUMMYAUD_bootstrap,
|
&DUMMYAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_FUSIONSOUND
|
#if SDL_AUDIO_DRIVER_FUSIONSOUND
|
||||||
&FUSIONSOUND_bootstrap,
|
&FUSIONSOUND_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_ANDROID
|
#if SDL_AUDIO_DRIVER_ANDROID
|
||||||
&ANDROIDAUD_bootstrap,
|
&ANDROIDAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_PSP
|
#if SDL_AUDIO_DRIVER_PSP
|
||||||
&PSPAUD_bootstrap,
|
&PSPAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||||
&EmscriptenAudio_bootstrap,
|
&EMSCRIPTENAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -166,7 +156,7 @@ SDL_AudioDetectDevices_Default(void)
|
||||||
{
|
{
|
||||||
/* you have to write your own implementation if these assertions fail. */
|
/* you have to write your own implementation if these assertions fail. */
|
||||||
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
|
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
|
||||||
SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport);
|
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
|
||||||
|
|
||||||
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
|
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
|
||||||
if (current_audio.impl.HasCaptureSupport) {
|
if (current_audio.impl.HasCaptureSupport) {
|
||||||
|
@ -206,6 +196,17 @@ SDL_AudioWaitDone_Default(_THIS)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
return -1; /* just fail immediately. */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SDL_AudioFlushCapture_Default(_THIS)
|
||||||
|
{ /* no-op. */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SDL_AudioCloseDevice_Default(_THIS)
|
SDL_AudioCloseDevice_Default(_THIS)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
|
@ -279,6 +280,8 @@ finalize_audio_entry_points(void)
|
||||||
FILL_STUB(GetPendingBytes);
|
FILL_STUB(GetPendingBytes);
|
||||||
FILL_STUB(GetDeviceBuf);
|
FILL_STUB(GetDeviceBuf);
|
||||||
FILL_STUB(WaitDone);
|
FILL_STUB(WaitDone);
|
||||||
|
FILL_STUB(CaptureFromDevice);
|
||||||
|
FILL_STUB(FlushCapture);
|
||||||
FILL_STUB(CloseDevice);
|
FILL_STUB(CloseDevice);
|
||||||
FILL_STUB(LockDevice);
|
FILL_STUB(LockDevice);
|
||||||
FILL_STUB(UnlockDevice);
|
FILL_STUB(UnlockDevice);
|
||||||
|
@ -317,7 +320,7 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
|
||||||
static SDL_INLINE int
|
static SDL_INLINE int
|
||||||
add_capture_device(const char *name, void *handle)
|
add_capture_device(const char *name, void *handle)
|
||||||
{
|
{
|
||||||
/* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
|
SDL_assert(current_audio.impl.HasCaptureSupport);
|
||||||
return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
|
return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,14 +369,14 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||||
{
|
{
|
||||||
SDL_assert(get_audio_device(device->id) == device);
|
SDL_assert(get_audio_device(device->id) == device);
|
||||||
|
|
||||||
if (!device->enabled) {
|
if (!SDL_AtomicGet(&device->enabled)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ends the audio callback and mark the device as STOPPED, but the
|
/* Ends the audio callback and mark the device as STOPPED, but the
|
||||||
app still needs to close the device to free resources. */
|
app still needs to close the device to free resources. */
|
||||||
current_audio.impl.LockDevice(device);
|
current_audio.impl.LockDevice(device);
|
||||||
device->enabled = 0;
|
SDL_AtomicSet(&device->enabled, 0);
|
||||||
current_audio.impl.UnlockDevice(device);
|
current_audio.impl.UnlockDevice(device);
|
||||||
|
|
||||||
/* Post the event, if desired */
|
/* Post the event, if desired */
|
||||||
|
@ -421,77 +424,24 @@ SDL_RemoveAudioDevice(const int iscapture, void *handle)
|
||||||
|
|
||||||
/* this expects that you managed thread safety elsewhere. */
|
/* this expects that you managed thread safety elsewhere. */
|
||||||
static void
|
static void
|
||||||
free_audio_queue(SDL_AudioBufferQueue *buffer)
|
free_audio_queue(SDL_AudioBufferQueue *packet)
|
||||||
{
|
{
|
||||||
while (buffer) {
|
while (packet) {
|
||||||
SDL_AudioBufferQueue *next = buffer->next;
|
SDL_AudioBufferQueue *next = packet->next;
|
||||||
SDL_free(buffer);
|
SDL_free(packet);
|
||||||
buffer = next;
|
packet = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL
|
/* NOTE: This assumes you'll hold the mixer lock before calling! */
|
||||||
SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int _len)
|
static int
|
||||||
|
queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len)
|
||||||
{
|
{
|
||||||
/* this function always holds the mixer lock before being called. */
|
|
||||||
Uint32 len = (Uint32) _len;
|
|
||||||
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
|
|
||||||
SDL_AudioBufferQueue *buffer;
|
|
||||||
|
|
||||||
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
|
|
||||||
SDL_assert(_len >= 0); /* this shouldn't ever happen, right?! */
|
|
||||||
|
|
||||||
while ((len > 0) && ((buffer = device->buffer_queue_head) != NULL)) {
|
|
||||||
const Uint32 avail = buffer->datalen - buffer->startpos;
|
|
||||||
const Uint32 cpy = SDL_min(len, avail);
|
|
||||||
SDL_assert(device->queued_bytes >= avail);
|
|
||||||
|
|
||||||
SDL_memcpy(stream, buffer->data + buffer->startpos, cpy);
|
|
||||||
buffer->startpos += cpy;
|
|
||||||
stream += cpy;
|
|
||||||
device->queued_bytes -= cpy;
|
|
||||||
len -= cpy;
|
|
||||||
|
|
||||||
if (buffer->startpos == buffer->datalen) { /* packet is done, put it in the pool. */
|
|
||||||
device->buffer_queue_head = buffer->next;
|
|
||||||
SDL_assert((buffer->next != NULL) || (buffer == device->buffer_queue_tail));
|
|
||||||
buffer->next = device->buffer_queue_pool;
|
|
||||||
device->buffer_queue_pool = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
|
|
||||||
|
|
||||||
if (len > 0) { /* fill any remaining space in the stream with silence. */
|
|
||||||
SDL_assert(device->buffer_queue_head == NULL);
|
|
||||||
SDL_memset(stream, device->spec.silence, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->buffer_queue_head == NULL) {
|
|
||||||
device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
|
|
||||||
{
|
|
||||||
SDL_AudioDevice *device = get_audio_device(devid);
|
|
||||||
const Uint8 *data = (const Uint8 *) _data;
|
|
||||||
SDL_AudioBufferQueue *orighead;
|
SDL_AudioBufferQueue *orighead;
|
||||||
SDL_AudioBufferQueue *origtail;
|
SDL_AudioBufferQueue *origtail;
|
||||||
Uint32 origlen;
|
Uint32 origlen;
|
||||||
Uint32 datalen;
|
Uint32 datalen;
|
||||||
|
|
||||||
if (!device) {
|
|
||||||
return -1; /* get_audio_device() will have set the error state */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->spec.callback != SDL_BufferQueueDrainCallback) {
|
|
||||||
return SDL_SetError("Audio device has a callback, queueing not allowed");
|
|
||||||
}
|
|
||||||
|
|
||||||
current_audio.impl.LockDevice(device);
|
|
||||||
|
|
||||||
orighead = device->buffer_queue_head;
|
orighead = device->buffer_queue_head;
|
||||||
origtail = device->buffer_queue_tail;
|
origtail = device->buffer_queue_tail;
|
||||||
origlen = origtail ? origtail->datalen : 0;
|
origlen = origtail ? origtail->datalen : 0;
|
||||||
|
@ -521,8 +471,6 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
|
||||||
device->buffer_queue_tail = origtail;
|
device->buffer_queue_tail = origtail;
|
||||||
device->buffer_queue_pool = NULL;
|
device->buffer_queue_pool = NULL;
|
||||||
|
|
||||||
current_audio.impl.UnlockDevice(device);
|
|
||||||
|
|
||||||
free_audio_queue(packet); /* give back what we can. */
|
free_audio_queue(packet); /* give back what we can. */
|
||||||
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
|
@ -549,22 +497,142 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
|
||||||
device->queued_bytes += datalen;
|
device->queued_bytes += datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_audio.impl.UnlockDevice(device);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NOTE: This assumes you'll hold the mixer lock before calling! */
|
||||||
|
static Uint32
|
||||||
|
dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len)
|
||||||
|
{
|
||||||
|
SDL_AudioBufferQueue *packet;
|
||||||
|
Uint8 *ptr = stream;
|
||||||
|
|
||||||
|
while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) {
|
||||||
|
const Uint32 avail = packet->datalen - packet->startpos;
|
||||||
|
const Uint32 cpy = SDL_min(len, avail);
|
||||||
|
SDL_assert(device->queued_bytes >= avail);
|
||||||
|
|
||||||
|
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||||
|
packet->startpos += cpy;
|
||||||
|
ptr += cpy;
|
||||||
|
device->queued_bytes -= cpy;
|
||||||
|
len -= cpy;
|
||||||
|
|
||||||
|
if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
|
||||||
|
device->buffer_queue_head = packet->next;
|
||||||
|
SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail));
|
||||||
|
packet->next = device->buffer_queue_pool;
|
||||||
|
device->buffer_queue_pool = packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
|
||||||
|
|
||||||
|
if (device->buffer_queue_head == NULL) {
|
||||||
|
device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Uint32) (ptr - stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SDLCALL
|
||||||
|
SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
|
||||||
|
{
|
||||||
|
/* this function always holds the mixer lock before being called. */
|
||||||
|
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
|
||||||
|
Uint32 written;
|
||||||
|
|
||||||
|
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
|
||||||
|
SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */
|
||||||
|
SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
|
||||||
|
|
||||||
|
written = dequeue_audio_from_device(device, stream, (Uint32) len);
|
||||||
|
stream += written;
|
||||||
|
len -= (int) written;
|
||||||
|
|
||||||
|
if (len > 0) { /* fill any remaining space in the stream with silence. */
|
||||||
|
SDL_assert(device->buffer_queue_head == NULL);
|
||||||
|
SDL_memset(stream, device->spec.silence, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SDLCALL
|
||||||
|
SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len)
|
||||||
|
{
|
||||||
|
/* this function always holds the mixer lock before being called. */
|
||||||
|
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
|
||||||
|
|
||||||
|
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
|
||||||
|
SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */
|
||||||
|
SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
|
||||||
|
|
||||||
|
/* note that if this needs to allocate more space and run out of memory,
|
||||||
|
we have no choice but to quietly drop the data and hope it works out
|
||||||
|
later, but you probably have bigger problems in this case anyhow. */
|
||||||
|
queue_audio_to_device(device, stream, (Uint32) len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len)
|
||||||
|
{
|
||||||
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
return -1; /* get_audio_device() will have set the error state */
|
||||||
|
} else if (device->iscapture) {
|
||||||
|
return SDL_SetError("This is a capture device, queueing not allowed");
|
||||||
|
} else if (device->spec.callback != SDL_BufferQueueDrainCallback) {
|
||||||
|
return SDL_SetError("Audio device has a callback, queueing not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
current_audio.impl.LockDevice(device);
|
||||||
|
rc = queue_audio_to_device(device, data, len);
|
||||||
|
current_audio.impl.UnlockDevice(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32
|
||||||
|
SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len)
|
||||||
|
{
|
||||||
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
|
Uint32 rc;
|
||||||
|
|
||||||
|
if ( (len == 0) || /* nothing to do? */
|
||||||
|
(!device) || /* called with bogus device id */
|
||||||
|
(!device->iscapture) || /* playback devices can't dequeue */
|
||||||
|
(device->spec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
|
||||||
|
return 0; /* just report zero bytes dequeued. */
|
||||||
|
}
|
||||||
|
|
||||||
|
current_audio.impl.LockDevice(device);
|
||||||
|
rc = dequeue_audio_from_device(device, data, len);
|
||||||
|
current_audio.impl.UnlockDevice(device);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
Uint32
|
Uint32
|
||||||
SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
|
SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
|
||||||
{
|
{
|
||||||
Uint32 retval = 0;
|
Uint32 retval = 0;
|
||||||
SDL_AudioDevice *device = get_audio_device(devid);
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Nothing to do unless we're set up for queueing. */
|
/* Nothing to do unless we're set up for queueing. */
|
||||||
if (device && (device->spec.callback == SDL_BufferQueueDrainCallback)) {
|
if (device->spec.callback == SDL_BufferQueueDrainCallback) {
|
||||||
current_audio.impl.LockDevice(device);
|
current_audio.impl.LockDevice(device);
|
||||||
retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device);
|
retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device);
|
||||||
current_audio.impl.UnlockDevice(device);
|
current_audio.impl.UnlockDevice(device);
|
||||||
|
} else if (device->spec.callback == SDL_BufferQueueFillCallback) {
|
||||||
|
current_audio.impl.LockDevice(device);
|
||||||
|
retval = device->queued_bytes;
|
||||||
|
current_audio.impl.UnlockDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -574,25 +642,49 @@ void
|
||||||
SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
|
SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *device = get_audio_device(devid);
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
SDL_AudioBufferQueue *buffer = NULL;
|
SDL_AudioBufferQueue *packet;
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return; /* nothing to do. */
|
return; /* nothing to do. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Blank out the device and release the mutex. Free it afterwards. */
|
/* Blank out the device and release the mutex. Free it afterwards. */
|
||||||
current_audio.impl.LockDevice(device);
|
current_audio.impl.LockDevice(device);
|
||||||
buffer = device->buffer_queue_head;
|
|
||||||
|
/* merge the available pool and the current queue into one list. */
|
||||||
|
packet = device->buffer_queue_head;
|
||||||
|
if (packet) {
|
||||||
|
device->buffer_queue_tail->next = device->buffer_queue_pool;
|
||||||
|
} else {
|
||||||
|
packet = device->buffer_queue_pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the queued packets from the device. */
|
||||||
device->buffer_queue_tail = NULL;
|
device->buffer_queue_tail = NULL;
|
||||||
device->buffer_queue_head = NULL;
|
device->buffer_queue_head = NULL;
|
||||||
device->queued_bytes = 0;
|
device->queued_bytes = 0;
|
||||||
|
device->buffer_queue_pool = packet;
|
||||||
|
|
||||||
|
/* Keep up to two packets in the pool to reduce future malloc pressure. */
|
||||||
|
if (packet) {
|
||||||
|
if (!packet->next) {
|
||||||
|
packet = NULL; /* one packet (the only one) for the pool. */
|
||||||
|
} else {
|
||||||
|
SDL_AudioBufferQueue *next = packet->next->next;
|
||||||
|
packet->next->next = NULL; /* two packets for the pool. */
|
||||||
|
packet = next; /* rest will be freed. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current_audio.impl.UnlockDevice(device);
|
current_audio.impl.UnlockDevice(device);
|
||||||
|
|
||||||
free_audio_queue(buffer);
|
/* free any extra packets we didn't keep in the pool. */
|
||||||
|
free_audio_queue(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The general mixing thread function */
|
/* The general mixing thread function */
|
||||||
int SDLCALL
|
static int SDLCALL
|
||||||
SDL_RunAudio(void *devicep)
|
SDL_RunAudio(void *devicep)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
|
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
|
||||||
|
@ -601,7 +693,9 @@ SDL_RunAudio(void *devicep)
|
||||||
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
|
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
|
||||||
Uint8 *stream;
|
Uint8 *stream;
|
||||||
void *udata = device->spec.userdata;
|
void *udata = device->spec.userdata;
|
||||||
void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback;
|
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
|
||||||
|
|
||||||
|
SDL_assert(!device->iscapture);
|
||||||
|
|
||||||
/* The audio mixing is always a high priority thread */
|
/* The audio mixing is always a high priority thread */
|
||||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||||
|
@ -611,11 +705,11 @@ SDL_RunAudio(void *devicep)
|
||||||
current_audio.impl.ThreadInit(device);
|
current_audio.impl.ThreadInit(device);
|
||||||
|
|
||||||
/* Loop, filling the audio buffers */
|
/* Loop, filling the audio buffers */
|
||||||
while (!device->shutdown) {
|
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||||
/* Fill the current buffer with sound */
|
/* Fill the current buffer with sound */
|
||||||
if (device->convert.needed) {
|
if (device->convert.needed) {
|
||||||
stream = device->convert.buf;
|
stream = device->convert.buf;
|
||||||
} else if (device->enabled) {
|
} else if (SDL_AtomicGet(&device->enabled)) {
|
||||||
stream = current_audio.impl.GetDeviceBuf(device);
|
stream = current_audio.impl.GetDeviceBuf(device);
|
||||||
} else {
|
} else {
|
||||||
/* if the device isn't enabled, we still write to the
|
/* if the device isn't enabled, we still write to the
|
||||||
|
@ -632,15 +726,15 @@ SDL_RunAudio(void *devicep)
|
||||||
|
|
||||||
/* !!! FIXME: this should be LockDevice. */
|
/* !!! FIXME: this should be LockDevice. */
|
||||||
SDL_LockMutex(device->mixer_lock);
|
SDL_LockMutex(device->mixer_lock);
|
||||||
if (device->paused) {
|
if (SDL_AtomicGet(&device->paused)) {
|
||||||
SDL_memset(stream, silence, stream_len);
|
SDL_memset(stream, silence, stream_len);
|
||||||
} else {
|
} else {
|
||||||
(*fill) (udata, stream, stream_len);
|
(*callback) (udata, stream, stream_len);
|
||||||
}
|
}
|
||||||
SDL_UnlockMutex(device->mixer_lock);
|
SDL_UnlockMutex(device->mixer_lock);
|
||||||
|
|
||||||
/* Convert the audio if necessary */
|
/* Convert the audio if necessary */
|
||||||
if (device->enabled && device->convert.needed) {
|
if (device->convert.needed && SDL_AtomicGet(&device->enabled)) {
|
||||||
SDL_ConvertAudio(&device->convert);
|
SDL_ConvertAudio(&device->convert);
|
||||||
stream = current_audio.impl.GetDeviceBuf(device);
|
stream = current_audio.impl.GetDeviceBuf(device);
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
|
@ -661,11 +755,93 @@ SDL_RunAudio(void *devicep)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the audio to drain. */
|
/* Wait for the audio to drain. */
|
||||||
|
/* !!! FIXME: can we rename this WaitDrain? */
|
||||||
current_audio.impl.WaitDone(device);
|
current_audio.impl.WaitDone(device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The general capture thread function */
|
||||||
|
static int SDLCALL
|
||||||
|
SDL_CaptureAudio(void *devicep)
|
||||||
|
{
|
||||||
|
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
|
||||||
|
const int silence = (int) device->spec.silence;
|
||||||
|
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
|
||||||
|
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
|
||||||
|
Uint8 *stream;
|
||||||
|
void *udata = device->spec.userdata;
|
||||||
|
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
|
||||||
|
|
||||||
|
SDL_assert(device->iscapture);
|
||||||
|
|
||||||
|
/* The audio mixing is always a high priority thread */
|
||||||
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||||
|
|
||||||
|
/* Perform any thread setup */
|
||||||
|
device->threadid = SDL_ThreadID();
|
||||||
|
current_audio.impl.ThreadInit(device);
|
||||||
|
|
||||||
|
/* Loop, filling the audio buffers */
|
||||||
|
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||||
|
int still_need;
|
||||||
|
Uint8 *ptr;
|
||||||
|
|
||||||
|
if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
|
||||||
|
SDL_Delay(delay); /* just so we don't cook the CPU. */
|
||||||
|
current_audio.impl.FlushCapture(device); /* dump anything pending. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the current buffer with sound */
|
||||||
|
still_need = stream_len;
|
||||||
|
if (device->convert.needed) {
|
||||||
|
ptr = stream = device->convert.buf;
|
||||||
|
} else {
|
||||||
|
/* just use the "fake" stream to hold data read from the device. */
|
||||||
|
ptr = stream = device->fake_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We still read from the device when "paused" to keep the state sane,
|
||||||
|
and block when there isn't data so this thread isn't eating CPU.
|
||||||
|
But we don't process it further or call the app's callback. */
|
||||||
|
|
||||||
|
while (still_need > 0) {
|
||||||
|
const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
|
||||||
|
SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
|
||||||
|
if (rc > 0) {
|
||||||
|
still_need -= rc;
|
||||||
|
ptr += rc;
|
||||||
|
} else { /* uhoh, device failed for some reason! */
|
||||||
|
SDL_OpenedAudioDeviceDisconnected(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (still_need > 0) {
|
||||||
|
/* Keep any data we already read, silence the rest. */
|
||||||
|
SDL_memset(ptr, silence, still_need);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->convert.needed) {
|
||||||
|
SDL_ConvertAudio(&device->convert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* !!! FIXME: this should be LockDevice. */
|
||||||
|
SDL_LockMutex(device->mixer_lock);
|
||||||
|
if (SDL_AtomicGet(&device->paused)) {
|
||||||
|
current_audio.impl.FlushCapture(device); /* one snuck in! */
|
||||||
|
} else {
|
||||||
|
(*callback)(udata, stream, stream_len);
|
||||||
|
}
|
||||||
|
SDL_UnlockMutex(device->mixer_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_audio.impl.FlushCapture(device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static SDL_AudioFormat
|
static SDL_AudioFormat
|
||||||
SDL_ParseAudioFormat(const char *string)
|
SDL_ParseAudioFormat(const char *string)
|
||||||
|
@ -873,27 +1049,26 @@ SDL_GetAudioDeviceName(int index, int iscapture)
|
||||||
static void
|
static void
|
||||||
close_audio_device(SDL_AudioDevice * device)
|
close_audio_device(SDL_AudioDevice * device)
|
||||||
{
|
{
|
||||||
device->enabled = 0;
|
SDL_AtomicSet(&device->shutdown, 1);
|
||||||
device->shutdown = 1;
|
SDL_AtomicSet(&device->enabled, 0);
|
||||||
if (device->thread != NULL) {
|
if (device->thread != NULL) {
|
||||||
SDL_WaitThread(device->thread, NULL);
|
SDL_WaitThread(device->thread, NULL);
|
||||||
}
|
}
|
||||||
if (device->mixer_lock != NULL) {
|
if (device->mixer_lock != NULL) {
|
||||||
SDL_DestroyMutex(device->mixer_lock);
|
SDL_DestroyMutex(device->mixer_lock);
|
||||||
}
|
}
|
||||||
SDL_FreeAudioMem(device->fake_stream);
|
SDL_free(device->fake_stream);
|
||||||
if (device->convert.needed) {
|
if (device->convert.needed) {
|
||||||
SDL_FreeAudioMem(device->convert.buf);
|
SDL_free(device->convert.buf);
|
||||||
}
|
}
|
||||||
if (device->opened) {
|
if (device->hidden != NULL) {
|
||||||
current_audio.impl.CloseDevice(device);
|
current_audio.impl.CloseDevice(device);
|
||||||
device->opened = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free_audio_queue(device->buffer_queue_head);
|
free_audio_queue(device->buffer_queue_head);
|
||||||
free_audio_queue(device->buffer_queue_pool);
|
free_audio_queue(device->buffer_queue_pool);
|
||||||
|
|
||||||
SDL_FreeAudioMem(device);
|
SDL_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -964,12 +1139,12 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
|
const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
|
||||||
int allowed_changes, int min_id)
|
int allowed_changes, int min_id)
|
||||||
{
|
{
|
||||||
|
const SDL_bool is_internal_thread = (desired->callback != NULL);
|
||||||
SDL_AudioDeviceID id = 0;
|
SDL_AudioDeviceID id = 0;
|
||||||
SDL_AudioSpec _obtained;
|
SDL_AudioSpec _obtained;
|
||||||
SDL_AudioDevice *device;
|
SDL_AudioDevice *device;
|
||||||
SDL_bool build_cvt;
|
SDL_bool build_cvt;
|
||||||
void *handle = NULL;
|
void *handle = NULL;
|
||||||
Uint32 stream_len;
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
@ -1016,7 +1191,7 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
* opens of the default system device.
|
* opens of the default system device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
|
if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) {
|
||||||
if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
|
if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
|
||||||
SDL_SetError("No such device");
|
SDL_SetError("No such device");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1068,17 +1243,18 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
|
device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice));
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SDL_zerop(device);
|
|
||||||
device->id = id + 1;
|
device->id = id + 1;
|
||||||
device->spec = *obtained;
|
device->spec = *obtained;
|
||||||
device->enabled = 1;
|
device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||||
device->paused = 1;
|
|
||||||
device->iscapture = iscapture;
|
SDL_AtomicSet(&device->shutdown, 0); /* just in case. */
|
||||||
|
SDL_AtomicSet(&device->paused, 1);
|
||||||
|
SDL_AtomicSet(&device->enabled, 1);
|
||||||
|
|
||||||
/* Create a mutex for locking the sound buffers */
|
/* Create a mutex for locking the sound buffers */
|
||||||
if (!current_audio.impl.SkipMixerLock) {
|
if (!current_audio.impl.SkipMixerLock) {
|
||||||
|
@ -1094,7 +1270,10 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
close_audio_device(device);
|
close_audio_device(device);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
device->opened = 1;
|
|
||||||
|
/* if your target really doesn't need it, set it to 0x1 or something. */
|
||||||
|
/* otherwise, close_audio_device() won't call impl.CloseDevice(). */
|
||||||
|
SDL_assert(device->hidden != NULL);
|
||||||
|
|
||||||
/* See if we need to do any conversion */
|
/* See if we need to do any conversion */
|
||||||
build_cvt = SDL_FALSE;
|
build_cvt = SDL_FALSE;
|
||||||
|
@ -1144,7 +1323,7 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
device->convert.len_ratio);
|
device->convert.len_ratio);
|
||||||
|
|
||||||
device->convert.buf =
|
device->convert.buf =
|
||||||
(Uint8 *) SDL_AllocAudioMem(device->convert.len *
|
(Uint8 *) SDL_malloc(device->convert.len *
|
||||||
device->convert.len_mult);
|
device->convert.len_mult);
|
||||||
if (device->convert.buf == NULL) {
|
if (device->convert.buf == NULL) {
|
||||||
close_audio_device(device);
|
close_audio_device(device);
|
||||||
|
@ -1154,19 +1333,6 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a fake audio memory buffer */
|
|
||||||
stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
|
|
||||||
if (device->spec.size > stream_len) {
|
|
||||||
stream_len = device->spec.size;
|
|
||||||
}
|
|
||||||
SDL_assert(stream_len > 0);
|
|
||||||
device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len);
|
|
||||||
if (device->fake_stream == NULL) {
|
|
||||||
close_audio_device(device);
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->spec.callback == NULL) { /* use buffer queueing? */
|
if (device->spec.callback == NULL) { /* use buffer queueing? */
|
||||||
/* pool a few packets to start. Enough for two callbacks. */
|
/* pool a few packets to start. Enough for two callbacks. */
|
||||||
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
|
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
|
||||||
|
@ -1182,7 +1348,7 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device->spec.callback = SDL_BufferQueueDrainCallback;
|
device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
|
||||||
device->spec.userdata = device;
|
device->spec.userdata = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1192,14 +1358,27 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
/* Start the audio thread if necessary */
|
/* Start the audio thread if necessary */
|
||||||
if (!current_audio.impl.ProvidesOwnCallbackThread) {
|
if (!current_audio.impl.ProvidesOwnCallbackThread) {
|
||||||
/* Start the audio thread */
|
/* Start the audio thread */
|
||||||
|
/* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */
|
||||||
/* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */
|
|
||||||
/* buffer queueing callback only needs a few bytes, so make the stack tiny. */
|
/* buffer queueing callback only needs a few bytes, so make the stack tiny. */
|
||||||
char name[64];
|
const size_t stacksize = is_internal_thread ? 64 * 1024 : 0;
|
||||||
const size_t stacksize = (device->spec.callback == SDL_BufferQueueDrainCallback) ? 64 * 1024 : 0;
|
char threadname[64];
|
||||||
|
|
||||||
SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id);
|
/* Allocate a fake audio buffer; only used by our internal threads. */
|
||||||
device->thread = SDL_CreateThreadInternal(SDL_RunAudio, name, stacksize, device);
|
Uint32 stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
|
||||||
|
if (device->spec.size > stream_len) {
|
||||||
|
stream_len = device->spec.size;
|
||||||
|
}
|
||||||
|
SDL_assert(stream_len > 0);
|
||||||
|
|
||||||
|
device->fake_stream = (Uint8 *) SDL_malloc(stream_len);
|
||||||
|
if (device->fake_stream == NULL) {
|
||||||
|
close_audio_device(device);
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_snprintf(threadname, sizeof (threadname), "SDLAudioDev%d", (int) device->id);
|
||||||
|
device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device);
|
||||||
|
|
||||||
if (device->thread == NULL) {
|
if (device->thread == NULL) {
|
||||||
SDL_CloseAudioDevice(device->id);
|
SDL_CloseAudioDevice(device->id);
|
||||||
|
@ -1255,8 +1434,8 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *device = get_audio_device(devid);
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
SDL_AudioStatus status = SDL_AUDIO_STOPPED;
|
SDL_AudioStatus status = SDL_AUDIO_STOPPED;
|
||||||
if (device && device->enabled) {
|
if (device && SDL_AtomicGet(&device->enabled)) {
|
||||||
if (device->paused) {
|
if (SDL_AtomicGet(&device->paused)) {
|
||||||
status = SDL_AUDIO_PAUSED;
|
status = SDL_AUDIO_PAUSED;
|
||||||
} else {
|
} else {
|
||||||
status = SDL_AUDIO_PLAYING;
|
status = SDL_AUDIO_PLAYING;
|
||||||
|
@ -1278,7 +1457,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
|
||||||
SDL_AudioDevice *device = get_audio_device(devid);
|
SDL_AudioDevice *device = get_audio_device(devid);
|
||||||
if (device) {
|
if (device) {
|
||||||
current_audio.impl.LockDevice(device);
|
current_audio.impl.LockDevice(device);
|
||||||
device->paused = pause_on;
|
SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
|
||||||
current_audio.impl.UnlockDevice(device);
|
current_audio.impl.UnlockDevice(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,6 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void);
|
||||||
/* Function to calculate the size and silence for a SDL_AudioSpec */
|
/* Function to calculate the size and silence for a SDL_AudioSpec */
|
||||||
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
|
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
|
||||||
|
|
||||||
/* The actual mixing thread function */
|
|
||||||
extern int SDLCALL SDL_RunAudio(void *audiop);
|
|
||||||
|
|
||||||
/* this is used internally to access some autogenerated code. */
|
/* this is used internally to access some autogenerated code. */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
#include "../SDL_internal.h"
|
|
||||||
|
|
||||||
#define SDL_AllocAudioMem SDL_malloc
|
|
||||||
#define SDL_FreeAudioMem SDL_free
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -26,6 +26,10 @@
|
||||||
#include "SDL_mutex.h"
|
#include "SDL_mutex.h"
|
||||||
#include "SDL_thread.h"
|
#include "SDL_thread.h"
|
||||||
|
|
||||||
|
/* !!! FIXME: These are wordy and unlocalized... */
|
||||||
|
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
|
||||||
|
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
|
||||||
|
|
||||||
/* The SDL audio driver */
|
/* The SDL audio driver */
|
||||||
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||||
#define _THIS SDL_AudioDevice *_this
|
#define _THIS SDL_AudioDevice *_this
|
||||||
|
@ -76,6 +80,8 @@ typedef struct SDL_AudioDriverImpl
|
||||||
int (*GetPendingBytes) (_THIS);
|
int (*GetPendingBytes) (_THIS);
|
||||||
Uint8 *(*GetDeviceBuf) (_THIS);
|
Uint8 *(*GetDeviceBuf) (_THIS);
|
||||||
void (*WaitDone) (_THIS);
|
void (*WaitDone) (_THIS);
|
||||||
|
int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
|
||||||
|
void (*FlushCapture) (_THIS);
|
||||||
void (*CloseDevice) (_THIS);
|
void (*CloseDevice) (_THIS);
|
||||||
void (*LockDevice) (_THIS);
|
void (*LockDevice) (_THIS);
|
||||||
void (*UnlockDevice) (_THIS);
|
void (*UnlockDevice) (_THIS);
|
||||||
|
@ -90,7 +96,7 @@ typedef struct SDL_AudioDriverImpl
|
||||||
int SkipMixerLock; /* !!! FIXME: do we need this anymore? */
|
int SkipMixerLock; /* !!! FIXME: do we need this anymore? */
|
||||||
int HasCaptureSupport;
|
int HasCaptureSupport;
|
||||||
int OnlyHasDefaultOutputDevice;
|
int OnlyHasDefaultOutputDevice;
|
||||||
int OnlyHasDefaultInputDevice;
|
int OnlyHasDefaultCaptureDevice;
|
||||||
int AllowsArbitraryDeviceNames;
|
int AllowsArbitraryDeviceNames;
|
||||||
} SDL_AudioDriverImpl;
|
} SDL_AudioDriverImpl;
|
||||||
|
|
||||||
|
@ -157,12 +163,10 @@ struct SDL_AudioDevice
|
||||||
SDL_AudioStreamer streamer;
|
SDL_AudioStreamer streamer;
|
||||||
|
|
||||||
/* Current state flags */
|
/* Current state flags */
|
||||||
/* !!! FIXME: should be SDL_bool */
|
SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */
|
||||||
int iscapture;
|
SDL_atomic_t enabled; /* true if device is functioning and connected. */
|
||||||
int enabled; /* true if device is functioning and connected. */
|
SDL_atomic_t paused;
|
||||||
int shutdown; /* true if we are signaling the play thread to end. */
|
SDL_bool iscapture;
|
||||||
int paused;
|
|
||||||
int opened;
|
|
||||||
|
|
||||||
/* Fake audio buffer for when the audio hardware is busy */
|
/* Fake audio buffer for when the audio hardware is busy */
|
||||||
Uint8 *fake_stream;
|
Uint8 *fake_stream;
|
||||||
|
|
|
@ -504,7 +504,7 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
||||||
was_error = 1;
|
was_error = 1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
SDL_memset(spec, 0, (sizeof *spec));
|
SDL_zerop(spec);
|
||||||
spec->freq = SDL_SwapLE32(format->frequency);
|
spec->freq = SDL_SwapLE32(format->frequency);
|
||||||
|
|
||||||
if (IEEE_float_encoded) {
|
if (IEEE_float_encoded) {
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "SDL_assert.h"
|
#include "SDL_assert.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_alsa_audio.h"
|
#include "SDL_alsa_audio.h"
|
||||||
|
|
||||||
|
@ -43,8 +42,10 @@
|
||||||
static int (*ALSA_snd_pcm_open)
|
static int (*ALSA_snd_pcm_open)
|
||||||
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
|
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
|
||||||
static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
|
static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
|
||||||
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
|
static snd_pcm_sframes_t (*ALSA_snd_pcm_writei)
|
||||||
(snd_pcm_t *, const void *, snd_pcm_uframes_t);
|
(snd_pcm_t *, const void *, snd_pcm_uframes_t);
|
||||||
|
static snd_pcm_sframes_t (*ALSA_snd_pcm_readi)
|
||||||
|
(snd_pcm_t *, void *, snd_pcm_uframes_t);
|
||||||
static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
|
static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
|
||||||
static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
|
static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
|
||||||
static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
|
static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
|
||||||
|
@ -86,6 +87,7 @@ static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
|
||||||
static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
|
static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
|
||||||
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
|
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
|
||||||
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
|
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
|
||||||
|
static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
|
||||||
static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
|
static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
|
||||||
static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
|
static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
|
||||||
static int (*ALSA_snd_device_name_free_hint) (void **);
|
static int (*ALSA_snd_device_name_free_hint) (void **);
|
||||||
|
@ -122,6 +124,7 @@ load_alsa_syms(void)
|
||||||
SDL_ALSA_SYM(snd_pcm_open);
|
SDL_ALSA_SYM(snd_pcm_open);
|
||||||
SDL_ALSA_SYM(snd_pcm_close);
|
SDL_ALSA_SYM(snd_pcm_close);
|
||||||
SDL_ALSA_SYM(snd_pcm_writei);
|
SDL_ALSA_SYM(snd_pcm_writei);
|
||||||
|
SDL_ALSA_SYM(snd_pcm_readi);
|
||||||
SDL_ALSA_SYM(snd_pcm_recover);
|
SDL_ALSA_SYM(snd_pcm_recover);
|
||||||
SDL_ALSA_SYM(snd_pcm_prepare);
|
SDL_ALSA_SYM(snd_pcm_prepare);
|
||||||
SDL_ALSA_SYM(snd_pcm_drain);
|
SDL_ALSA_SYM(snd_pcm_drain);
|
||||||
|
@ -148,6 +151,7 @@ load_alsa_syms(void)
|
||||||
SDL_ALSA_SYM(snd_pcm_nonblock);
|
SDL_ALSA_SYM(snd_pcm_nonblock);
|
||||||
SDL_ALSA_SYM(snd_pcm_wait);
|
SDL_ALSA_SYM(snd_pcm_wait);
|
||||||
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
|
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
|
||||||
|
SDL_ALSA_SYM(snd_pcm_reset);
|
||||||
SDL_ALSA_SYM(snd_device_name_hint);
|
SDL_ALSA_SYM(snd_device_name_hint);
|
||||||
SDL_ALSA_SYM(snd_device_name_get_hint);
|
SDL_ALSA_SYM(snd_device_name_get_hint);
|
||||||
SDL_ALSA_SYM(snd_device_name_free_hint);
|
SDL_ALSA_SYM(snd_device_name_free_hint);
|
||||||
|
@ -242,37 +246,37 @@ ALSA_WaitDevice(_THIS)
|
||||||
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
|
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
|
||||||
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
|
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
|
||||||
*/
|
*/
|
||||||
#define SWIZ6(T) \
|
#define SWIZ6(T, buf, numframes) \
|
||||||
T *ptr = (T *) this->hidden->mixbuf; \
|
T *ptr = (T *) buf; \
|
||||||
Uint32 i; \
|
Uint32 i; \
|
||||||
for (i = 0; i < this->spec.samples; i++, ptr += 6) { \
|
for (i = 0; i < numframes; i++, ptr += 6) { \
|
||||||
T tmp; \
|
T tmp; \
|
||||||
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
|
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
|
||||||
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
|
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE void
|
static SDL_INLINE void
|
||||||
swizzle_alsa_channels_6_64bit(_THIS)
|
swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
SWIZ6(Uint64);
|
SWIZ6(Uint64, buffer, bufferlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE void
|
static SDL_INLINE void
|
||||||
swizzle_alsa_channels_6_32bit(_THIS)
|
swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
SWIZ6(Uint32);
|
SWIZ6(Uint32, buffer, bufferlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE void
|
static SDL_INLINE void
|
||||||
swizzle_alsa_channels_6_16bit(_THIS)
|
swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
SWIZ6(Uint16);
|
SWIZ6(Uint16, buffer, bufferlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE void
|
static SDL_INLINE void
|
||||||
swizzle_alsa_channels_6_8bit(_THIS)
|
swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
SWIZ6(Uint8);
|
SWIZ6(Uint8, buffer, bufferlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SWIZ6
|
#undef SWIZ6
|
||||||
|
@ -283,18 +287,16 @@ swizzle_alsa_channels_6_8bit(_THIS)
|
||||||
* channels from Windows/Mac order to the format alsalib will want.
|
* channels from Windows/Mac order to the format alsalib will want.
|
||||||
*/
|
*/
|
||||||
static SDL_INLINE void
|
static SDL_INLINE void
|
||||||
swizzle_alsa_channels(_THIS)
|
swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
if (this->spec.channels == 6) {
|
if (this->spec.channels == 6) {
|
||||||
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
|
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
|
||||||
if (fmtsize == 16)
|
case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
|
||||||
swizzle_alsa_channels_6_16bit(this);
|
case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
|
||||||
else if (fmtsize == 8)
|
case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
|
||||||
swizzle_alsa_channels_6_8bit(this);
|
case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
|
||||||
else if (fmtsize == 32)
|
default: SDL_assert(!"unhandled bitsize"); break;
|
||||||
swizzle_alsa_channels_6_32bit(this);
|
}
|
||||||
else if (fmtsize == 64)
|
|
||||||
swizzle_alsa_channels_6_64bit(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* !!! FIXME: update this for 7.1 if needed, later. */
|
/* !!! FIXME: update this for 7.1 if needed, later. */
|
||||||
|
@ -304,18 +306,17 @@ swizzle_alsa_channels(_THIS)
|
||||||
static void
|
static void
|
||||||
ALSA_PlayDevice(_THIS)
|
ALSA_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
int status;
|
|
||||||
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
|
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
|
||||||
const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) *
|
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||||
this->spec.channels;
|
this->spec.channels;
|
||||||
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
|
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
|
||||||
|
|
||||||
swizzle_alsa_channels(this);
|
swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left);
|
||||||
|
|
||||||
while ( frames_left > 0 && this->enabled ) {
|
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
||||||
/* !!! FIXME: This works, but needs more testing before going live */
|
/* !!! FIXME: This works, but needs more testing before going live */
|
||||||
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
|
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
|
||||||
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
||||||
sample_buf, frames_left);
|
sample_buf, frames_left);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
@ -346,20 +347,66 @@ ALSA_GetDeviceBuf(_THIS)
|
||||||
return (this->hidden->mixbuf);
|
return (this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
Uint8 *sample_buf = (Uint8 *) buffer;
|
||||||
|
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||||
|
this->spec.channels;
|
||||||
|
const int total_frames = buflen / frame_size;
|
||||||
|
snd_pcm_uframes_t frames_left = total_frames;
|
||||||
|
|
||||||
|
SDL_assert((buflen % frame_size) == 0);
|
||||||
|
|
||||||
|
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
||||||
|
/* !!! FIXME: This works, but needs more testing before going live */
|
||||||
|
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
|
||||||
|
int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
||||||
|
sample_buf, frames_left);
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
/*printf("ALSA: capture error %d\n", status);*/
|
||||||
|
if (status == -EAGAIN) {
|
||||||
|
/* Apparently snd_pcm_recover() doesn't handle this case -
|
||||||
|
does it assume snd_pcm_wait() above? */
|
||||||
|
SDL_Delay(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
|
||||||
|
if (status < 0) {
|
||||||
|
/* Hmm, not much we can do - abort */
|
||||||
|
fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
|
||||||
|
ALSA_snd_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*printf("ALSA: captured %d bytes\n", status * frame_size);*/
|
||||||
|
sample_buf += status * frame_size;
|
||||||
|
frames_left -= status;
|
||||||
|
}
|
||||||
|
|
||||||
|
swizzle_alsa_channels(this, buffer, total_frames - frames_left);
|
||||||
|
|
||||||
|
return (total_frames - frames_left) * frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ALSA_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
ALSA_snd_pcm_reset(this->hidden->pcm_handle);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ALSA_CloseDevice(_THIS)
|
ALSA_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->pcm_handle) {
|
if (this->hidden->pcm_handle) {
|
||||||
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
|
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
|
||||||
ALSA_snd_pcm_close(this->hidden->pcm_handle);
|
ALSA_snd_pcm_close(this->hidden->pcm_handle);
|
||||||
this->hidden->pcm_handle = NULL;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -492,16 +539,16 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
/* Name of device should depend on # channels in spec */
|
/* Name of device should depend on # channels in spec */
|
||||||
status = ALSA_snd_pcm_open(&pcm_handle,
|
status = ALSA_snd_pcm_open(&pcm_handle,
|
||||||
get_audio_device(handle, this->spec.channels),
|
get_audio_device(handle, this->spec.channels),
|
||||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||||
|
SND_PCM_NONBLOCK);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't open audio device: %s",
|
return SDL_SetError("ALSA: Couldn't open audio device: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -512,7 +559,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
snd_pcm_hw_params_alloca(&hwparams);
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
|
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't get hardware config: %s",
|
return SDL_SetError("ALSA: Couldn't get hardware config: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -521,7 +567,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
|
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
|
return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -575,7 +620,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
|
return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
@ -587,7 +631,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
|
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't set audio channels");
|
return SDL_SetError("ALSA: Couldn't set audio channels");
|
||||||
}
|
}
|
||||||
this->spec.channels = channels;
|
this->spec.channels = channels;
|
||||||
|
@ -598,7 +641,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
|
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
|
||||||
&rate, NULL);
|
&rate, NULL);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
|
return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -610,7 +652,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Failed to set desired buffer size, do the best you can... */
|
/* Failed to set desired buffer size, do the best you can... */
|
||||||
status = ALSA_set_period_size(this, hwparams, 1);
|
status = ALSA_set_period_size(this, hwparams, 1);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
|
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,26 +659,22 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
snd_pcm_sw_params_alloca(&swparams);
|
snd_pcm_sw_params_alloca(&swparams);
|
||||||
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
|
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't get software config: %s",
|
return SDL_SetError("ALSA: Couldn't get software config: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
|
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set minimum available samples: %s",
|
return SDL_SetError("Couldn't set minimum available samples: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
status =
|
status =
|
||||||
ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
|
ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("ALSA: Couldn't set start threshold: %s",
|
return SDL_SetError("ALSA: Couldn't set start threshold: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
|
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set software audio parameters: %s",
|
return SDL_SetError("Couldn't set software audio parameters: %s",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -646,13 +683,14 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
|
if (!iscapture) {
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
ALSA_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
||||||
|
}
|
||||||
|
|
||||||
/* Switch to blocking mode for playback */
|
/* Switch to blocking mode for playback */
|
||||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||||
|
@ -866,6 +904,10 @@ ALSA_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->PlayDevice = ALSA_PlayDevice;
|
impl->PlayDevice = ALSA_PlayDevice;
|
||||||
impl->CloseDevice = ALSA_CloseDevice;
|
impl->CloseDevice = ALSA_CloseDevice;
|
||||||
impl->Deinitialize = ALSA_Deinitialize;
|
impl->Deinitialize = ALSA_Deinitialize;
|
||||||
|
impl->CaptureFromDevice = ALSA_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = ALSA_FlushCapture;
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
/* Output audio to Android */
|
/* Output audio to Android */
|
||||||
|
|
||||||
|
#include "SDL_assert.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_androidaudio.h"
|
#include "SDL_androidaudio.h"
|
||||||
|
@ -33,22 +34,21 @@
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
static SDL_AudioDevice* audioDevice = NULL;
|
static SDL_AudioDevice* audioDevice = NULL;
|
||||||
|
static SDL_AudioDevice* captureDevice = NULL;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
|
|
||||||
|
SDL_assert((captureDevice == NULL) || !iscapture);
|
||||||
|
SDL_assert((audioDevice == NULL) || iscapture);
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
/* TODO: implement capture */
|
captureDevice = this;
|
||||||
return SDL_SetError("Capture not supported on Android");
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if (audioDevice != NULL) {
|
|
||||||
return SDL_SetError("Only one audio device at a time please!");
|
|
||||||
}
|
|
||||||
|
|
||||||
audioDevice = this;
|
audioDevice = this;
|
||||||
|
}
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
|
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
|
@ -82,100 +82,137 @@ AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
this->spec.freq = 48000;
|
this->spec.freq = 48000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: pass in/return a (Java) device ID, also whether we're opening for input or output */
|
/* TODO: pass in/return a (Java) device ID */
|
||||||
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
|
this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
|
||||||
|
|
||||||
if (this->spec.samples == 0) {
|
if (this->spec.samples == 0) {
|
||||||
/* Init failed? */
|
/* Init failed? */
|
||||||
return SDL_SetError("Java-side initialization failed!");
|
return SDL_SetError("Java-side initialization failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AndroidAUD_PlayDevice(_THIS)
|
ANDROIDAUDIO_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
Android_JNI_WriteAudioBuffer();
|
Android_JNI_WriteAudioBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
AndroidAUD_GetDeviceBuf(_THIS)
|
ANDROIDAUDIO_GetDeviceBuf(_THIS)
|
||||||
{
|
{
|
||||||
return Android_JNI_GetAudioBuffer();
|
return Android_JNI_GetAudioBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AndroidAUD_CloseDevice(_THIS)
|
ANDROIDAUDIO_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
Android_JNI_FlushCapturedAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ANDROIDAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
|
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
|
||||||
so it's safe to terminate the Java side buffer and AudioTrack
|
so it's safe to terminate the Java side buffer and AudioTrack
|
||||||
*/
|
*/
|
||||||
Android_JNI_CloseAudioDevice();
|
Android_JNI_CloseAudioDevice(this->iscapture);
|
||||||
|
if (this->iscapture) {
|
||||||
if (audioDevice == this) {
|
SDL_assert(captureDevice == this);
|
||||||
if (audioDevice->hidden != NULL) {
|
captureDevice = NULL;
|
||||||
SDL_free(this->hidden);
|
} else {
|
||||||
this->hidden = NULL;
|
SDL_assert(audioDevice == this);
|
||||||
}
|
|
||||||
audioDevice = NULL;
|
audioDevice = NULL;
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
AndroidAUD_Init(SDL_AudioDriverImpl * impl)
|
ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = AndroidAUD_OpenDevice;
|
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
|
||||||
impl->PlayDevice = AndroidAUD_PlayDevice;
|
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
|
||||||
impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
|
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
|
||||||
impl->CloseDevice = AndroidAUD_CloseDevice;
|
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
|
||||||
|
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
|
||||||
|
|
||||||
/* and the capabilities */
|
/* and the capabilities */
|
||||||
impl->HasCaptureSupport = 0; /* TODO */
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
impl->OnlyHasDefaultInputDevice = 1;
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap ANDROIDAUD_bootstrap = {
|
AudioBootStrap ANDROIDAUDIO_bootstrap = {
|
||||||
"android", "SDL Android audio driver", AndroidAUD_Init, 0
|
"android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Pause (block) all non already paused audio devices by taking their mixer lock */
|
/* Pause (block) all non already paused audio devices by taking their mixer lock */
|
||||||
void AndroidAUD_PauseDevices(void)
|
void ANDROIDAUDIO_PauseDevices(void)
|
||||||
{
|
{
|
||||||
/* TODO: Handle multiple devices? */
|
/* TODO: Handle multiple devices? */
|
||||||
struct SDL_PrivateAudioData *private;
|
struct SDL_PrivateAudioData *private;
|
||||||
if(audioDevice != NULL && audioDevice->hidden != NULL) {
|
if(audioDevice != NULL && audioDevice->hidden != NULL) {
|
||||||
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
|
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
|
||||||
if (audioDevice->paused) {
|
if (SDL_AtomicGet(&audioDevice->paused)) {
|
||||||
/* The device is already paused, leave it alone */
|
/* The device is already paused, leave it alone */
|
||||||
private->resume = SDL_FALSE;
|
private->resume = SDL_FALSE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SDL_LockMutex(audioDevice->mixer_lock);
|
SDL_LockMutex(audioDevice->mixer_lock);
|
||||||
audioDevice->paused = SDL_TRUE;
|
SDL_AtomicSet(&audioDevice->paused, 1);
|
||||||
|
private->resume = SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(captureDevice != NULL && captureDevice->hidden != NULL) {
|
||||||
|
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
|
||||||
|
if (SDL_AtomicGet(&captureDevice->paused)) {
|
||||||
|
/* The device is already paused, leave it alone */
|
||||||
|
private->resume = SDL_FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_LockMutex(captureDevice->mixer_lock);
|
||||||
|
SDL_AtomicSet(&captureDevice->paused, 1);
|
||||||
private->resume = SDL_TRUE;
|
private->resume = SDL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
|
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
|
||||||
void AndroidAUD_ResumeDevices(void)
|
void ANDROIDAUDIO_ResumeDevices(void)
|
||||||
{
|
{
|
||||||
/* TODO: Handle multiple devices? */
|
/* TODO: Handle multiple devices? */
|
||||||
struct SDL_PrivateAudioData *private;
|
struct SDL_PrivateAudioData *private;
|
||||||
if(audioDevice != NULL && audioDevice->hidden != NULL) {
|
if(audioDevice != NULL && audioDevice->hidden != NULL) {
|
||||||
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
|
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
|
||||||
if (private->resume) {
|
if (private->resume) {
|
||||||
audioDevice->paused = SDL_FALSE;
|
SDL_AtomicSet(&audioDevice->paused, 0);
|
||||||
private->resume = SDL_FALSE;
|
private->resume = SDL_FALSE;
|
||||||
SDL_UnlockMutex(audioDevice->mixer_lock);
|
SDL_UnlockMutex(audioDevice->mixer_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(captureDevice != NULL && captureDevice->hidden != NULL) {
|
||||||
|
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
|
||||||
|
if (private->resume) {
|
||||||
|
SDL_AtomicSet(&captureDevice->paused, 0);
|
||||||
|
private->resume = SDL_FALSE;
|
||||||
|
SDL_UnlockMutex(captureDevice->mixer_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ struct SDL_PrivateAudioData
|
||||||
int resume;
|
int resume;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void AndroidAUD_CloseDevice(_THIS);
|
|
||||||
|
|
||||||
#endif /* _SDL_androidaudio_h */
|
#endif /* _SDL_androidaudio_h */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_artsaudio.h"
|
#include "SDL_artsaudio.h"
|
||||||
|
|
||||||
|
@ -203,17 +202,12 @@ ARTS_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
ARTS_CloseDevice(_THIS)
|
ARTS_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->stream) {
|
if (this->hidden->stream) {
|
||||||
SDL_NAME(arts_close_stream) (this->hidden->stream);
|
SDL_NAME(arts_close_stream) (this->hidden->stream);
|
||||||
this->hidden->stream = 0;
|
|
||||||
}
|
}
|
||||||
SDL_NAME(arts_free) ();
|
SDL_NAME(arts_free) ();
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -241,7 +235,7 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||||
|
@ -267,19 +261,16 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
ARTS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
|
||||||
if ((rc = SDL_NAME(arts_init) ()) != 0) {
|
if ((rc = SDL_NAME(arts_init) ()) != 0) {
|
||||||
ARTS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Unable to initialize ARTS: %s",
|
return SDL_SetError("Unable to initialize ARTS: %s",
|
||||||
SDL_NAME(arts_error_text) (rc));
|
SDL_NAME(arts_error_text) (rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ARTS_Suspend()) {
|
if (!ARTS_Suspend()) {
|
||||||
ARTS_CloseDevice(this);
|
|
||||||
return SDL_SetError("ARTS can not open audio device");
|
return SDL_SetError("ARTS can not open audio device");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +288,6 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Determine the power of two of the fragment size */
|
/* Determine the power of two of the fragment size */
|
||||||
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
|
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
|
||||||
if ((0x01 << frag_spec) != this->spec.size) {
|
if ((0x01 << frag_spec) != this->spec.size) {
|
||||||
ARTS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Fragment size must be a power of two");
|
return SDL_SetError("Fragment size must be a power of two");
|
||||||
}
|
}
|
||||||
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
||||||
|
@ -316,9 +306,8 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
ARTS_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_audiodev_c.h"
|
#include "../SDL_audiodev_c.h"
|
||||||
#include "SDL_bsdaudio.h"
|
#include "SDL_bsdaudio.h"
|
||||||
|
@ -63,13 +62,17 @@ BSDAUDIO_Status(_THIS)
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
audio_info_t info;
|
audio_info_t info;
|
||||||
|
const audio_prinfo *prinfo;
|
||||||
|
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||||
fprintf(stderr, "AUDIO_GETINFO failed.\n");
|
fprintf(stderr, "AUDIO_GETINFO failed.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prinfo = this->iscapture ? &info.play : &info.record;
|
||||||
|
|
||||||
fprintf(stderr, "\n"
|
fprintf(stderr, "\n"
|
||||||
"[play/record info]\n"
|
"[%s info]\n"
|
||||||
"buffer size : %d bytes\n"
|
"buffer size : %d bytes\n"
|
||||||
"sample rate : %i Hz\n"
|
"sample rate : %i Hz\n"
|
||||||
"channels : %i\n"
|
"channels : %i\n"
|
||||||
|
@ -83,18 +86,19 @@ BSDAUDIO_Status(_THIS)
|
||||||
"waiting : %s\n"
|
"waiting : %s\n"
|
||||||
"active : %s\n"
|
"active : %s\n"
|
||||||
"",
|
"",
|
||||||
info.play.buffer_size,
|
this->iscapture ? "record" : "play",
|
||||||
info.play.sample_rate,
|
prinfo->buffer_size,
|
||||||
info.play.channels,
|
prinfo->sample_rate,
|
||||||
info.play.precision,
|
prinfo->channels,
|
||||||
info.play.encoding,
|
prinfo->precision,
|
||||||
info.play.seek,
|
prinfo->encoding,
|
||||||
info.play.samples,
|
prinfo->seek,
|
||||||
info.play.eof,
|
prinfo->samples,
|
||||||
info.play.pause ? "yes" : "no",
|
prinfo->eof,
|
||||||
info.play.error ? "yes" : "no",
|
prinfo->pause ? "yes" : "no",
|
||||||
info.play.waiting ? "yes" : "no",
|
prinfo->error ? "yes" : "no",
|
||||||
info.play.active ? "yes" : "no");
|
prinfo->waiting ? "yes" : "no",
|
||||||
|
prinfo->active ? "yes" : "no");
|
||||||
|
|
||||||
fprintf(stderr, "\n"
|
fprintf(stderr, "\n"
|
||||||
"[audio info]\n"
|
"[audio info]\n"
|
||||||
|
@ -182,11 +186,15 @@ BSDAUDIO_PlayDevice(_THIS)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p < written
|
#ifdef DEBUG_AUDIO
|
||||||
|
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (p < this->hidden->mixlen
|
||||||
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
|
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
|
||||||
SDL_Delay(1); /* Let a little CPU time go by */
|
SDL_Delay(1); /* Let a little CPU time go by */
|
||||||
}
|
}
|
||||||
} while (p < written);
|
} while (p < this->hidden->mixlen);
|
||||||
|
|
||||||
/* If timer synchronization is enabled, set the next write frame */
|
/* If timer synchronization is enabled, set the next write frame */
|
||||||
if (this->hidden->frame_ticks) {
|
if (this->hidden->frame_ticks) {
|
||||||
|
@ -197,9 +205,6 @@ BSDAUDIO_PlayDevice(_THIS)
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(this);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
|
||||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
|
@ -208,27 +213,74 @@ BSDAUDIO_GetDeviceBuf(_THIS)
|
||||||
return (this->hidden->mixbuf);
|
return (this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
||||||
|
{
|
||||||
|
Uint8 *buffer = (Uint8 *) _buffer;
|
||||||
|
int br, p = 0;
|
||||||
|
|
||||||
|
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||||
|
do {
|
||||||
|
br = read(this->hidden->audio_fd, buffer + p, buflen - p);
|
||||||
|
if (br > 0)
|
||||||
|
p += br;
|
||||||
|
if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
|
||||||
|
/* Non recoverable error has occurred. It should be reported!!! */
|
||||||
|
perror("audio");
|
||||||
|
return p ? p : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_AUDIO
|
||||||
|
fprintf(stderr, "Captured %d bytes of audio data\n", br);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (p < buflen
|
||||||
|
|| ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
|
||||||
|
SDL_Delay(1); /* Let a little CPU time go by */
|
||||||
|
}
|
||||||
|
} while (p < buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
BSDAUDIO_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
audio_info_t info;
|
||||||
|
size_t remain;
|
||||||
|
Uint8 buf[512];
|
||||||
|
|
||||||
|
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||||
|
return; /* oh well. */
|
||||||
|
}
|
||||||
|
|
||||||
|
remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
|
||||||
|
while (remain > 0) {
|
||||||
|
const size_t len = SDL_min(sizeof (buf), remain);
|
||||||
|
const int br = read(this->hidden->audio_fd, buf, len);
|
||||||
|
if (br <= 0) {
|
||||||
|
return; /* oh well. */
|
||||||
|
}
|
||||||
|
remain -= br;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
BSDAUDIO_CloseDevice(_THIS)
|
BSDAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(this->hidden->audio_fd);
|
||||||
this->hidden->audio_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
|
||||||
SDL_AudioFormat format = 0;
|
SDL_AudioFormat format = 0;
|
||||||
audio_info_t info;
|
audio_info_t info;
|
||||||
|
audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
|
||||||
|
|
||||||
/* We don't care what the devname is...we'll try to open anything. */
|
/* We don't care what the devname is...we'll try to open anything. */
|
||||||
/* ...but default to first name in the list... */
|
/* ...but default to first name in the list... */
|
||||||
|
@ -245,7 +297,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->audio_fd = open(devname, flags, 0);
|
this->hidden->audio_fd = open(devname, flags, 0);
|
||||||
|
@ -259,9 +311,8 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
/* Set to play mode */
|
/* Set to play mode */
|
||||||
info.mode = AUMODE_PLAY;
|
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
|
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
|
||||||
BSDAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't put device into play mode");
|
return SDL_SetError("Couldn't put device into play mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,28 +321,28 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
format; format = SDL_NextAudioFormat()) {
|
format; format = SDL_NextAudioFormat()) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case AUDIO_U8:
|
case AUDIO_U8:
|
||||||
info.play.encoding = AUDIO_ENCODING_ULINEAR;
|
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
|
||||||
info.play.precision = 8;
|
prinfo->precision = 8;
|
||||||
break;
|
break;
|
||||||
case AUDIO_S8:
|
case AUDIO_S8:
|
||||||
info.play.encoding = AUDIO_ENCODING_SLINEAR;
|
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
|
||||||
info.play.precision = 8;
|
prinfo->precision = 8;
|
||||||
break;
|
break;
|
||||||
case AUDIO_S16LSB:
|
case AUDIO_S16LSB:
|
||||||
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
|
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||||
info.play.precision = 16;
|
prinfo->precision = 16;
|
||||||
break;
|
break;
|
||||||
case AUDIO_S16MSB:
|
case AUDIO_S16MSB:
|
||||||
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
|
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
|
||||||
info.play.precision = 16;
|
prinfo->precision = 16;
|
||||||
break;
|
break;
|
||||||
case AUDIO_U16LSB:
|
case AUDIO_U16LSB:
|
||||||
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
|
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
|
||||||
info.play.precision = 16;
|
prinfo->precision = 16;
|
||||||
break;
|
break;
|
||||||
case AUDIO_U16MSB:
|
case AUDIO_U16MSB:
|
||||||
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
|
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
|
||||||
info.play.precision = 16;
|
prinfo->precision = 16;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
|
@ -303,33 +354,34 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format) {
|
if (!format) {
|
||||||
BSDAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
|
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.format = format;
|
this->spec.format = format;
|
||||||
|
|
||||||
AUDIO_INITINFO(&info);
|
AUDIO_INITINFO(&info);
|
||||||
info.play.channels = this->spec.channels;
|
prinfo->channels = this->spec.channels;
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
|
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
|
||||||
this->spec.channels = 1;
|
this->spec.channels = 1;
|
||||||
}
|
}
|
||||||
AUDIO_INITINFO(&info);
|
AUDIO_INITINFO(&info);
|
||||||
info.play.sample_rate = this->spec.freq;
|
prinfo->sample_rate = this->spec.freq;
|
||||||
info.blocksize = this->spec.size;
|
info.blocksize = this->spec.size;
|
||||||
info.hiwat = 5;
|
info.hiwat = 5;
|
||||||
info.lowat = 3;
|
info.lowat = 3;
|
||||||
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
|
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
|
||||||
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
|
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
|
||||||
this->spec.freq = info.play.sample_rate;
|
this->spec.freq = prinfo->sample_rate;
|
||||||
|
|
||||||
|
if (!iscapture) {
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
BSDAUDIO_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
}
|
||||||
|
|
||||||
BSDAUDIO_Status(this);
|
BSDAUDIO_Status(this);
|
||||||
|
|
||||||
|
@ -347,7 +399,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->WaitDevice = BSDAUDIO_WaitDevice;
|
impl->WaitDevice = BSDAUDIO_WaitDevice;
|
||||||
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
|
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
|
||||||
impl->CloseDevice = BSDAUDIO_CloseDevice;
|
impl->CloseDevice = BSDAUDIO_CloseDevice;
|
||||||
|
impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = BSDAUDIO_FlushCapture;
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
impl->AllowsArbitraryDeviceNames = 1;
|
impl->AllowsArbitraryDeviceNames = 1;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#if SDL_AUDIO_DRIVER_COREAUDIO
|
#if SDL_AUDIO_DRIVER_COREAUDIO
|
||||||
|
|
||||||
|
/* !!! FIXME: clean out some of the macro salsa in here. */
|
||||||
|
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
@ -30,11 +32,8 @@
|
||||||
|
|
||||||
#define DEBUG_COREAUDIO 0
|
#define DEBUG_COREAUDIO 0
|
||||||
|
|
||||||
static void COREAUDIO_CloseDevice(_THIS);
|
|
||||||
|
|
||||||
#define CHECK_RESULT(msg) \
|
#define CHECK_RESULT(msg) \
|
||||||
if (result != noErr) { \
|
if (result != noErr) { \
|
||||||
COREAUDIO_CloseDevice(this); \
|
|
||||||
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
||||||
return 0; \
|
return 0; \
|
||||||
}
|
}
|
||||||
|
@ -185,7 +184,7 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
|
||||||
#if DEBUG_COREAUDIO
|
#if DEBUG_COREAUDIO
|
||||||
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
|
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
|
||||||
((iscapture) ? "capture" : "output"),
|
((iscapture) ? "capture" : "output"),
|
||||||
(int) *devCount, ptr, (int) dev);
|
(int) i, ptr, (int) dev);
|
||||||
#endif
|
#endif
|
||||||
addfn(ptr, iscapture, dev, addfndata);
|
addfn(ptr, iscapture, dev, addfndata);
|
||||||
}
|
}
|
||||||
|
@ -268,6 +267,27 @@ device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectP
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static int open_playback_devices = 0;
|
||||||
|
static int open_capture_devices = 0;
|
||||||
|
|
||||||
|
static void update_audio_session()
|
||||||
|
{
|
||||||
|
#if !MACOSX_COREAUDIO
|
||||||
|
/* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */
|
||||||
|
UInt32 category;
|
||||||
|
if (open_playback_devices && open_capture_devices) {
|
||||||
|
category = kAudioSessionCategory_PlayAndRecord;
|
||||||
|
} else if (open_capture_devices) {
|
||||||
|
category = kAudioSessionCategory_RecordAudio;
|
||||||
|
} else { /* nothing open, or just playing audio. */
|
||||||
|
category = kAudioSessionCategory_AmbientSound;
|
||||||
|
}
|
||||||
|
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof (UInt32), &category);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The CoreAudio callback */
|
/* The CoreAudio callback */
|
||||||
static OSStatus
|
static OSStatus
|
||||||
outputCallback(void *inRefCon,
|
outputCallback(void *inRefCon,
|
||||||
|
@ -283,7 +303,7 @@ outputCallback(void *inRefCon,
|
||||||
UInt32 i;
|
UInt32 i;
|
||||||
|
|
||||||
/* Only do anything if audio is enabled and not paused */
|
/* Only do anything if audio is enabled and not paused */
|
||||||
if (!this->enabled || this->paused) {
|
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||||
for (i = 0; i < ioData->mNumberBuffers; i++) {
|
for (i = 0; i < ioData->mNumberBuffers; i++) {
|
||||||
abuf = &ioData->mBuffers[i];
|
abuf = &ioData->mBuffers[i];
|
||||||
SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
|
SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
|
||||||
|
@ -324,18 +344,53 @@ outputCallback(void *inRefCon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus
|
static OSStatus
|
||||||
inputCallback(void *inRefCon,
|
inputCallback(void *inRefCon,
|
||||||
AudioUnitRenderActionFlags * ioActionFlags,
|
AudioUnitRenderActionFlags *ioActionFlags,
|
||||||
const AudioTimeStamp * inTimeStamp,
|
const AudioTimeStamp *inTimeStamp,
|
||||||
UInt32 inBusNumber, UInt32 inNumberFrames,
|
UInt32 inBusNumber, UInt32 inNumberFrames,
|
||||||
AudioBufferList * ioData)
|
AudioBufferList *ioData)
|
||||||
{
|
{
|
||||||
/* err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer); */
|
SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
|
||||||
/* !!! FIXME: write me! */
|
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||||
|
return noErr; /* just drop this if we're not accepting input. */
|
||||||
|
}
|
||||||
|
|
||||||
|
const OSStatus err = AudioUnitRender(this->hidden->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &this->hidden->captureBufferList);
|
||||||
|
SDL_assert(this->hidden->captureBufferList.mNumberBuffers == 1);
|
||||||
|
|
||||||
|
if (err == noErr) {
|
||||||
|
const AudioBuffer *abuf = &this->hidden->captureBufferList.mBuffers[0];
|
||||||
|
UInt32 remaining = abuf->mDataByteSize;
|
||||||
|
const Uint8 *ptr = (const Uint8 *) abuf->mData;
|
||||||
|
|
||||||
|
/* No SDL conversion should be needed here, ever, since we accept
|
||||||
|
any input format in OpenAudio, and leave the conversion to CoreAudio.
|
||||||
|
*/
|
||||||
|
while (remaining > 0) {
|
||||||
|
UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
|
||||||
|
if (len > remaining)
|
||||||
|
len = remaining;
|
||||||
|
|
||||||
|
/* !!! FIXME: why are we copying here? just pass the buffer to the callback? */
|
||||||
|
SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
|
||||||
|
ptr += len;
|
||||||
|
remaining -= len;
|
||||||
|
this->hidden->bufferOffset += len;
|
||||||
|
|
||||||
|
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
||||||
|
SDL_LockMutex(this->mixer_lock);
|
||||||
|
(*this->spec.callback)(this->spec.userdata,
|
||||||
|
this->hidden->buffer, this->hidden->bufferSize);
|
||||||
|
SDL_UnlockMutex(this->mixer_lock);
|
||||||
|
this->hidden->bufferOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +412,7 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty
|
||||||
UInt32 size = sizeof (isAlive);
|
UInt32 size = sizeof (isAlive);
|
||||||
OSStatus error;
|
OSStatus error;
|
||||||
|
|
||||||
if (!this->enabled) {
|
if (!SDL_AtomicGet(&this->enabled)) {
|
||||||
return 0; /* already known to be dead. */
|
return 0; /* already known to be dead. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +436,7 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty
|
||||||
static void
|
static void
|
||||||
COREAUDIO_CloseDevice(_THIS)
|
COREAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
const int iscapture = this->iscapture;
|
||||||
if (this->hidden->audioUnitOpened) {
|
if (this->hidden->audioUnitOpened) {
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
/* Unregister our disconnect callback. */
|
/* Unregister our disconnect callback. */
|
||||||
|
@ -391,28 +446,29 @@ COREAUDIO_CloseDevice(_THIS)
|
||||||
AURenderCallbackStruct callback;
|
AURenderCallbackStruct callback;
|
||||||
const AudioUnitElement output_bus = 0;
|
const AudioUnitElement output_bus = 0;
|
||||||
const AudioUnitElement input_bus = 1;
|
const AudioUnitElement input_bus = 1;
|
||||||
const int iscapture = this->iscapture;
|
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
|
||||||
const AudioUnitElement bus =
|
|
||||||
((iscapture) ? input_bus : output_bus);
|
|
||||||
const AudioUnitScope scope =
|
|
||||||
((iscapture) ? kAudioUnitScope_Output :
|
|
||||||
kAudioUnitScope_Input);
|
|
||||||
|
|
||||||
/* stop processing the audio unit */
|
/* stop processing the audio unit */
|
||||||
AudioOutputUnitStop(this->hidden->audioUnit);
|
AudioOutputUnitStop(this->hidden->audioUnit);
|
||||||
|
|
||||||
/* Remove the input callback */
|
/* Remove the input callback */
|
||||||
SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct));
|
SDL_zero(callback);
|
||||||
AudioUnitSetProperty(this->hidden->audioUnit,
|
AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
kAudioUnitProperty_SetRenderCallback,
|
iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback,
|
||||||
scope, bus, &callback, sizeof(callback));
|
kAudioUnitScope_Global, bus, &callback, sizeof(callback));
|
||||||
AudioComponentInstanceDispose(this->hidden->audioUnit);
|
AudioComponentInstanceDispose(this->hidden->audioUnit);
|
||||||
this->hidden->audioUnitOpened = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(this->hidden->captureBufferList.mBuffers[0].mData);
|
||||||
SDL_free(this->hidden->buffer);
|
SDL_free(this->hidden->buffer);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
|
if (iscapture) {
|
||||||
|
open_capture_devices--;
|
||||||
|
} else {
|
||||||
|
open_playback_devices--;
|
||||||
}
|
}
|
||||||
|
update_audio_session();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
|
@ -480,9 +536,6 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
AudioComponent comp = NULL;
|
AudioComponent comp = NULL;
|
||||||
const AudioUnitElement output_bus = 0;
|
const AudioUnitElement output_bus = 0;
|
||||||
const AudioUnitElement input_bus = 1;
|
const AudioUnitElement input_bus = 1;
|
||||||
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
|
|
||||||
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
|
|
||||||
kAudioUnitScope_Input);
|
|
||||||
|
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
if (!prepare_device(this, handle, iscapture)) {
|
if (!prepare_device(this, handle, iscapture)) {
|
||||||
|
@ -495,7 +548,7 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||||
|
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
desc.componentSubType = iscapture ? kAudioUnitSubType_HALOutput : kAudioUnitSubType_DefaultOutput;
|
||||||
#else
|
#else
|
||||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||||
#endif
|
#endif
|
||||||
|
@ -512,10 +565,29 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
|
|
||||||
this->hidden->audioUnitOpened = 1;
|
this->hidden->audioUnitOpened = 1;
|
||||||
|
|
||||||
|
if (iscapture) { /* have to do EnableIO only for capture devices. */
|
||||||
|
UInt32 enable = 1;
|
||||||
|
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
|
kAudioOutputUnitProperty_EnableIO,
|
||||||
|
kAudioUnitScope_Input, input_bus,
|
||||||
|
&enable, sizeof (enable));
|
||||||
|
CHECK_RESULT
|
||||||
|
("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO input bus)");
|
||||||
|
|
||||||
|
enable = 0;
|
||||||
|
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
|
kAudioOutputUnitProperty_EnableIO,
|
||||||
|
kAudioUnitScope_Output, output_bus,
|
||||||
|
&enable, sizeof (enable));
|
||||||
|
CHECK_RESULT
|
||||||
|
("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO output bus)");
|
||||||
|
}
|
||||||
|
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
|
/* this is always on the output_bus, even for capture devices. */
|
||||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
kAudioOutputUnitProperty_CurrentDevice,
|
kAudioOutputUnitProperty_CurrentDevice,
|
||||||
kAudioUnitScope_Global, 0,
|
kAudioUnitScope_Global, output_bus,
|
||||||
&this->hidden->deviceID,
|
&this->hidden->deviceID,
|
||||||
sizeof(AudioDeviceID));
|
sizeof(AudioDeviceID));
|
||||||
CHECK_RESULT
|
CHECK_RESULT
|
||||||
|
@ -525,16 +597,45 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
/* Set the data format of the audio unit. */
|
/* Set the data format of the audio unit. */
|
||||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
kAudioUnitProperty_StreamFormat,
|
kAudioUnitProperty_StreamFormat,
|
||||||
scope, bus, strdesc, sizeof(*strdesc));
|
iscapture ? kAudioUnitScope_Output : kAudioUnitScope_Input,
|
||||||
|
iscapture ? input_bus : output_bus,
|
||||||
|
strdesc, sizeof (*strdesc));
|
||||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
|
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
|
||||||
|
|
||||||
|
if (iscapture) { /* only need to do this for capture devices. */
|
||||||
|
void *ptr;
|
||||||
|
UInt32 framesize = 0;
|
||||||
|
UInt32 propsize = sizeof (UInt32);
|
||||||
|
|
||||||
|
result = AudioUnitGetProperty(this->hidden->audioUnit,
|
||||||
|
kAudioUnitProperty_MaximumFramesPerSlice,
|
||||||
|
kAudioUnitScope_Global, output_bus,
|
||||||
|
&framesize, &propsize);
|
||||||
|
CHECK_RESULT
|
||||||
|
("AudioUnitGetProperty (kAudioDevicePropertyBufferFrameSize)");
|
||||||
|
|
||||||
|
framesize *= SDL_AUDIO_BITSIZE(this->spec.format) / 8;
|
||||||
|
ptr = SDL_calloc(1, framesize);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
this->hidden->captureBufferList.mNumberBuffers = 1;
|
||||||
|
this->hidden->captureBufferList.mBuffers[0].mNumberChannels = this->spec.channels;
|
||||||
|
this->hidden->captureBufferList.mBuffers[0].mDataByteSize = framesize;
|
||||||
|
this->hidden->captureBufferList.mBuffers[0].mData = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the audio callback */
|
/* Set the audio callback */
|
||||||
SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct));
|
SDL_zero(callback);
|
||||||
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
|
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
|
||||||
callback.inputProcRefCon = this;
|
callback.inputProcRefCon = this;
|
||||||
|
|
||||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||||
kAudioUnitProperty_SetRenderCallback,
|
iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback,
|
||||||
scope, bus, &callback, sizeof(callback));
|
kAudioUnitScope_Global,
|
||||||
|
iscapture ? input_bus : output_bus,
|
||||||
|
&callback, sizeof (callback));
|
||||||
CHECK_RESULT
|
CHECK_RESULT
|
||||||
("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
|
("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
|
||||||
|
|
||||||
|
@ -542,8 +643,14 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
/* Allocate a sample buffer */
|
/* Allocate a sample buffer */
|
||||||
this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
|
this->hidden->bufferSize = this->spec.size;
|
||||||
|
this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
|
||||||
|
|
||||||
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
|
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
|
||||||
|
if (this->hidden->buffer == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
result = AudioUnitInitialize(this->hidden->audioUnit);
|
result = AudioUnitInitialize(this->hidden->audioUnit);
|
||||||
CHECK_RESULT("AudioUnitInitialize");
|
CHECK_RESULT("AudioUnitInitialize");
|
||||||
|
@ -552,6 +659,8 @@ prepare_audiounit(_THIS, void *handle, int iscapture,
|
||||||
result = AudioOutputUnitStart(this->hidden->audioUnit);
|
result = AudioOutputUnitStart(this->hidden->audioUnit);
|
||||||
CHECK_RESULT("AudioOutputUnitStart");
|
CHECK_RESULT("AudioOutputUnitStart");
|
||||||
|
|
||||||
|
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
||||||
|
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||||
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||||
|
@ -575,10 +684,17 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
|
if (iscapture) {
|
||||||
|
open_capture_devices++;
|
||||||
|
} else {
|
||||||
|
open_playback_devices++;
|
||||||
|
}
|
||||||
|
update_audio_session();
|
||||||
|
|
||||||
/* Setup a AudioStreamBasicDescription with the requested format */
|
/* Setup a AudioStreamBasicDescription with the requested format */
|
||||||
SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
|
SDL_zero(strdesc);
|
||||||
strdesc.mFormatID = kAudioFormatLinearPCM;
|
strdesc.mFormatID = kAudioFormatLinearPCM;
|
||||||
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||||
strdesc.mChannelsPerFrame = this->spec.channels;
|
strdesc.mChannelsPerFrame = this->spec.channels;
|
||||||
|
@ -613,7 +729,6 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||||
COREAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Unsupported audio format");
|
return SDL_SetError("Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +738,6 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
|
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
|
||||||
|
|
||||||
if (!prepare_audiounit(this, handle, iscapture, &strdesc)) {
|
if (!prepare_audiounit(this, handle, iscapture, &strdesc)) {
|
||||||
COREAUDIO_CloseDevice(this);
|
|
||||||
return -1; /* prepare_audiounit() will call SDL_SetError()... */
|
return -1; /* prepare_audiounit() will call SDL_SetError()... */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,17 +767,20 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
|
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
|
||||||
#else
|
#else
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||||
|
|
||||||
/* Set category to ambient sound so that other music continues playing.
|
/* Set category to ambient sound so that other music continues playing.
|
||||||
You can change this at runtime in your own code if you need different
|
You can change this at runtime in your own code if you need different
|
||||||
behavior. If this is common, we can add an SDL hint for this.
|
behavior. If this is common, we can add an SDL hint for this.
|
||||||
*/
|
*/
|
||||||
|
/* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */
|
||||||
AudioSessionInitialize(NULL, NULL, NULL, nil);
|
AudioSessionInitialize(NULL, NULL, NULL, nil);
|
||||||
UInt32 category = kAudioSessionCategory_AmbientSound;
|
UInt32 category = kAudioSessionCategory_AmbientSound;
|
||||||
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category);
|
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
impl->ProvidesOwnCallbackThread = 1;
|
impl->ProvidesOwnCallbackThread = 1;
|
||||||
|
impl->HasCaptureSupport = 1;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct SDL_PrivateAudioData
|
||||||
void *buffer;
|
void *buffer;
|
||||||
UInt32 bufferOffset;
|
UInt32 bufferOffset;
|
||||||
UInt32 bufferSize;
|
UInt32 bufferSize;
|
||||||
|
AudioBufferList captureBufferList;
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
AudioDeviceID deviceID;
|
AudioDeviceID deviceID;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
/* Allow access to a raw mixing buffer */
|
/* Allow access to a raw mixing buffer */
|
||||||
|
|
||||||
|
#include "SDL_assert.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_loadso.h"
|
#include "SDL_loadso.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
|
@ -36,11 +37,13 @@
|
||||||
|
|
||||||
/* DirectX function pointers for audio */
|
/* DirectX function pointers for audio */
|
||||||
static void* DSoundDLL = NULL;
|
static void* DSoundDLL = NULL;
|
||||||
typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
|
typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
|
||||||
typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
|
typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
|
||||||
typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
|
typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN);
|
||||||
|
typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
|
||||||
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
|
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
|
||||||
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
|
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
|
||||||
|
static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
|
||||||
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
|
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -48,6 +51,7 @@ DSOUND_Unload(void)
|
||||||
{
|
{
|
||||||
pDirectSoundCreate8 = NULL;
|
pDirectSoundCreate8 = NULL;
|
||||||
pDirectSoundEnumerateW = NULL;
|
pDirectSoundEnumerateW = NULL;
|
||||||
|
pDirectSoundCaptureCreate8 = NULL;
|
||||||
pDirectSoundCaptureEnumerateW = NULL;
|
pDirectSoundCaptureEnumerateW = NULL;
|
||||||
|
|
||||||
if (DSoundDLL != NULL) {
|
if (DSoundDLL != NULL) {
|
||||||
|
@ -76,6 +80,7 @@ DSOUND_Load(void)
|
||||||
loaded = 1; /* will reset if necessary. */
|
loaded = 1; /* will reset if necessary. */
|
||||||
DSOUNDLOAD(DirectSoundCreate8);
|
DSOUNDLOAD(DirectSoundCreate8);
|
||||||
DSOUNDLOAD(DirectSoundEnumerateW);
|
DSOUNDLOAD(DirectSoundEnumerateW);
|
||||||
|
DSOUNDLOAD(DirectSoundCaptureCreate8);
|
||||||
DSOUNDLOAD(DirectSoundCaptureEnumerateW);
|
DSOUNDLOAD(DirectSoundCaptureEnumerateW);
|
||||||
#undef DSOUNDLOAD
|
#undef DSOUNDLOAD
|
||||||
|
|
||||||
|
@ -155,7 +160,7 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
|
||||||
{
|
{
|
||||||
const int iscapture = (int) ((size_t) data);
|
const int iscapture = (int) ((size_t) data);
|
||||||
if (guid != NULL) { /* skip default device */
|
if (guid != NULL) { /* skip default device */
|
||||||
char *str = WIN_StringToUTF8(desc);
|
char *str = WIN_LookupAudioDeviceName(desc, guid);
|
||||||
if (str != NULL) {
|
if (str != NULL) {
|
||||||
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
|
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
|
||||||
SDL_memcpy(cpyguid, guid, sizeof (GUID));
|
SDL_memcpy(cpyguid, guid, sizeof (GUID));
|
||||||
|
@ -197,7 +202,7 @@ DSOUND_WaitDevice(_THIS)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
|
while ((cursor / this->spec.size) == this->hidden->lastchunk) {
|
||||||
/* FIXME: find out how much time is left and sleep that long */
|
/* FIXME: find out how much time is left and sleep that long */
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
|
|
||||||
|
@ -239,9 +244,8 @@ DSOUND_PlayDevice(_THIS)
|
||||||
if (this->hidden->locked_buf) {
|
if (this->hidden->locked_buf) {
|
||||||
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
|
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
|
||||||
this->hidden->locked_buf,
|
this->hidden->locked_buf,
|
||||||
this->hidden->mixlen, NULL, 0);
|
this->spec.size, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
|
@ -265,7 +269,7 @@ DSOUND_GetDeviceBuf(_THIS)
|
||||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
cursor /= this->hidden->mixlen;
|
cursor /= this->spec.size;
|
||||||
#ifdef DEBUG_SOUND
|
#ifdef DEBUG_SOUND
|
||||||
/* Detect audio dropouts */
|
/* Detect audio dropouts */
|
||||||
{
|
{
|
||||||
|
@ -281,17 +285,17 @@ DSOUND_GetDeviceBuf(_THIS)
|
||||||
#endif
|
#endif
|
||||||
this->hidden->lastchunk = cursor;
|
this->hidden->lastchunk = cursor;
|
||||||
cursor = (cursor + 1) % this->hidden->num_buffers;
|
cursor = (cursor + 1) % this->hidden->num_buffers;
|
||||||
cursor *= this->hidden->mixlen;
|
cursor *= this->spec.size;
|
||||||
|
|
||||||
/* Lock the audio buffer */
|
/* Lock the audio buffer */
|
||||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
||||||
this->hidden->mixlen,
|
this->spec.size,
|
||||||
(LPVOID *) & this->hidden->locked_buf,
|
(LPVOID *) & this->hidden->locked_buf,
|
||||||
&rawlen, NULL, &junk, 0);
|
&rawlen, NULL, &junk, 0);
|
||||||
if (result == DSERR_BUFFERLOST) {
|
if (result == DSERR_BUFFERLOST) {
|
||||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
||||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
||||||
this->hidden->mixlen,
|
this->spec.size,
|
||||||
(LPVOID *) & this->
|
(LPVOID *) & this->
|
||||||
hidden->locked_buf, &rawlen, NULL,
|
hidden->locked_buf, &rawlen, NULL,
|
||||||
&junk, 0);
|
&junk, 0);
|
||||||
|
@ -310,7 +314,7 @@ DSOUND_WaitDone(_THIS)
|
||||||
|
|
||||||
/* Wait for the playing chunk to finish */
|
/* Wait for the playing chunk to finish */
|
||||||
if (stream != NULL) {
|
if (stream != NULL) {
|
||||||
SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
|
SDL_memset(stream, this->spec.silence, this->spec.size);
|
||||||
DSOUND_PlayDevice(this);
|
DSOUND_PlayDevice(this);
|
||||||
}
|
}
|
||||||
DSOUND_WaitDevice(this);
|
DSOUND_WaitDevice(this);
|
||||||
|
@ -319,93 +323,106 @@ DSOUND_WaitDone(_THIS)
|
||||||
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
|
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
DSOUND_CloseDevice(_THIS)
|
DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
if (this->hidden->sound != NULL) {
|
DWORD junk, cursor, ptr1len, ptr2len;
|
||||||
if (this->hidden->mixbuf != NULL) {
|
VOID *ptr1, *ptr2;
|
||||||
/* Clean up the audio buffer */
|
|
||||||
IDirectSoundBuffer_Release(this->hidden->mixbuf);
|
SDL_assert(buflen == this->spec.size);
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
}
|
while (SDL_TRUE) {
|
||||||
IDirectSound_Release(this->hidden->sound);
|
if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */
|
||||||
this->hidden->sound = NULL;
|
SDL_memset(buffer, this->spec.silence, buflen);
|
||||||
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
|
||||||
this->hidden = NULL;
|
return -1;
|
||||||
|
}
|
||||||
|
if ((cursor / this->spec.size) == h->lastchunk) {
|
||||||
|
SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(ptr1len == this->spec.size);
|
||||||
|
SDL_assert(ptr2 == NULL);
|
||||||
|
SDL_assert(ptr2len == 0);
|
||||||
|
|
||||||
|
SDL_memcpy(buffer, ptr1, ptr1len);
|
||||||
|
|
||||||
|
if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->lastchunk = (h->lastchunk + 1) % h->num_buffers;
|
||||||
|
|
||||||
|
return ptr1len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DSOUND_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
DWORD junk, cursor;
|
||||||
|
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
|
||||||
|
h->lastchunk = cursor / this->spec.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DSOUND_CloseDevice(_THIS)
|
||||||
|
{
|
||||||
|
if (this->hidden->mixbuf != NULL) {
|
||||||
|
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
|
||||||
|
IDirectSoundBuffer_Release(this->hidden->mixbuf);
|
||||||
|
}
|
||||||
|
if (this->hidden->sound != NULL) {
|
||||||
|
IDirectSound_Release(this->hidden->sound);
|
||||||
|
}
|
||||||
|
if (this->hidden->capturebuf != NULL) {
|
||||||
|
IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
|
||||||
|
IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
|
||||||
|
}
|
||||||
|
if (this->hidden->capture != NULL) {
|
||||||
|
IDirectSoundCapture_Release(this->hidden->capture);
|
||||||
|
}
|
||||||
|
SDL_free(this->hidden);
|
||||||
|
}
|
||||||
|
|
||||||
/* This function tries to create a secondary audio buffer, and returns the
|
/* This function tries to create a secondary audio buffer, and returns the
|
||||||
number of audio chunks available in the created buffer.
|
number of audio chunks available in the created buffer. This is for
|
||||||
|
playback devices, not capture.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
CreateSecondary(_THIS, HWND focus)
|
CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
{
|
{
|
||||||
LPDIRECTSOUND sndObj = this->hidden->sound;
|
LPDIRECTSOUND sndObj = this->hidden->sound;
|
||||||
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
|
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
|
||||||
Uint32 chunksize = this->spec.size;
|
|
||||||
const int numchunks = 8;
|
|
||||||
HRESULT result = DS_OK;
|
HRESULT result = DS_OK;
|
||||||
DSBUFFERDESC format;
|
DSBUFFERDESC format;
|
||||||
LPVOID pvAudioPtr1, pvAudioPtr2;
|
LPVOID pvAudioPtr1, pvAudioPtr2;
|
||||||
DWORD dwAudioBytes1, dwAudioBytes2;
|
DWORD dwAudioBytes1, dwAudioBytes2;
|
||||||
WAVEFORMATEX wfmt;
|
|
||||||
|
|
||||||
SDL_zero(wfmt);
|
|
||||||
|
|
||||||
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
|
|
||||||
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
|
||||||
} else {
|
|
||||||
wfmt.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
}
|
|
||||||
|
|
||||||
wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
|
||||||
wfmt.nChannels = this->spec.channels;
|
|
||||||
wfmt.nSamplesPerSec = this->spec.freq;
|
|
||||||
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
|
|
||||||
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
|
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
|
||||||
|
|
||||||
/* Try to set primary mixing privileges */
|
|
||||||
if (focus) {
|
|
||||||
result = IDirectSound_SetCooperativeLevel(sndObj,
|
|
||||||
focus, DSSCL_PRIORITY);
|
|
||||||
} else {
|
|
||||||
result = IDirectSound_SetCooperativeLevel(sndObj,
|
|
||||||
GetDesktopWindow(),
|
|
||||||
DSSCL_NORMAL);
|
|
||||||
}
|
|
||||||
if (result != DS_OK) {
|
|
||||||
return SetDSerror("DirectSound SetCooperativeLevel", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to create the secondary buffer */
|
/* Try to create the secondary buffer */
|
||||||
SDL_zero(format);
|
SDL_zero(format);
|
||||||
format.dwSize = sizeof(format);
|
format.dwSize = sizeof(format);
|
||||||
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
|
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
|
||||||
if (!focus) {
|
|
||||||
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
||||||
} else {
|
format.dwBufferBytes = bufsize;
|
||||||
format.dwFlags |= DSBCAPS_STICKYFOCUS;
|
format.lpwfxFormat = wfmt;
|
||||||
}
|
|
||||||
format.dwBufferBytes = numchunks * chunksize;
|
|
||||||
if ((format.dwBufferBytes < DSBSIZE_MIN) ||
|
|
||||||
(format.dwBufferBytes > DSBSIZE_MAX)) {
|
|
||||||
return SDL_SetError("Sound buffer size must be between %d and %d",
|
|
||||||
DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
|
|
||||||
}
|
|
||||||
format.dwReserved = 0;
|
|
||||||
format.lpwfxFormat = &wfmt;
|
|
||||||
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
|
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
return SetDSerror("DirectSound CreateSoundBuffer", result);
|
return SetDSerror("DirectSound CreateSoundBuffer", result);
|
||||||
}
|
}
|
||||||
IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
|
IDirectSoundBuffer_SetFormat(*sndbuf, wfmt);
|
||||||
|
|
||||||
/* Silence the initial audio buffer */
|
/* Silence the initial audio buffer */
|
||||||
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
|
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
|
||||||
|
@ -420,17 +437,64 @@ CreateSecondary(_THIS, HWND focus)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're ready to go */
|
/* We're ready to go */
|
||||||
return (numchunks);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function tries to create a capture buffer, and returns the
|
||||||
|
number of audio chunks available in the created buffer. This is for
|
||||||
|
capture devices, not playback.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
|
{
|
||||||
|
LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
|
||||||
|
LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
|
||||||
|
DSCBUFFERDESC format;
|
||||||
|
// DWORD junk, cursor;
|
||||||
|
HRESULT result;
|
||||||
|
|
||||||
|
SDL_zero(format);
|
||||||
|
format.dwSize = sizeof (format);
|
||||||
|
format.dwFlags = DSCBCAPS_WAVEMAPPED;
|
||||||
|
format.dwBufferBytes = bufsize;
|
||||||
|
format.lpwfxFormat = wfmt;
|
||||||
|
|
||||||
|
result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
|
||||||
|
if (result != DS_OK) {
|
||||||
|
return SetDSerror("DirectSound CreateCaptureBuffer", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
|
||||||
|
if (result != DS_OK) {
|
||||||
|
IDirectSoundCaptureBuffer_Release(*capturebuf);
|
||||||
|
return SetDSerror("DirectSound Start", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* presumably this starts at zero, but just in case... */
|
||||||
|
result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
|
||||||
|
if (result != DS_OK) {
|
||||||
|
IDirectSoundCaptureBuffer_Stop(*capturebuf);
|
||||||
|
IDirectSoundCaptureBuffer_Release(*capturebuf);
|
||||||
|
return SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->hidden->lastchunk = cursor / this->spec.size;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
|
const DWORD numchunks = 8;
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
SDL_bool valid_format = SDL_FALSE;
|
SDL_bool valid_format = SDL_FALSE;
|
||||||
SDL_bool tried_format = SDL_FALSE;
|
SDL_bool tried_format = SDL_FALSE;
|
||||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||||
LPGUID guid = (LPGUID) handle;
|
LPGUID guid = (LPGUID) handle;
|
||||||
|
DWORD bufsize;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
|
@ -438,13 +502,25 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
|
if (iscapture) {
|
||||||
|
result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
|
||||||
|
if (result != DS_OK) {
|
||||||
|
return SetDSerror("DirectSoundCaptureCreate8", result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
|
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
DSOUND_CloseDevice(this);
|
return SetDSerror("DirectSoundCreate8", result);
|
||||||
return SetDSerror("DirectSoundCreate", result);
|
}
|
||||||
|
result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
|
||||||
|
GetDesktopWindow(),
|
||||||
|
DSSCL_NORMAL);
|
||||||
|
if (result != DS_OK) {
|
||||||
|
return SetDSerror("DirectSound SetCooperativeLevel", result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((!valid_format) && (test_format)) {
|
while ((!valid_format) && (test_format)) {
|
||||||
|
@ -454,26 +530,52 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
case AUDIO_S32:
|
case AUDIO_S32:
|
||||||
case AUDIO_F32:
|
case AUDIO_F32:
|
||||||
tried_format = SDL_TRUE;
|
tried_format = SDL_TRUE;
|
||||||
|
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
this->hidden->num_buffers = CreateSecondary(this, NULL);
|
|
||||||
if (this->hidden->num_buffers > 0) {
|
/* Update the fragment size as size in bytes */
|
||||||
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
|
bufsize = numchunks * this->spec.size;
|
||||||
|
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
|
||||||
|
SDL_SetError("Sound buffer size must be between %d and %d",
|
||||||
|
(DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks,
|
||||||
|
DSBSIZE_MAX / numchunks);
|
||||||
|
} else {
|
||||||
|
int rc;
|
||||||
|
WAVEFORMATEX wfmt;
|
||||||
|
SDL_zero(wfmt);
|
||||||
|
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
|
||||||
|
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||||
|
} else {
|
||||||
|
wfmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
}
|
||||||
|
|
||||||
|
wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||||
|
wfmt.nChannels = this->spec.channels;
|
||||||
|
wfmt.nSamplesPerSec = this->spec.freq;
|
||||||
|
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
|
||||||
|
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
|
||||||
|
|
||||||
|
rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
|
||||||
|
if (rc == 0) {
|
||||||
|
this->hidden->num_buffers = numchunks;
|
||||||
valid_format = SDL_TRUE;
|
valid_format = SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
test_format = SDL_NextAudioFormat();
|
test_format = SDL_NextAudioFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_format) {
|
if (!valid_format) {
|
||||||
DSOUND_CloseDevice(this);
|
|
||||||
if (tried_format) {
|
if (tried_format) {
|
||||||
return -1; /* CreateSecondary() should have called SDL_SetError(). */
|
return -1; /* CreateSecondary() should have called SDL_SetError(). */
|
||||||
}
|
}
|
||||||
return SDL_SetError("DirectSound: Unsupported audio format");
|
return SDL_SetError("DirectSound: Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
|
/* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
|
||||||
this->hidden->mixlen = this->spec.size;
|
|
||||||
|
|
||||||
return 0; /* good to go. */
|
return 0; /* good to go. */
|
||||||
}
|
}
|
||||||
|
@ -500,11 +602,14 @@ DSOUND_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->WaitDevice = DSOUND_WaitDevice;
|
impl->WaitDevice = DSOUND_WaitDevice;
|
||||||
impl->WaitDone = DSOUND_WaitDone;
|
impl->WaitDone = DSOUND_WaitDone;
|
||||||
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
|
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
|
||||||
|
impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = DSOUND_FlushCapture;
|
||||||
impl->CloseDevice = DSOUND_CloseDevice;
|
impl->CloseDevice = DSOUND_CloseDevice;
|
||||||
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
|
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
|
||||||
|
|
||||||
impl->Deinitialize = DSOUND_Deinitialize;
|
impl->Deinitialize = DSOUND_Deinitialize;
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,9 @@ struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
LPDIRECTSOUND sound;
|
LPDIRECTSOUND sound;
|
||||||
LPDIRECTSOUNDBUFFER mixbuf;
|
LPDIRECTSOUNDBUFFER mixbuf;
|
||||||
|
LPDIRECTSOUNDCAPTURE capture;
|
||||||
|
LPDIRECTSOUNDCAPTUREBUFFER capturebuf;
|
||||||
int num_buffers;
|
int num_buffers;
|
||||||
int mixlen;
|
|
||||||
DWORD lastchunk;
|
DWORD lastchunk;
|
||||||
Uint8 *locked_buf;
|
Uint8 *locked_buf;
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,46 +31,33 @@
|
||||||
#include "SDL_rwops.h"
|
#include "SDL_rwops.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_diskaudio.h"
|
#include "SDL_diskaudio.h"
|
||||||
|
|
||||||
|
/* !!! FIXME: these should be SDL hints, not environment variables. */
|
||||||
/* environment variables and defaults. */
|
/* environment variables and defaults. */
|
||||||
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
|
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
|
||||||
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
|
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
|
||||||
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
|
#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN"
|
||||||
#define DISKDEFAULT_WRITEDELAY 150
|
#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
|
||||||
|
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
|
||||||
static const char *
|
|
||||||
DISKAUD_GetOutputFilename(const char *devname)
|
|
||||||
{
|
|
||||||
if (devname == NULL) {
|
|
||||||
devname = SDL_getenv(DISKENVR_OUTFILE);
|
|
||||||
if (devname == NULL) {
|
|
||||||
devname = DISKDEFAULT_OUTFILE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return devname;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void
|
static void
|
||||||
DISKAUD_WaitDevice(_THIS)
|
DISKAUDIO_WaitDevice(_THIS)
|
||||||
{
|
{
|
||||||
SDL_Delay(this->hidden->write_delay);
|
SDL_Delay(this->hidden->io_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DISKAUD_PlayDevice(_THIS)
|
DISKAUDIO_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
size_t written;
|
const size_t written = SDL_RWwrite(this->hidden->io,
|
||||||
|
this->hidden->mixbuf,
|
||||||
/* Write the audio data */
|
1, this->spec.size);
|
||||||
written = SDL_RWwrite(this->hidden->output,
|
|
||||||
this->hidden->mixbuf, 1, this->hidden->mixlen);
|
|
||||||
|
|
||||||
/* If we couldn't write, assume fatal error for now */
|
/* If we couldn't write, assume fatal error for now */
|
||||||
if (written != this->hidden->mixlen) {
|
if (written != this->spec.size) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(this);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
|
@ -79,63 +66,105 @@ DISKAUD_PlayDevice(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
DISKAUD_GetDeviceBuf(_THIS)
|
DISKAUDIO_GetDeviceBuf(_THIS)
|
||||||
{
|
{
|
||||||
return (this->hidden->mixbuf);
|
return (this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
DISKAUD_CloseDevice(_THIS)
|
DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
const int origbuflen = buflen;
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->output != NULL) {
|
SDL_Delay(h->io_delay);
|
||||||
SDL_RWclose(this->hidden->output);
|
|
||||||
this->hidden->output = NULL;
|
if (h->io) {
|
||||||
|
const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
|
||||||
|
buflen -= (int) br;
|
||||||
|
buffer = ((Uint8 *) buffer) + br;
|
||||||
|
if (buflen > 0) { /* EOF (or error, but whatever). */
|
||||||
|
SDL_RWclose(h->io);
|
||||||
|
h->io = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we ran out of file, just write silence. */
|
||||||
|
SDL_memset(buffer, this->spec.silence, buflen);
|
||||||
|
|
||||||
|
return origbuflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DISKAUDIO_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
/* no op...we don't advance the file pointer or anything. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
DISKAUDIO_CloseDevice(_THIS)
|
||||||
|
{
|
||||||
|
if (this->hidden->io != NULL) {
|
||||||
|
SDL_RWclose(this->hidden->io);
|
||||||
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_filename(const int iscapture, const char *devname)
|
||||||
|
{
|
||||||
|
if (devname == NULL) {
|
||||||
|
devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
|
||||||
|
if (devname == NULL) {
|
||||||
|
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return devname;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
|
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
|
||||||
const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname);
|
const char *fname = get_filename(iscapture, handle ? NULL : devname);
|
||||||
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
|
const char *envr = SDL_getenv(DISKENVR_IODELAY);
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc(sizeof(*this->hidden));
|
SDL_malloc(sizeof(*this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
this->hidden->mixlen = this->spec.size;
|
if (envr != NULL) {
|
||||||
this->hidden->write_delay =
|
this->hidden->io_delay = SDL_atoi(envr);
|
||||||
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
|
} else {
|
||||||
|
this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->output = SDL_RWFromFile(fname, "wb");
|
this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
|
||||||
if (this->hidden->output == NULL) {
|
if (this->hidden->io == NULL) {
|
||||||
DISKAUD_CloseDevice(this);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
if (!iscapture) {
|
||||||
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
DISKAUD_CloseDevice(this);
|
return SDL_OutOfMemory();
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
}
|
||||||
|
|
||||||
#if HAVE_STDIO_H
|
#if HAVE_STDIO_H
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"WARNING: You are using the SDL disk writer audio driver!\n"
|
"WARNING: You are using the SDL disk i/o audio driver!\n"
|
||||||
" Writing to file [%s].\n", fname);
|
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
|
||||||
|
fname);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We're ready to rock and roll. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
|
@ -143,30 +172,34 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DISKAUD_DetectDevices(void)
|
DISKAUDIO_DetectDevices(void)
|
||||||
{
|
{
|
||||||
/* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */
|
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
|
||||||
SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1);
|
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DISKAUD_Init(SDL_AudioDriverImpl * impl)
|
DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = DISKAUD_OpenDevice;
|
impl->OpenDevice = DISKAUDIO_OpenDevice;
|
||||||
impl->WaitDevice = DISKAUD_WaitDevice;
|
impl->WaitDevice = DISKAUDIO_WaitDevice;
|
||||||
impl->PlayDevice = DISKAUD_PlayDevice;
|
impl->PlayDevice = DISKAUDIO_PlayDevice;
|
||||||
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
|
impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
|
||||||
impl->CloseDevice = DISKAUD_CloseDevice;
|
impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
|
||||||
impl->DetectDevices = DISKAUD_DetectDevices;
|
impl->FlushCapture = DISKAUDIO_FlushCapture;
|
||||||
|
|
||||||
|
impl->CloseDevice = DISKAUDIO_CloseDevice;
|
||||||
|
impl->DetectDevices = DISKAUDIO_DetectDevices;
|
||||||
|
|
||||||
impl->AllowsArbitraryDeviceNames = 1;
|
impl->AllowsArbitraryDeviceNames = 1;
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap DISKAUD_bootstrap = {
|
AudioBootStrap DISKAUDIO_bootstrap = {
|
||||||
"disk", "direct-to-disk audio", DISKAUD_Init, 1
|
"disk", "direct-to-disk audio", DISKAUDIO_Init, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SDL_AUDIO_DRIVER_DISK */
|
#endif /* SDL_AUDIO_DRIVER_DISK */
|
||||||
|
|
|
@ -32,10 +32,9 @@
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
SDL_RWops *output;
|
SDL_RWops *io;
|
||||||
|
Uint32 io_delay;
|
||||||
Uint8 *mixbuf;
|
Uint8 *mixbuf;
|
||||||
Uint32 mixlen;
|
|
||||||
Uint32 write_delay;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _SDL_diskaudio_h */
|
#endif /* _SDL_diskaudio_h */
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_audiodev_c.h"
|
#include "../SDL_audiodev_c.h"
|
||||||
#include "SDL_dspaudio.h"
|
#include "SDL_dspaudio.h"
|
||||||
|
@ -60,16 +59,11 @@ DSP_DetectDevices(void)
|
||||||
static void
|
static void
|
||||||
DSP_CloseDevice(_THIS)
|
DSP_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(this->hidden->audio_fd);
|
||||||
this->hidden->audio_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,23 +100,20 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->audio_fd = open(devname, flags, 0);
|
this->hidden->audio_fd = open(devname, flags, 0);
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (this->hidden->audio_fd < 0) {
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||||
}
|
}
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
|
|
||||||
/* Make the file descriptor use blocking writes with fcntl() */
|
/* Make the file descriptor use blocking i/o with fcntl() */
|
||||||
{
|
{
|
||||||
long ctlflags;
|
long ctlflags;
|
||||||
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
|
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
|
||||||
ctlflags &= ~O_NONBLOCK;
|
ctlflags &= ~O_NONBLOCK;
|
||||||
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
|
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set audio blocking mode");
|
return SDL_SetError("Couldn't set audio blocking mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +121,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Get a list of supported hardware formats */
|
/* Get a list of supported hardware formats */
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_GETFMTS");
|
perror("SNDCTL_DSP_GETFMTS");
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't get audio format list");
|
return SDL_SetError("Couldn't get audio format list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +177,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
@ -197,7 +186,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
|
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
|
||||||
(value != format)) {
|
(value != format)) {
|
||||||
perror("SNDCTL_DSP_SETFMT");
|
perror("SNDCTL_DSP_SETFMT");
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set audio format");
|
return SDL_SetError("Couldn't set audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +193,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
value = this->spec.channels;
|
value = this->spec.channels;
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_CHANNELS");
|
perror("SNDCTL_DSP_CHANNELS");
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Cannot set the number of channels");
|
return SDL_SetError("Cannot set the number of channels");
|
||||||
}
|
}
|
||||||
this->spec.channels = value;
|
this->spec.channels = value;
|
||||||
|
@ -214,7 +201,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
value = this->spec.freq;
|
value = this->spec.freq;
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_SPEED");
|
perror("SNDCTL_DSP_SPEED");
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't set audio frequency");
|
return SDL_SetError("Couldn't set audio frequency");
|
||||||
}
|
}
|
||||||
this->spec.freq = value;
|
this->spec.freq = value;
|
||||||
|
@ -225,7 +211,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Determine the power of two of the fragment size */
|
/* Determine the power of two of the fragment size */
|
||||||
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
|
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
|
||||||
if ((0x01U << frag_spec) != this->spec.size) {
|
if ((0x01U << frag_spec) != this->spec.size) {
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_SetError("Fragment size must be a power of two");
|
return SDL_SetError("Fragment size must be a power of two");
|
||||||
}
|
}
|
||||||
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
||||||
|
@ -250,13 +235,14 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
|
if (!iscapture) {
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
DSP_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
}
|
||||||
|
|
||||||
/* We're ready to rock and roll. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -266,14 +252,13 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
static void
|
static void
|
||||||
DSP_PlayDevice(_THIS)
|
DSP_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
const Uint8 *mixbuf = this->hidden->mixbuf;
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
const int mixlen = this->hidden->mixlen;
|
if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
|
||||||
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
|
|
||||||
perror("Audio write");
|
perror("Audio write");
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(this);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
|
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +268,30 @@ DSP_GetDeviceBuf(_THIS)
|
||||||
return (this->hidden->mixbuf);
|
return (this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
DSP_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
return (int) read(this->hidden->audio_fd, buffer, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DSP_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
audio_buf_info info;
|
||||||
|
if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
|
||||||
|
while (info.bytes > 0) {
|
||||||
|
char buf[512];
|
||||||
|
const size_t len = SDL_min(sizeof (buf), info.bytes);
|
||||||
|
const ssize_t br = read(h->audio_fd, buf, len);
|
||||||
|
if (br <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info.bytes -= br;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DSP_Init(SDL_AudioDriverImpl * impl)
|
DSP_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
|
@ -292,8 +301,11 @@ DSP_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->PlayDevice = DSP_PlayDevice;
|
impl->PlayDevice = DSP_PlayDevice;
|
||||||
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
||||||
impl->CloseDevice = DSP_CloseDevice;
|
impl->CloseDevice = DSP_CloseDevice;
|
||||||
|
impl->CaptureFromDevice = DSP_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = DSP_FlushCapture;
|
||||||
|
|
||||||
impl->AllowsArbitraryDeviceNames = 1;
|
impl->AllowsArbitraryDeviceNames = 1;
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,27 +22,44 @@
|
||||||
|
|
||||||
/* Output audio to nowhere... */
|
/* Output audio to nowhere... */
|
||||||
|
|
||||||
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_dummyaudio.h"
|
#include "SDL_dummyaudio.h"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
return 0; /* always succeeds. */
|
return 0; /* always succeeds. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DUMMYAUD_Init(SDL_AudioDriverImpl * impl)
|
DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
/* Delay to make this sort of simulate real audio input. */
|
||||||
|
SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
|
||||||
|
|
||||||
|
/* always return a full buffer of silence. */
|
||||||
|
SDL_memset(buffer, this->spec.silence, buflen);
|
||||||
|
return buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = DUMMYAUD_OpenDevice;
|
impl->OpenDevice = DUMMYAUDIO_OpenDevice;
|
||||||
|
impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
|
||||||
|
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap DUMMYAUD_bootstrap = {
|
AudioBootStrap DUMMYAUDIO_bootstrap = {
|
||||||
"dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
|
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -61,16 +61,15 @@ HandleAudioProcess(_THIS)
|
||||||
Uint8 *buf = NULL;
|
Uint8 *buf = NULL;
|
||||||
int byte_len = 0;
|
int byte_len = 0;
|
||||||
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
|
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
|
||||||
int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
|
|
||||||
|
|
||||||
/* Only do soemthing if audio is enabled */
|
/* Only do something if audio is enabled */
|
||||||
if (!this->enabled)
|
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (this->paused)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->convert.needed) {
|
if (this->convert.needed) {
|
||||||
|
const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
|
||||||
|
|
||||||
if (this->hidden->conv_in_len != 0) {
|
if (this->hidden->conv_in_len != 0) {
|
||||||
this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels;
|
this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels;
|
||||||
}
|
}
|
||||||
|
@ -136,29 +135,139 @@ HandleAudioProcess(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Emscripten_CloseDevice(_THIS)
|
HandleCaptureProcess(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
Uint8 *buf;
|
||||||
if (this->hidden->mixbuf != NULL) {
|
int buflen;
|
||||||
/* Clean up the audio buffer */
|
|
||||||
SDL_free(this->hidden->mixbuf);
|
/* Only do something if audio is enabled */
|
||||||
this->hidden->mixbuf = NULL;
|
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
if (this->convert.needed) {
|
||||||
this->hidden = NULL;
|
buf = this->convert.buf;
|
||||||
|
buflen = this->convert.len_cvt;
|
||||||
|
} else {
|
||||||
|
if (!this->hidden->mixbuf) {
|
||||||
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
|
||||||
|
if (!this->hidden->mixbuf) {
|
||||||
|
return; /* oh well. */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
buf = this->hidden->mixbuf;
|
||||||
|
buflen = this->spec.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
EM_ASM_ARGS({
|
||||||
|
var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
|
||||||
|
if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
|
||||||
|
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0);
|
||||||
|
if (channelData.length != $1) {
|
||||||
|
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||||
|
}
|
||||||
|
for (var j = 0; j < $1; ++j) {
|
||||||
|
setValue($0 + (j * 4), channelData[j], 'float');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var c = 0; c < numChannels; ++c) {
|
||||||
|
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
|
||||||
|
if (channelData.length != $1) {
|
||||||
|
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < $1; ++j) {
|
||||||
|
setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, buf, (this->spec.size / sizeof (float)) / this->spec.channels);
|
||||||
|
|
||||||
|
/* okay, we've got an interleaved float32 array in C now. */
|
||||||
|
|
||||||
|
if (this->convert.needed) {
|
||||||
|
SDL_ConvertAudio(&this->convert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send it to the app. */
|
||||||
|
(*this->spec.callback) (this->spec.userdata, buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
||||||
|
{
|
||||||
|
EM_ASM_({
|
||||||
|
if ($0) {
|
||||||
|
if (SDL2.capture.silenceTimer !== undefined) {
|
||||||
|
clearTimeout(SDL2.capture.silenceTimer);
|
||||||
|
}
|
||||||
|
if (SDL2.capture.scriptProcessorNode !== undefined) {
|
||||||
|
SDL2.capture.scriptProcessorNode.disconnect();
|
||||||
|
SDL2.capture.scriptProcessorNode = undefined;
|
||||||
|
}
|
||||||
|
if (SDL2.capture.mediaStreamNode !== undefined) {
|
||||||
|
SDL2.capture.mediaStreamNode.disconnect();
|
||||||
|
SDL2.capture.mediaStreamNode = undefined;
|
||||||
|
}
|
||||||
|
if (SDL2.capture.silenceBuffer !== undefined) {
|
||||||
|
SDL2.capture.silenceBuffer = undefined
|
||||||
|
}
|
||||||
|
SDL2.capture = undefined;
|
||||||
|
} else {
|
||||||
|
if (SDL2.audio.scriptProcessorNode != undefined) {
|
||||||
|
SDL2.audio.scriptProcessorNode.disconnect();
|
||||||
|
SDL2.audio.scriptProcessorNode = undefined;
|
||||||
|
}
|
||||||
|
SDL2.audio = undefined;
|
||||||
|
}
|
||||||
|
if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) {
|
||||||
|
SDL2.audioContext.close();
|
||||||
|
SDL2.audioContext = undefined;
|
||||||
|
}
|
||||||
|
}, this->iscapture);
|
||||||
|
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
|
SDL_free(this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
SDL_bool valid_format = SDL_FALSE;
|
SDL_bool valid_format = SDL_FALSE;
|
||||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
SDL_AudioFormat test_format;
|
||||||
int i;
|
int i;
|
||||||
float f;
|
float f;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
/* based on parts of library_sdl.js */
|
||||||
|
|
||||||
|
/* create context (TODO: this puts stuff in the global namespace...)*/
|
||||||
|
result = EM_ASM_INT({
|
||||||
|
if(typeof(SDL2) === 'undefined') {
|
||||||
|
SDL2 = {};
|
||||||
|
}
|
||||||
|
if (!$0) {
|
||||||
|
SDL2.audio = {};
|
||||||
|
} else {
|
||||||
|
SDL2.capture = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SDL2.audioContext) {
|
||||||
|
if (typeof(AudioContext) !== 'undefined') {
|
||||||
|
SDL2.audioContext = new AudioContext();
|
||||||
|
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
||||||
|
SDL2.audioContext = new webkitAudioContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL2.audioContext === undefined ? -1 : 0;
|
||||||
|
}, iscapture);
|
||||||
|
if (result < 0) {
|
||||||
|
return SDL_SetError("Web Audio API is not available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||||
while ((!valid_format) && (test_format)) {
|
while ((!valid_format) && (test_format)) {
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case AUDIO_F32: /* web audio only supports floats */
|
case AUDIO_F32: /* web audio only supports floats */
|
||||||
|
@ -181,36 +290,11 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* based on parts of library_sdl.js */
|
|
||||||
|
|
||||||
/* create context (TODO: this puts stuff in the global namespace...)*/
|
|
||||||
result = EM_ASM_INT_V({
|
|
||||||
if(typeof(SDL2) === 'undefined')
|
|
||||||
SDL2 = {};
|
|
||||||
|
|
||||||
if(typeof(SDL2.audio) === 'undefined')
|
|
||||||
SDL2.audio = {};
|
|
||||||
|
|
||||||
if (!SDL2.audioContext) {
|
|
||||||
if (typeof(AudioContext) !== 'undefined') {
|
|
||||||
SDL2.audioContext = new AudioContext();
|
|
||||||
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
|
||||||
SDL2.audioContext = new webkitAudioContext();
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
if (result < 0) {
|
|
||||||
return SDL_SetError("Web Audio API is not available!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* limit to native freq */
|
/* limit to native freq */
|
||||||
int sampleRate = EM_ASM_INT_V({
|
const int sampleRate = EM_ASM_INT_V({
|
||||||
return SDL2.audioContext['sampleRate'];
|
return SDL2.audioContext.sampleRate;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this->spec.freq != sampleRate) {
|
if(this->spec.freq != sampleRate) {
|
||||||
|
@ -227,6 +311,62 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
|
if (iscapture) {
|
||||||
|
/* The idea is to take the capture media stream, hook it up to an
|
||||||
|
audio graph where we can pass it through a ScriptProcessorNode
|
||||||
|
to access the raw PCM samples and push them to the SDL app's
|
||||||
|
callback. From there, we "process" the audio data into silence
|
||||||
|
and forget about it. */
|
||||||
|
|
||||||
|
/* This should, strictly speaking, use MediaRecorder for capture, but
|
||||||
|
this API is cleaner to use and better supported, and fires a
|
||||||
|
callback whenever there's enough data to fire down into the app.
|
||||||
|
The downside is that we are spending CPU time silencing a buffer
|
||||||
|
that the audiocontext uselessly mixes into any output. On the
|
||||||
|
upside, both of those things are not only run in native code in
|
||||||
|
the browser, they're probably SIMD code, too. MediaRecorder
|
||||||
|
feels like it's a pretty inefficient tapdance in similar ways,
|
||||||
|
to be honest. */
|
||||||
|
|
||||||
|
EM_ASM_({
|
||||||
|
var have_microphone = function(stream) {
|
||||||
|
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
|
||||||
|
if (SDL2.capture.silenceTimer !== undefined) {
|
||||||
|
clearTimeout(SDL2.capture.silenceTimer);
|
||||||
|
SDL2.capture.silenceTimer = undefined;
|
||||||
|
}
|
||||||
|
SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream);
|
||||||
|
SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1);
|
||||||
|
SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {
|
||||||
|
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
|
||||||
|
SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
|
||||||
|
Runtime.dynCall('vi', $2, [$3]);
|
||||||
|
};
|
||||||
|
SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);
|
||||||
|
SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);
|
||||||
|
};
|
||||||
|
|
||||||
|
var no_microphone = function(error) {
|
||||||
|
//console.log('SDL audio capture: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.');
|
||||||
|
};
|
||||||
|
|
||||||
|
/* we write silence to the audio callback until the microphone is available (user approves use, etc). */
|
||||||
|
SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate);
|
||||||
|
SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0);
|
||||||
|
var silence_callback = function() {
|
||||||
|
SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer;
|
||||||
|
Runtime.dynCall('vi', $2, [$3]);
|
||||||
|
};
|
||||||
|
|
||||||
|
SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
|
||||||
|
|
||||||
|
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
|
||||||
|
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
|
||||||
|
} else if (navigator.webkitGetUserMedia !== undefined) {
|
||||||
|
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
||||||
|
}
|
||||||
|
}, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
|
||||||
|
} else {
|
||||||
/* setup a ScriptProcessorNode */
|
/* setup a ScriptProcessorNode */
|
||||||
EM_ASM_ARGS({
|
EM_ASM_ARGS({
|
||||||
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
|
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
|
||||||
|
@ -236,17 +376,18 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
};
|
};
|
||||||
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
|
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
|
||||||
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
|
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
Emscripten_Init(SDL_AudioDriverImpl * impl)
|
EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = Emscripten_OpenDevice;
|
impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
|
||||||
impl->CloseDevice = Emscripten_CloseDevice;
|
impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
|
||||||
|
|
||||||
/* only one output */
|
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
|
|
||||||
/* no threads here */
|
/* no threads here */
|
||||||
|
@ -254,7 +395,7 @@ Emscripten_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->ProvidesOwnCallbackThread = 1;
|
impl->ProvidesOwnCallbackThread = 1;
|
||||||
|
|
||||||
/* check availability */
|
/* check availability */
|
||||||
int available = EM_ASM_INT_V({
|
const int available = EM_ASM_INT_V({
|
||||||
if (typeof(AudioContext) !== 'undefined') {
|
if (typeof(AudioContext) !== 'undefined') {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
||||||
|
@ -267,11 +408,23 @@ Emscripten_Init(SDL_AudioDriverImpl * impl)
|
||||||
SDL_SetError("No audio context available");
|
SDL_SetError("No audio context available");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int capture_available = available && EM_ASM_INT_V({
|
||||||
|
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
|
||||||
|
return 1;
|
||||||
|
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
|
||||||
|
impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE;
|
||||||
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap EmscriptenAudio_bootstrap = {
|
AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
|
||||||
"emscripten", "SDL emscripten audio driver", Emscripten_Init, 0
|
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
|
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_esdaudio.h"
|
#include "SDL_esdaudio.h"
|
||||||
|
|
||||||
|
@ -174,17 +173,11 @@ ESD_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
ESD_CloseDevice(_THIS)
|
ESD_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (this->hidden->audio_fd >= 0) {
|
||||||
SDL_NAME(esd_close) (this->hidden->audio_fd);
|
SDL_NAME(esd_close) (this->hidden->audio_fd);
|
||||||
this->hidden->audio_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to get the name of the program */
|
/* Try to get the name of the program */
|
||||||
|
@ -227,7 +220,7 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
this->hidden->audio_fd = -1;
|
this->hidden->audio_fd = -1;
|
||||||
|
|
||||||
/* Convert audio spec to the ESD audio format */
|
/* Convert audio spec to the ESD audio format */
|
||||||
|
@ -252,7 +245,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
ESD_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +263,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
get_progname());
|
get_progname());
|
||||||
|
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (this->hidden->audio_fd < 0) {
|
||||||
ESD_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't open ESD connection");
|
return SDL_SetError("Couldn't open ESD connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,9 +274,8 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
ESD_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#if SDL_AUDIO_DRIVER_FUSIONSOUND
|
#if SDL_AUDIO_DRIVER_FUSIONSOUND
|
||||||
|
|
||||||
|
/* !!! FIXME: why is this is SDL_FS_* instead of FUSIONSOUND_*? */
|
||||||
|
|
||||||
/* Allow access to a raw mixing buffer */
|
/* Allow access to a raw mixing buffer */
|
||||||
|
|
||||||
#ifdef HAVE_SIGNAL_H
|
#ifdef HAVE_SIGNAL_H
|
||||||
|
@ -31,7 +33,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_fsaudio.h"
|
#include "SDL_fsaudio.h"
|
||||||
|
|
||||||
|
@ -168,20 +169,14 @@ SDL_FS_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
SDL_FS_CloseDevice(_THIS)
|
SDL_FS_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->stream) {
|
if (this->hidden->stream) {
|
||||||
this->hidden->stream->Release(this->hidden->stream);
|
this->hidden->stream->Release(this->hidden->stream);
|
||||||
this->hidden->stream = NULL;
|
|
||||||
}
|
}
|
||||||
if (this->hidden->fs) {
|
if (this->hidden->fs) {
|
||||||
this->hidden->fs->Release(this->hidden->fs);
|
this->hidden->fs->Release(this->hidden->fs);
|
||||||
this->hidden->fs = NULL;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +195,7 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||||
|
@ -239,7 +234,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
SDL_FS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
@ -247,7 +241,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Retrieve the main sound interface. */
|
/* Retrieve the main sound interface. */
|
||||||
ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
|
ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
SDL_FS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Unable to initialize FusionSound: %d", ret);
|
return SDL_SetError("Unable to initialize FusionSound: %d", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +259,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
this->hidden->fs->CreateStream(this->hidden->fs, &desc,
|
this->hidden->fs->CreateStream(this->hidden->fs, &desc,
|
||||||
&this->hidden->stream);
|
&this->hidden->stream);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
SDL_FS_CloseDevice(this);
|
|
||||||
return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
|
return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,9 +277,8 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
SDL_FS_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
|
|
@ -49,10 +49,11 @@ FillSound(void *device, void *stream, size_t len,
|
||||||
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
||||||
|
|
||||||
/* Only do soemthing if audio is enabled */
|
/* Only do soemthing if audio is enabled */
|
||||||
if (!audio->enabled)
|
if (!SDL_AtomicGet(&audio->enabled)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!audio->paused) {
|
if (!SDL_AtomicGet(&audio->paused)) {
|
||||||
if (audio->convert.needed) {
|
if (audio->convert.needed) {
|
||||||
SDL_LockMutex(audio->mixer_lock);
|
SDL_LockMutex(audio->mixer_lock);
|
||||||
(*audio->spec.callback) (audio->spec.userdata,
|
(*audio->spec.callback) (audio->spec.userdata,
|
||||||
|
@ -73,16 +74,11 @@ FillSound(void *device, void *stream, size_t len,
|
||||||
static void
|
static void
|
||||||
HAIKUAUDIO_CloseDevice(_THIS)
|
HAIKUAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (_this->hidden != NULL) {
|
|
||||||
if (_this->hidden->audio_obj) {
|
if (_this->hidden->audio_obj) {
|
||||||
_this->hidden->audio_obj->Stop();
|
_this->hidden->audio_obj->Stop();
|
||||||
delete _this->hidden->audio_obj;
|
delete _this->hidden->audio_obj;
|
||||||
_this->hidden->audio_obj = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _this->hidden;
|
delete _this->hidden;
|
||||||
_this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,10 +118,10 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (_this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Parse the audio format and fill the Be raw audio format */
|
/* Parse the audio format and fill the Be raw audio format */
|
||||||
SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
|
SDL_zero(format);
|
||||||
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
|
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
|
||||||
format.frame_rate = (float) _this->spec.freq;
|
format.frame_rate = (float) _this->spec.freq;
|
||||||
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
|
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
|
||||||
|
@ -176,7 +172,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||||
HAIKUAUDIO_CloseDevice(_this);
|
|
||||||
return SDL_SetError("Unsupported audio format");
|
return SDL_SetError("Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +190,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
|
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
|
||||||
_this->hidden->audio_obj->SetHasData(true);
|
_this->hidden->audio_obj->SetHasData(true);
|
||||||
} else {
|
} else {
|
||||||
HAIKUAUDIO_CloseDevice(_this);
|
|
||||||
return SDL_SetError("Unable to start Be audio");
|
return SDL_SetError("Unable to start Be audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_mutex.h"
|
#include "SDL_mutex.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_audiodev_c.h"
|
#include "../SDL_audiodev_c.h"
|
||||||
|
|
||||||
|
@ -38,22 +37,20 @@
|
||||||
#include "ppapi_simple/ps_event.h"
|
#include "ppapi_simple/ps_event.h"
|
||||||
|
|
||||||
/* The tag name used by NACL audio */
|
/* The tag name used by NACL audio */
|
||||||
#define NACLAUD_DRIVER_NAME "nacl"
|
#define NACLAUDIO_DRIVER_NAME "nacl"
|
||||||
|
|
||||||
#define SAMPLE_FRAME_COUNT 4096
|
#define SAMPLE_FRAME_COUNT 4096
|
||||||
|
|
||||||
/* Audio driver functions */
|
/* Audio driver functions */
|
||||||
static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture);
|
|
||||||
static void NACLAUD_CloseDevice(_THIS);
|
|
||||||
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
|
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
|
||||||
|
|
||||||
/* FIXME: Make use of latency if needed */
|
/* FIXME: Make use of latency if needed */
|
||||||
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
|
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
|
||||||
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
|
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
|
||||||
|
|
||||||
SDL_LockMutex(private->mutex);
|
SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */
|
||||||
|
|
||||||
if (_this->enabled && !_this->paused) {
|
if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
|
||||||
if (_this->convert.needed) {
|
if (_this->convert.needed) {
|
||||||
SDL_LockMutex(_this->mixer_lock);
|
SDL_LockMutex(_this->mixer_lock);
|
||||||
(*_this->spec.callback) (_this->spec.userdata,
|
(*_this->spec.callback) (_this->spec.userdata,
|
||||||
|
@ -68,13 +65,13 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt
|
||||||
SDL_UnlockMutex(_this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SDL_memset(samples, 0, buffer_size);
|
SDL_memset(samples, _this->spec.silence, buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
SDL_UnlockMutex(private->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
|
static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
|
||||||
const PPB_Core *core = PSInterfaceCore();
|
const PPB_Core *core = PSInterfaceCore();
|
||||||
const PPB_Audio *ppb_audio = PSInterfaceAudio();
|
const PPB_Audio *ppb_audio = PSInterfaceAudio();
|
||||||
SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
|
SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
|
||||||
|
@ -85,7 +82,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
|
NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
|
||||||
PP_Instance instance = PSGetInstanceId();
|
PP_Instance instance = PSGetInstanceId();
|
||||||
const PPB_Audio *ppb_audio = PSInterfaceAudio();
|
const PPB_Audio *ppb_audio = PSInterfaceAudio();
|
||||||
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
|
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
|
||||||
|
@ -121,30 +118,30 @@ NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
NACLAUD_Init(SDL_AudioDriverImpl * impl)
|
NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
if (PSGetInstanceId() == 0) {
|
if (PSGetInstanceId() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = NACLAUD_OpenDevice;
|
impl->OpenDevice = NACLAUDIO_OpenDevice;
|
||||||
impl->CloseDevice = NACLAUD_CloseDevice;
|
impl->CloseDevice = NACLAUDIO_CloseDevice;
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
impl->ProvidesOwnCallbackThread = 1;
|
impl->ProvidesOwnCallbackThread = 1;
|
||||||
/*
|
/*
|
||||||
* impl->WaitDevice = NACLAUD_WaitDevice;
|
* impl->WaitDevice = NACLAUDIO_WaitDevice;
|
||||||
* impl->GetDeviceBuf = NACLAUD_GetDeviceBuf;
|
* impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf;
|
||||||
* impl->PlayDevice = NACLAUD_PlayDevice;
|
* impl->PlayDevice = NACLAUDIO_PlayDevice;
|
||||||
* impl->Deinitialize = NACLAUD_Deinitialize;
|
* impl->Deinitialize = NACLAUDIO_Deinitialize;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap NACLAUD_bootstrap = {
|
AudioBootStrap NACLAUDIO_bootstrap = {
|
||||||
NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver",
|
NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver",
|
||||||
NACLAUD_Init, 0
|
NACLAUDIO_Init, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SDL_AUDIO_DRIVER_NACL */
|
#endif /* SDL_AUDIO_DRIVER_NACL */
|
||||||
|
|
|
@ -30,22 +30,21 @@
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_loadso.h"
|
#include "SDL_loadso.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_nasaudio.h"
|
#include "SDL_nasaudio.h"
|
||||||
|
|
||||||
static struct SDL_PrivateAudioData *this2 = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static void (*NAS_AuCloseServer) (AuServer *);
|
static void (*NAS_AuCloseServer) (AuServer *);
|
||||||
static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
|
static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
|
||||||
static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
|
static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
|
||||||
|
static void (*NAS_AuHandleEvents) (AuServer *);
|
||||||
static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
|
static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
|
||||||
static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
|
static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
|
||||||
static void (*NAS_AuSetElements)
|
static void (*NAS_AuSetElements)
|
||||||
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
|
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
|
||||||
static void (*NAS_AuWriteElement)
|
static void (*NAS_AuWriteElement)
|
||||||
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
|
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
|
||||||
|
static AuUint32 (*NAS_AuReadElement)
|
||||||
|
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuStatus *);
|
||||||
static AuServer *(*NAS_AuOpenServer)
|
static AuServer *(*NAS_AuOpenServer)
|
||||||
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
|
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
|
||||||
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
|
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
|
||||||
|
@ -80,10 +79,12 @@ load_nas_syms(void)
|
||||||
SDL_NAS_SYM(AuCloseServer);
|
SDL_NAS_SYM(AuCloseServer);
|
||||||
SDL_NAS_SYM(AuNextEvent);
|
SDL_NAS_SYM(AuNextEvent);
|
||||||
SDL_NAS_SYM(AuDispatchEvent);
|
SDL_NAS_SYM(AuDispatchEvent);
|
||||||
|
SDL_NAS_SYM(AuHandleEvents);
|
||||||
SDL_NAS_SYM(AuCreateFlow);
|
SDL_NAS_SYM(AuCreateFlow);
|
||||||
SDL_NAS_SYM(AuStartFlow);
|
SDL_NAS_SYM(AuStartFlow);
|
||||||
SDL_NAS_SYM(AuSetElements);
|
SDL_NAS_SYM(AuSetElements);
|
||||||
SDL_NAS_SYM(AuWriteElement);
|
SDL_NAS_SYM(AuWriteElement);
|
||||||
|
SDL_NAS_SYM(AuReadElement);
|
||||||
SDL_NAS_SYM(AuOpenServer);
|
SDL_NAS_SYM(AuOpenServer);
|
||||||
SDL_NAS_SYM(AuRegisterEventHandler);
|
SDL_NAS_SYM(AuRegisterEventHandler);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -187,19 +188,53 @@ NAS_GetDeviceBuf(_THIS)
|
||||||
return (this->hidden->mixbuf);
|
return (this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
NAS_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
while (SDL_TRUE) {
|
||||||
|
/* just keep the event queue moving and the server chattering. */
|
||||||
|
NAS_AuHandleEvents(h->aud);
|
||||||
|
|
||||||
|
retval = (int) NAS_AuReadElement(h->aud, h->flow, 1, buflen, buffer, NULL);
|
||||||
|
/*printf("read %d capture bytes\n", (int) retval);*/
|
||||||
|
if (retval == 0) {
|
||||||
|
SDL_Delay(10); /* don't burn the CPU if we're waiting for data. */
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NAS_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
AuUint32 total = 0;
|
||||||
|
AuUint32 br;
|
||||||
|
Uint8 buf[512];
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* just keep the event queue moving and the server chattering. */
|
||||||
|
NAS_AuHandleEvents(h->aud);
|
||||||
|
br = NAS_AuReadElement(h->aud, h->flow, 1, sizeof (buf), buf, NULL);
|
||||||
|
/*printf("flushed %d capture bytes\n", (int) br);*/
|
||||||
|
total += br;
|
||||||
|
} while ((br == sizeof (buf)) && (total < this->spec.size));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
NAS_CloseDevice(_THIS)
|
NAS_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->aud) {
|
if (this->hidden->aud) {
|
||||||
NAS_AuCloseServer(this->hidden->aud);
|
NAS_AuCloseServer(this->hidden->aud);
|
||||||
this->hidden->aud = 0;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this2 = this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char
|
static unsigned char
|
||||||
|
@ -225,6 +260,12 @@ sdlformat_to_auformat(unsigned int fmt)
|
||||||
static AuBool
|
static AuBool
|
||||||
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
|
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
|
||||||
{
|
{
|
||||||
|
SDL_AudioDevice *this = (SDL_AudioDevice *) hnd->data;
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
if (this->iscapture) {
|
||||||
|
return AuTrue; /* we don't (currently) care about any of this for capture devices */
|
||||||
|
}
|
||||||
|
|
||||||
switch (ev->type) {
|
switch (ev->type) {
|
||||||
case AuEventTypeElementNotify:
|
case AuEventTypeElementNotify:
|
||||||
{
|
{
|
||||||
|
@ -232,24 +273,24 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
|
||||||
|
|
||||||
switch (event->kind) {
|
switch (event->kind) {
|
||||||
case AuElementNotifyKindLowWater:
|
case AuElementNotifyKindLowWater:
|
||||||
if (this2->buf_free >= 0) {
|
if (h->buf_free >= 0) {
|
||||||
this2->really += event->num_bytes;
|
h->really += event->num_bytes;
|
||||||
gettimeofday(&this2->last_tv, 0);
|
gettimeofday(&h->last_tv, 0);
|
||||||
this2->buf_free += event->num_bytes;
|
h->buf_free += event->num_bytes;
|
||||||
} else {
|
} else {
|
||||||
this2->buf_free = event->num_bytes;
|
h->buf_free = event->num_bytes;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AuElementNotifyKindState:
|
case AuElementNotifyKindState:
|
||||||
switch (event->cur_state) {
|
switch (event->cur_state) {
|
||||||
case AuStatePause:
|
case AuStatePause:
|
||||||
if (event->reason != AuReasonUser) {
|
if (event->reason != AuReasonUser) {
|
||||||
if (this2->buf_free >= 0) {
|
if (h->buf_free >= 0) {
|
||||||
this2->really += event->num_bytes;
|
h->really += event->num_bytes;
|
||||||
gettimeofday(&this2->last_tv, 0);
|
gettimeofday(&h->last_tv, 0);
|
||||||
this2->buf_free += event->num_bytes;
|
h->buf_free += event->num_bytes;
|
||||||
} else {
|
} else {
|
||||||
this2->buf_free = event->num_bytes;
|
h->buf_free = event->num_bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -261,15 +302,29 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static AuDeviceID
|
static AuDeviceID
|
||||||
find_device(_THIS, int nch)
|
find_device(_THIS)
|
||||||
{
|
{
|
||||||
/* These "Au" things are all macros, not functions... */
|
/* These "Au" things are all macros, not functions... */
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
const unsigned int devicekind = this->iscapture ? AuComponentKindPhysicalInput : AuComponentKindPhysicalOutput;
|
||||||
|
const int numdevs = AuServerNumDevices(h->aud);
|
||||||
|
const int nch = this->spec.channels;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
|
|
||||||
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
|
/* Try to find exact match on channels first... */
|
||||||
AuComponentKindPhysicalOutput) &&
|
for (i = 0; i < numdevs; i++) {
|
||||||
AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
|
const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
|
||||||
return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
|
if ((AuDeviceKind(dev) == devicekind) && (AuDeviceNumTracks(dev) == nch)) {
|
||||||
|
return AuDeviceIdentifier(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take anything, then... */
|
||||||
|
for (i = 0; i < numdevs; i++) {
|
||||||
|
const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
|
||||||
|
if (AuDeviceKind(dev) == devicekind) {
|
||||||
|
this->spec.channels = AuDeviceNumTracks(dev);
|
||||||
|
return AuDeviceIdentifier(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AuNone;
|
return AuNone;
|
||||||
|
@ -288,7 +343,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
format = 0;
|
format = 0;
|
||||||
|
@ -300,21 +355,18 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
NAS_CloseDevice(this);
|
|
||||||
return SDL_SetError("NAS: Couldn't find any hardware audio formats");
|
return SDL_SetError("NAS: Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
|
||||||
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
||||||
if (this->hidden->aud == 0) {
|
if (this->hidden->aud == 0) {
|
||||||
NAS_CloseDevice(this);
|
|
||||||
return SDL_SetError("NAS: Couldn't open connection to NAS server");
|
return SDL_SetError("NAS: Couldn't open connection to NAS server");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->dev = find_device(this, this->spec.channels);
|
this->hidden->dev = find_device(this);
|
||||||
if ((this->hidden->dev == AuNone)
|
if ((this->hidden->dev == AuNone)
|
||||||
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
|
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
|
||||||
NAS_CloseDevice(this);
|
|
||||||
return SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
|
return SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,29 +380,38 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
this2 = this->hidden;
|
if (iscapture) {
|
||||||
|
AuMakeElementImportDevice(elms, this->spec.freq, this->hidden->dev,
|
||||||
|
AuUnlimitedSamples, 0, NULL);
|
||||||
|
AuMakeElementExportClient(elms + 1, 0, this->spec.freq, format,
|
||||||
|
this->spec.channels, AuTrue, buffer_size,
|
||||||
|
buffer_size, 0, NULL);
|
||||||
|
} else {
|
||||||
AuMakeElementImportClient(elms, this->spec.freq, format,
|
AuMakeElementImportClient(elms, this->spec.freq, format,
|
||||||
this->spec.channels, AuTrue, buffer_size,
|
this->spec.channels, AuTrue, buffer_size,
|
||||||
buffer_size / 4, 0, NULL);
|
buffer_size / 4, 0, NULL);
|
||||||
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
|
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
|
||||||
AuUnlimitedSamples, 0, NULL);
|
AuUnlimitedSamples, 0, NULL);
|
||||||
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
|
}
|
||||||
NULL);
|
|
||||||
|
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue,
|
||||||
|
2, elms, NULL);
|
||||||
|
|
||||||
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
|
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
|
||||||
this->hidden->flow, event_handler,
|
this->hidden->flow, event_handler,
|
||||||
(AuPointer) NULL);
|
(AuPointer) this);
|
||||||
|
|
||||||
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
|
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
|
if (!iscapture) {
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
NAS_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
}
|
||||||
|
|
||||||
/* We're ready to rock and roll. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -381,9 +442,14 @@ NAS_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->PlayDevice = NAS_PlayDevice;
|
impl->PlayDevice = NAS_PlayDevice;
|
||||||
impl->WaitDevice = NAS_WaitDevice;
|
impl->WaitDevice = NAS_WaitDevice;
|
||||||
impl->GetDeviceBuf = NAS_GetDeviceBuf;
|
impl->GetDeviceBuf = NAS_GetDeviceBuf;
|
||||||
|
impl->CaptureFromDevice = NAS_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = NAS_FlushCapture;
|
||||||
impl->CloseDevice = NAS_CloseDevice;
|
impl->CloseDevice = NAS_CloseDevice;
|
||||||
impl->Deinitialize = NAS_Deinitialize;
|
impl->Deinitialize = NAS_Deinitialize;
|
||||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
|
|
||||||
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_stdinc.h"
|
#include "SDL_stdinc.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_paudio.h"
|
#include "SDL_paudio.h"
|
||||||
|
|
||||||
|
@ -228,16 +227,11 @@ PAUDIO_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
PAUDIO_CloseDevice(_THIS)
|
PAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(this->hidden->audio_fd);
|
||||||
this->hidden->audio_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -262,13 +256,12 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
|
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
|
||||||
this->hidden->audio_fd = fd;
|
this->hidden->audio_fd = fd;
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +270,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
* that we can have.
|
* that we can have.
|
||||||
*/
|
*/
|
||||||
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't get audio buffer information");
|
return SDL_SetError("Couldn't get audio buffer information");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +383,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Couldn't find any hardware audio formats\n");
|
fprintf(stderr, "Couldn't find any hardware audio formats\n");
|
||||||
#endif
|
#endif
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
@ -449,15 +440,13 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Paudio: %s", err);
|
return SDL_SetError("Paudio: %s", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
@ -492,7 +481,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
paud_control.ioctl_request = AUDIO_START;
|
paud_control.ioctl_request = AUDIO_START;
|
||||||
paud_control.position = 0;
|
paud_control.position = 0;
|
||||||
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
|
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
|
||||||
PAUDIO_CloseDevice(this);
|
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Can't start audio play\n");
|
fprintf(stderr, "Can't start audio play\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_error.h"
|
#include "SDL_error.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_audiodev_c.h"
|
#include "../SDL_audiodev_c.h"
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
@ -40,10 +39,10 @@
|
||||||
#include <pspthreadman.h>
|
#include <pspthreadman.h>
|
||||||
|
|
||||||
/* The tag name used by PSP audio */
|
/* The tag name used by PSP audio */
|
||||||
#define PSPAUD_DRIVER_NAME "psp"
|
#define PSPAUDIO_DRIVER_NAME "psp"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
int format, mixlen, i;
|
int format, mixlen, i;
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
|
@ -51,7 +50,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
switch (this->spec.format & 0xff) {
|
switch (this->spec.format & 0xff) {
|
||||||
case 8:
|
case 8:
|
||||||
case 16:
|
case 16:
|
||||||
|
@ -99,7 +98,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PSPAUD_PlayDevice(_THIS)
|
static void PSPAUDIO_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
|
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
|
||||||
|
|
||||||
|
@ -113,28 +112,25 @@ static void PSPAUD_PlayDevice(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void PSPAUD_WaitDevice(_THIS)
|
static void PSPAUDIO_WaitDevice(_THIS)
|
||||||
{
|
{
|
||||||
/* Because we block when sending audio, there's no need for this function to do anything. */
|
/* Because we block when sending audio, there's no need for this function to do anything. */
|
||||||
}
|
}
|
||||||
static Uint8 *PSPAUD_GetDeviceBuf(_THIS)
|
static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbufs[this->hidden->next_buffer];
|
return this->hidden->mixbufs[this->hidden->next_buffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PSPAUD_CloseDevice(_THIS)
|
static void PSPAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden->channel >= 0) {
|
if (this->hidden->channel >= 0) {
|
||||||
sceAudioChRelease(this->hidden->channel);
|
sceAudioChRelease(this->hidden->channel);
|
||||||
this->hidden->channel = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->hidden->rawbuf != NULL) {
|
|
||||||
free(this->hidden->rawbuf);
|
|
||||||
this->hidden->rawbuf = NULL;
|
|
||||||
}
|
}
|
||||||
|
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
|
||||||
|
SDL_free(this->hidden);
|
||||||
}
|
}
|
||||||
static void PSPAUD_ThreadInit(_THIS)
|
|
||||||
|
static void PSPAUDIO_ThreadInit(_THIS)
|
||||||
{
|
{
|
||||||
/* Increase the priority of this audio thread by 1 to put it
|
/* Increase the priority of this audio thread by 1 to put it
|
||||||
ahead of other SDL threads. */
|
ahead of other SDL threads. */
|
||||||
|
@ -149,24 +145,23 @@ static void PSPAUD_ThreadInit(_THIS)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
PSPAUD_Init(SDL_AudioDriverImpl * impl)
|
PSPAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = PSPAUD_OpenDevice;
|
impl->OpenDevice = PSPAUDIO_OpenDevice;
|
||||||
impl->PlayDevice = PSPAUD_PlayDevice;
|
impl->PlayDevice = PSPAUDIO_PlayDevice;
|
||||||
impl->WaitDevice = PSPAUD_WaitDevice;
|
impl->WaitDevice = PSPAUDIO_WaitDevice;
|
||||||
impl->GetDeviceBuf = PSPAUD_GetDeviceBuf;
|
impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf;
|
||||||
impl->WaitDone = PSPAUD_WaitDevice;
|
impl->WaitDone = PSPAUDIO_WaitDevice;
|
||||||
impl->CloseDevice = PSPAUD_CloseDevice;
|
impl->CloseDevice = PSPAUDIO_CloseDevice;
|
||||||
impl->ThreadInit = PSPAUD_ThreadInit;
|
impl->ThreadInit = PSPAUDIO_ThreadInit;
|
||||||
|
|
||||||
/* PSP audio device */
|
/* PSP audio device */
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
/*
|
/*
|
||||||
impl->HasCaptureSupport = 1;
|
impl->HasCaptureSupport = 1;
|
||||||
|
|
||||||
impl->OnlyHasDefaultInputDevice = 1;
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
impl->DetectDevices = DSOUND_DetectDevices;
|
impl->DetectDevices = DSOUND_DetectDevices;
|
||||||
|
@ -175,8 +170,8 @@ PSPAUD_Init(SDL_AudioDriverImpl * impl)
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBootStrap PSPAUD_bootstrap = {
|
AudioBootStrap PSPAUDIO_bootstrap = {
|
||||||
"psp", "PSP audio driver", PSPAUD_Init, 0
|
"psp", "PSP audio driver", PSPAUDIO_Init, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/* SDL_AUDI */
|
/* SDL_AUDI */
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_pulseaudio.h"
|
#include "SDL_pulseaudio.h"
|
||||||
#include "SDL_loadso.h"
|
#include "SDL_loadso.h"
|
||||||
|
@ -100,12 +99,19 @@ static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *,
|
||||||
const pa_sample_spec *, const pa_channel_map *);
|
const pa_sample_spec *, const pa_channel_map *);
|
||||||
static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
|
static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
|
||||||
const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
|
const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
|
||||||
|
static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
|
||||||
|
const pa_buffer_attr *, pa_stream_flags_t);
|
||||||
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
|
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
|
||||||
static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
|
static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
|
||||||
|
static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
|
||||||
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
|
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
|
||||||
pa_free_cb_t, int64_t, pa_seek_mode_t);
|
pa_free_cb_t, int64_t, pa_seek_mode_t);
|
||||||
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
|
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
|
||||||
pa_stream_success_cb_t, void *);
|
pa_stream_success_cb_t, void *);
|
||||||
|
static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *, const void **, size_t *);
|
||||||
|
static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *);
|
||||||
|
static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
|
||||||
|
pa_stream_success_cb_t, void *);
|
||||||
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
|
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
|
||||||
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
|
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
|
||||||
|
|
||||||
|
@ -206,11 +212,16 @@ load_pulseaudio_syms(void)
|
||||||
SDL_PULSEAUDIO_SYM(pa_context_unref);
|
SDL_PULSEAUDIO_SYM(pa_context_unref);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_new);
|
SDL_PULSEAUDIO_SYM(pa_stream_new);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
|
SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
|
||||||
|
SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_get_state);
|
SDL_PULSEAUDIO_SYM(pa_stream_get_state);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
|
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
|
||||||
|
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_write);
|
SDL_PULSEAUDIO_SYM(pa_stream_write);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_drain);
|
SDL_PULSEAUDIO_SYM(pa_stream_drain);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
|
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
|
||||||
|
SDL_PULSEAUDIO_SYM(pa_stream_peek);
|
||||||
|
SDL_PULSEAUDIO_SYM(pa_stream_drop);
|
||||||
|
SDL_PULSEAUDIO_SYM(pa_stream_flush);
|
||||||
SDL_PULSEAUDIO_SYM(pa_stream_unref);
|
SDL_PULSEAUDIO_SYM(pa_stream_unref);
|
||||||
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
|
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
|
||||||
SDL_PULSEAUDIO_SYM(pa_strerror);
|
SDL_PULSEAUDIO_SYM(pa_strerror);
|
||||||
|
@ -239,6 +250,12 @@ getAppName(void)
|
||||||
return "SDL Application"; /* oh well. */
|
return "SDL Application"; /* oh well. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stream_operation_complete_no_op(pa_stream *s, int success, void *userdata)
|
||||||
|
{
|
||||||
|
/* no-op for pa_stream_drain(), etc, to use for callback. */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
|
WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
|
||||||
{
|
{
|
||||||
|
@ -326,7 +343,7 @@ PULSEAUDIO_WaitDevice(_THIS)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
|
||||||
while (this->enabled) {
|
while (SDL_AtomicGet(&this->enabled)) {
|
||||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
|
@ -344,25 +361,19 @@ PULSEAUDIO_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
/* Write the audio data */
|
/* Write the audio data */
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
if (this->enabled) {
|
if (SDL_AtomicGet(&this->enabled)) {
|
||||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
stream_drain_complete(pa_stream *s, int success, void *userdata)
|
|
||||||
{
|
|
||||||
/* no-op for pa_stream_drain() to use for callback. */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PULSEAUDIO_WaitDone(_THIS)
|
PULSEAUDIO_WaitDone(_THIS)
|
||||||
{
|
{
|
||||||
if (this->enabled) {
|
if (SDL_AtomicGet(&this->enabled)) {
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL);
|
pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_operation_complete_no_op, NULL);
|
||||||
if (o) {
|
if (o) {
|
||||||
while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) {
|
while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) {
|
||||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
|
@ -386,24 +397,96 @@ PULSEAUDIO_GetDeviceBuf(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
const void *data = NULL;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
while (SDL_AtomicGet(&this->enabled)) {
|
||||||
|
if (h->capturebuf != NULL) {
|
||||||
|
const int cpy = SDL_min(buflen, h->capturelen);
|
||||||
|
SDL_memcpy(buffer, h->capturebuf, cpy);
|
||||||
|
/*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/
|
||||||
|
h->capturebuf += cpy;
|
||||||
|
h->capturelen -= cpy;
|
||||||
|
if (h->capturelen == 0) {
|
||||||
|
h->capturebuf = NULL;
|
||||||
|
PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */
|
||||||
|
}
|
||||||
|
return cpy; /* new data, return it. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
|
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||||
|
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
|
SDL_OpenedAudioDeviceDisconnected(this);
|
||||||
|
return -1; /* uhoh, pulse failed! */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) {
|
||||||
|
continue; /* no data available yet. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a new fragment is available! */
|
||||||
|
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||||
|
SDL_assert(nbytes > 0);
|
||||||
|
if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */
|
||||||
|
PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
|
||||||
|
} else {
|
||||||
|
/* store this fragment's data, start feeding it to SDL. */
|
||||||
|
/*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/
|
||||||
|
h->capturebuf = (const Uint8 *) data;
|
||||||
|
h->capturelen = nbytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; /* not enabled? */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
PULSEAUDIO_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
struct SDL_PrivateAudioData *h = this->hidden;
|
||||||
|
|
||||||
|
if (h->capturebuf != NULL) {
|
||||||
|
PULSEAUDIO_pa_stream_drop(h->stream);
|
||||||
|
h->capturebuf = NULL;
|
||||||
|
h->capturelen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_stream_flush(h->stream, stream_operation_complete_no_op, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PULSEAUDIO_CloseDevice(_THIS)
|
PULSEAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
SDL_free(this->hidden->device_name);
|
|
||||||
if (this->hidden->stream) {
|
if (this->hidden->stream) {
|
||||||
|
if (this->hidden->capturebuf != NULL) {
|
||||||
|
PULSEAUDIO_pa_stream_drop(this->hidden->stream);
|
||||||
|
}
|
||||||
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
|
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
|
||||||
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
|
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
|
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
|
SDL_free(this->hidden->device_name);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
||||||
|
{
|
||||||
|
if (i) {
|
||||||
|
char **devname = (char **) data;
|
||||||
|
*devname = SDL_strdup(i->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
|
||||||
{
|
{
|
||||||
if (i) {
|
if (i) {
|
||||||
char **devname = (char **) data;
|
char **devname = (char **) data;
|
||||||
|
@ -412,7 +495,7 @@ DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
FindDeviceName(struct SDL_PrivateAudioData *h, void *handle)
|
FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle)
|
||||||
{
|
{
|
||||||
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
|
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
|
||||||
|
|
||||||
|
@ -420,7 +503,16 @@ FindDeviceName(struct SDL_PrivateAudioData *h, void *handle)
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name));
|
if (iscapture) {
|
||||||
|
WaitForPulseOperation(h->mainloop,
|
||||||
|
PULSEAUDIO_pa_context_get_source_info_by_index(h->context, idx,
|
||||||
|
SourceDeviceNameCallback, &h->device_name));
|
||||||
|
} else {
|
||||||
|
WaitForPulseOperation(h->mainloop,
|
||||||
|
PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx,
|
||||||
|
SinkDeviceNameCallback, &h->device_name));
|
||||||
|
}
|
||||||
|
|
||||||
return (h->device_name != NULL);
|
return (h->device_name != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,15 +526,15 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
pa_channel_map pacmap;
|
pa_channel_map pacmap;
|
||||||
pa_stream_flags_t flags = 0;
|
pa_stream_flags_t flags = 0;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
h = this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc((sizeof *this->hidden));
|
SDL_malloc((sizeof *this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
h = this->hidden;
|
|
||||||
|
|
||||||
paspec.format = PA_SAMPLE_INVALID;
|
paspec.format = PA_SAMPLE_INVALID;
|
||||||
|
|
||||||
|
@ -483,7 +575,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (paspec.format == PA_SAMPLE_INVALID) {
|
if (paspec.format == PA_SAMPLE_INVALID) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
this->spec.format = test_format;
|
||||||
|
@ -495,13 +586,14 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
|
if (!iscapture) {
|
||||||
h->mixlen = this->spec.size;
|
h->mixlen = this->spec.size;
|
||||||
h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen);
|
h->mixbuf = (Uint8 *) SDL_malloc(h->mixlen);
|
||||||
if (h->mixbuf == NULL) {
|
if (h->mixbuf == NULL) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
|
||||||
|
}
|
||||||
|
|
||||||
paspec.channels = this->spec.channels;
|
paspec.channels = this->spec.channels;
|
||||||
paspec.rate = this->spec.freq;
|
paspec.rate = this->spec.freq;
|
||||||
|
@ -523,13 +615,11 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
|
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Could not connect to PulseAudio server");
|
return SDL_SetError("Could not connect to PulseAudio server");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FindDeviceName(h, handle)) {
|
if (!FindDeviceName(h, iscapture, handle)) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
return SDL_SetError("Requested PulseAudio sink/source missing?");
|
||||||
return SDL_SetError("Requested PulseAudio sink missing?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The SDL ALSA output hints us that we use Windows' channel mapping */
|
/* The SDL ALSA output hints us that we use Windows' channel mapping */
|
||||||
|
@ -545,7 +635,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (h->stream == NULL) {
|
if (h->stream == NULL) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Could not set up PulseAudio stream");
|
return SDL_SetError("Could not set up PulseAudio stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,20 +644,22 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
flags |= PA_STREAM_DONT_MOVE;
|
flags |= PA_STREAM_DONT_MOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags,
|
if (iscapture) {
|
||||||
NULL, NULL) < 0) {
|
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags);
|
||||||
PULSEAUDIO_CloseDevice(this);
|
} else {
|
||||||
|
rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
return SDL_SetError("Could not connect PulseAudio stream");
|
return SDL_SetError("Could not connect PulseAudio stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("pa_mainloop_iterate() failed");
|
return SDL_SetError("pa_mainloop_iterate() failed");
|
||||||
}
|
}
|
||||||
state = PULSEAUDIO_pa_stream_get_state(h->stream);
|
state = PULSEAUDIO_pa_stream_get_state(h->stream);
|
||||||
if (!PA_STREAM_IS_GOOD(state)) {
|
if (!PA_STREAM_IS_GOOD(state)) {
|
||||||
PULSEAUDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("Could not connect PulseAudio stream");
|
return SDL_SetError("Could not connect PulseAudio stream");
|
||||||
}
|
}
|
||||||
} while (state != PA_STREAM_READY);
|
} while (state != PA_STREAM_READY);
|
||||||
|
@ -687,6 +778,10 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->CloseDevice = PULSEAUDIO_CloseDevice;
|
impl->CloseDevice = PULSEAUDIO_CloseDevice;
|
||||||
impl->WaitDone = PULSEAUDIO_WaitDone;
|
impl->WaitDone = PULSEAUDIO_WaitDone;
|
||||||
impl->Deinitialize = PULSEAUDIO_Deinitialize;
|
impl->Deinitialize = PULSEAUDIO_Deinitialize;
|
||||||
|
impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = PULSEAUDIO_FlushCapture;
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@ struct SDL_PrivateAudioData
|
||||||
/* Raw mixing buffer */
|
/* Raw mixing buffer */
|
||||||
Uint8 *mixbuf;
|
Uint8 *mixbuf;
|
||||||
int mixlen;
|
int mixlen;
|
||||||
|
|
||||||
|
const Uint8 *capturebuf;
|
||||||
|
int capturelen;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _SDL_pulseaudio_h */
|
#endif /* _SDL_pulseaudio_h */
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_qsa_audio.h"
|
#include "SDL_qsa_audio.h"
|
||||||
|
|
||||||
|
@ -138,8 +137,7 @@ QSA_ThreadInit(_THIS)
|
||||||
static void
|
static void
|
||||||
QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
|
QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
|
||||||
{
|
{
|
||||||
SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
|
SDL_zerop(cpars);
|
||||||
|
|
||||||
cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
|
cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||||
cpars->mode = SND_PCM_MODE_BLOCK;
|
cpars->mode = SND_PCM_MODE_BLOCK;
|
||||||
cpars->start_mode = SND_PCM_START_DATA;
|
cpars->start_mode = SND_PCM_START_DATA;
|
||||||
|
@ -229,7 +227,7 @@ QSA_PlayDevice(_THIS)
|
||||||
int towrite;
|
int towrite;
|
||||||
void *pcmbuffer;
|
void *pcmbuffer;
|
||||||
|
|
||||||
if ((!this->enabled) || (!this->hidden)) {
|
if (!SDL_AtomicGet(&this->enabled) || !this->hidden) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +260,7 @@ QSA_PlayDevice(_THIS)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if ((errno == EINVAL) || (errno == EIO)) {
|
if ((errno == EINVAL) || (errno == EIO)) {
|
||||||
SDL_memset(&cstatus, 0, sizeof(cstatus));
|
SDL_zero(cstatus);
|
||||||
if (!this->hidden->iscapture) {
|
if (!this->hidden->iscapture) {
|
||||||
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +303,7 @@ QSA_PlayDevice(_THIS)
|
||||||
towrite -= written;
|
towrite -= written;
|
||||||
pcmbuffer += written * this->spec.channels;
|
pcmbuffer += written * this->spec.channels;
|
||||||
}
|
}
|
||||||
} while ((towrite > 0) && (this->enabled));
|
} while ((towrite > 0) && SDL_AtomicGet(&this->enabled));
|
||||||
|
|
||||||
/* If we couldn't write, assume fatal error for now */
|
/* If we couldn't write, assume fatal error for now */
|
||||||
if (towrite != 0) {
|
if (towrite != 0) {
|
||||||
|
@ -322,7 +320,6 @@ QSA_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
QSA_CloseDevice(_THIS)
|
QSA_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
if (this->hidden->audio_handle != NULL) {
|
if (this->hidden->audio_handle != NULL) {
|
||||||
if (!this->hidden->iscapture) {
|
if (!this->hidden->iscapture) {
|
||||||
/* Finish playing available samples */
|
/* Finish playing available samples */
|
||||||
|
@ -334,15 +331,10 @@ QSA_CloseDevice(_THIS)
|
||||||
SND_PCM_CHANNEL_CAPTURE);
|
SND_PCM_CHANNEL_CAPTURE);
|
||||||
}
|
}
|
||||||
snd_pcm_close(this->hidden->audio_handle);
|
snd_pcm_close(this->hidden->audio_handle);
|
||||||
this->hidden->audio_handle = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_FreeAudioMem(this->hidden->pcm_buf);
|
SDL_free(this->hidden->pcm_buf);
|
||||||
this->hidden->pcm_buf = NULL;
|
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -365,13 +357,13 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Initialize channel transfer parameters to default */
|
/* Initialize channel transfer parameters to default */
|
||||||
QSA_InitAudioParams(&cparams);
|
QSA_InitAudioParams(&cparams);
|
||||||
|
|
||||||
/* Initialize channel direction: capture or playback */
|
/* Initialize channel direction: capture or playback */
|
||||||
this->hidden->iscapture = iscapture;
|
this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||||
|
|
||||||
if (device != NULL) {
|
if (device != NULL) {
|
||||||
/* Open requested audio device */
|
/* Open requested audio device */
|
||||||
|
@ -391,7 +383,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Check if requested device is opened */
|
/* Check if requested device is opened */
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
this->hidden->audio_handle = NULL;
|
this->hidden->audio_handle = NULL;
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return QSA_SetError("snd_pcm_open", status);
|
return QSA_SetError("snd_pcm_open", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +392,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
snd_pcm_plugin_set_disable(this->hidden->audio_handle,
|
snd_pcm_plugin_set_disable(this->hidden->audio_handle,
|
||||||
PLUGIN_DISABLE_MMAP);
|
PLUGIN_DISABLE_MMAP);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return QSA_SetError("snd_pcm_plugin_set_disable", status);
|
return QSA_SetError("snd_pcm_plugin_set_disable", status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,7 +477,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* assumes test_format not 0 on success */
|
/* assumes test_format not 0 on success */
|
||||||
if (test_format == 0) {
|
if (test_format == 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
|
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,12 +494,11 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Setup the transfer parameters according to cparams */
|
/* Setup the transfer parameters according to cparams */
|
||||||
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
|
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return QSA_SetError("snd_pcm_channel_params", status);
|
return QSA_SetError("snd_pcm_channel_params", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure channel is setup right one last time */
|
/* Make sure channel is setup right one last time */
|
||||||
SDL_memset(&csetup, 0, sizeof(csetup));
|
SDL_zero(csetup);
|
||||||
if (!this->hidden->iscapture) {
|
if (!this->hidden->iscapture) {
|
||||||
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
|
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||||
} else {
|
} else {
|
||||||
|
@ -519,7 +507,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* Setup an audio channel */
|
/* Setup an audio channel */
|
||||||
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
|
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return SDL_SetError("QSA: Unable to setup channel");
|
return SDL_SetError("QSA: Unable to setup channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,9 +527,8 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
* closest multiple)
|
* closest multiple)
|
||||||
*/
|
*/
|
||||||
this->hidden->pcm_buf =
|
this->hidden->pcm_buf =
|
||||||
(Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
|
(Uint8 *) SDL_malloc(this->hidden->pcm_len);
|
||||||
if (this->hidden->pcm_buf == NULL) {
|
if (this->hidden->pcm_buf == NULL) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->pcm_buf, this->spec.silence,
|
SDL_memset(this->hidden->pcm_buf, this->spec.silence,
|
||||||
|
@ -560,7 +546,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (this->hidden->audio_fd < 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return QSA_SetError("snd_pcm_file_descriptor", status);
|
return QSA_SetError("snd_pcm_file_descriptor", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +563,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
QSA_CloseDevice(this);
|
|
||||||
return QSA_SetError("snd_pcm_plugin_prepare", status);
|
return QSA_SetError("snd_pcm_plugin_prepare", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,10 +730,9 @@ static void
|
||||||
QSA_Deinitialize(void)
|
QSA_Deinitialize(void)
|
||||||
{
|
{
|
||||||
/* Clear devices array on shutdown */
|
/* Clear devices array on shutdown */
|
||||||
SDL_memset(qsa_playback_device, 0x00,
|
/* !!! FIXME: we zero these on init...any reason to do it here? */
|
||||||
sizeof(QSA_Device) * QSA_MAX_DEVICES);
|
SDL_zero(qsa_playback_device);
|
||||||
SDL_memset(qsa_capture_device, 0x00,
|
SDL_zero(qsa_capture_device);
|
||||||
sizeof(QSA_Device) * QSA_MAX_DEVICES);
|
|
||||||
qsa_playback_devices = 0;
|
qsa_playback_devices = 0;
|
||||||
qsa_capture_devices = 0;
|
qsa_capture_devices = 0;
|
||||||
}
|
}
|
||||||
|
@ -761,10 +744,8 @@ QSA_Init(SDL_AudioDriverImpl * impl)
|
||||||
int32_t status = 0;
|
int32_t status = 0;
|
||||||
|
|
||||||
/* Clear devices array */
|
/* Clear devices array */
|
||||||
SDL_memset(qsa_playback_device, 0x00,
|
SDL_zero(qsa_playback_device);
|
||||||
sizeof(QSA_Device) * QSA_MAX_DEVICES);
|
SDL_zero(qsa_capture_device);
|
||||||
SDL_memset(qsa_capture_device, 0x00,
|
|
||||||
sizeof(QSA_Device) * QSA_MAX_DEVICES);
|
|
||||||
qsa_playback_devices = 0;
|
qsa_playback_devices = 0;
|
||||||
qsa_capture_devices = 0;
|
qsa_capture_devices = 0;
|
||||||
|
|
||||||
|
@ -788,7 +769,7 @@ QSA_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->SkipMixerLock = 0;
|
impl->SkipMixerLock = 0;
|
||||||
impl->HasCaptureSupport = 1;
|
impl->HasCaptureSupport = 1;
|
||||||
impl->OnlyHasDefaultOutputDevice = 0;
|
impl->OnlyHasDefaultOutputDevice = 0;
|
||||||
impl->OnlyHasDefaultInputDevice = 0;
|
impl->OnlyHasDefaultCaptureDevice = 0;
|
||||||
|
|
||||||
/* Check if io-audio manager is running or not */
|
/* Check if io-audio manager is running or not */
|
||||||
status = snd_cards();
|
status = snd_cards();
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* SDL capture state */
|
/* SDL capture state */
|
||||||
int iscapture;
|
SDL_bool iscapture;
|
||||||
|
|
||||||
/* The audio device handle */
|
/* The audio device handle */
|
||||||
int cardno;
|
int cardno;
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_sndioaudio.h"
|
#include "SDL_sndioaudio.h"
|
||||||
|
|
||||||
|
@ -180,16 +179,11 @@ SNDIO_WaitDone(_THIS)
|
||||||
static void
|
static void
|
||||||
SNDIO_CloseDevice(_THIS)
|
SNDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
if ( this->hidden->dev != NULL ) {
|
if ( this->hidden->dev != NULL ) {
|
||||||
SNDIO_sio_close(this->hidden->dev);
|
SNDIO_sio_close(this->hidden->dev);
|
||||||
this->hidden->dev = NULL;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -204,13 +198,12 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
|
|
||||||
/* !!! FIXME: SIO_DEVANY can be a specific device... */
|
/* !!! FIXME: SIO_DEVANY can be a specific device... */
|
||||||
if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
|
if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
|
||||||
SNDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("sio_open() failed");
|
return SDL_SetError("sio_open() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +226,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
|
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
|
||||||
SNDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("sio_getpar() failed");
|
return SDL_SetError("sio_getpar() failed");
|
||||||
}
|
}
|
||||||
if (par.bps != SIO_BPS(par.bits)) {
|
if (par.bps != SIO_BPS(par.bits)) {
|
||||||
|
@ -248,7 +240,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
SNDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
|
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +260,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
else if ((par.bps == 1) && (!par.sig))
|
else if ((par.bps == 1) && (!par.sig))
|
||||||
this->spec.format = AUDIO_U8;
|
this->spec.format = AUDIO_U8;
|
||||||
else {
|
else {
|
||||||
SNDIO_CloseDevice(this);
|
|
||||||
return SDL_SetError("sndio: Got unsupported hardware audio format.");
|
return SDL_SetError("sndio: Got unsupported hardware audio format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,9 +272,8 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
SNDIO_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audiomem.h"
|
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "../SDL_audiodev_c.h"
|
#include "../SDL_audiodev_c.h"
|
||||||
#include "SDL_sunaudio.h"
|
#include "SDL_sunaudio.h"
|
||||||
|
@ -183,18 +182,12 @@ SUNAUDIO_GetDeviceBuf(_THIS)
|
||||||
static void
|
static void
|
||||||
SUNAUDIO_CloseDevice(_THIS)
|
SUNAUDIO_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
SDL_free(this->hidden->ulaw_buf);
|
SDL_free(this->hidden->ulaw_buf);
|
||||||
this->hidden->ulaw_buf = NULL;
|
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(this->hidden->audio_fd);
|
||||||
this->hidden->audio_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -219,7 +212,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->audio_fd = open(devname, flags, 0);
|
this->hidden->audio_fd = open(devname, flags, 0);
|
||||||
|
@ -340,7 +333,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "../../core/windows/SDL_windows.h"
|
#include "../../core/windows/SDL_windows.h"
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
|
|
||||||
|
#include "SDL_assert.h"
|
||||||
#include "SDL_timer.h"
|
#include "SDL_timer.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
|
@ -40,11 +41,11 @@
|
||||||
static void DetectWave##typ##Devs(void) { \
|
static void DetectWave##typ##Devs(void) { \
|
||||||
const UINT iscapture = iscap ? 1 : 0; \
|
const UINT iscapture = iscap ? 1 : 0; \
|
||||||
const UINT devcount = wave##typ##GetNumDevs(); \
|
const UINT devcount = wave##typ##GetNumDevs(); \
|
||||||
capstyp caps; \
|
capstyp##2W caps; \
|
||||||
UINT i; \
|
UINT i; \
|
||||||
for (i = 0; i < devcount; i++) { \
|
for (i = 0; i < devcount; i++) { \
|
||||||
if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
|
if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
|
||||||
char *name = WIN_StringToUTF8(caps.szPname); \
|
char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
|
||||||
if (name != NULL) { \
|
if (name != NULL) { \
|
||||||
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
|
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
|
||||||
SDL_free(name); \
|
SDL_free(name); \
|
||||||
|
@ -152,45 +153,87 @@ WINMM_WaitDone(_THIS)
|
||||||
} while (left > 0);
|
} while (left > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
const int nextbuf = this->hidden->next_buffer;
|
||||||
|
MMRESULT result;
|
||||||
|
|
||||||
|
SDL_assert(buflen == this->spec.size);
|
||||||
|
|
||||||
|
/* Wait for an audio chunk to finish */
|
||||||
|
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
|
||||||
|
|
||||||
|
/* Copy it to caller's buffer... */
|
||||||
|
SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);
|
||||||
|
|
||||||
|
/* requeue the buffer that just finished. */
|
||||||
|
result = waveInAddBuffer(this->hidden->hin,
|
||||||
|
&this->hidden->wavebuf[nextbuf],
|
||||||
|
sizeof (this->hidden->wavebuf[nextbuf]));
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return -1; /* uhoh! Disable the device. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* queue the next buffer in sequence, next time. */
|
||||||
|
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
|
||||||
|
return this->spec.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
WINMM_FlushCapture(_THIS)
|
||||||
|
{
|
||||||
|
/* Wait for an audio chunk to finish */
|
||||||
|
if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
|
||||||
|
const int nextbuf = this->hidden->next_buffer;
|
||||||
|
/* requeue the buffer that just finished without reading from it. */
|
||||||
|
waveInAddBuffer(this->hidden->hin,
|
||||||
|
&this->hidden->wavebuf[nextbuf],
|
||||||
|
sizeof (this->hidden->wavebuf[nextbuf]));
|
||||||
|
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WINMM_CloseDevice(_THIS)
|
WINMM_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
/* Close up audio */
|
|
||||||
if (this->hidden != NULL) {
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (this->hidden->audio_sem) {
|
if (this->hidden->hout) {
|
||||||
CloseHandle(this->hidden->audio_sem);
|
waveOutReset(this->hidden->hout);
|
||||||
this->hidden->audio_sem = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up mixing buffers */
|
/* Clean up mixing buffers */
|
||||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
|
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
|
||||||
waveOutUnprepareHeader(this->hidden->hout,
|
waveOutUnprepareHeader(this->hidden->hout,
|
||||||
&this->hidden->wavebuf[i],
|
&this->hidden->wavebuf[i],
|
||||||
sizeof(this->hidden->wavebuf[i]));
|
sizeof (this->hidden->wavebuf[i]));
|
||||||
this->hidden->wavebuf[i].dwUser = 0xFFFF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free raw mixing buffer */
|
waveOutClose(this->hidden->hout);
|
||||||
SDL_free(this->hidden->mixbuf);
|
}
|
||||||
this->hidden->mixbuf = NULL;
|
|
||||||
|
|
||||||
if (this->hidden->hin) {
|
if (this->hidden->hin) {
|
||||||
|
waveInReset(this->hidden->hin);
|
||||||
|
|
||||||
|
/* Clean up mixing buffers */
|
||||||
|
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
|
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
|
||||||
|
waveInUnprepareHeader(this->hidden->hin,
|
||||||
|
&this->hidden->wavebuf[i],
|
||||||
|
sizeof (this->hidden->wavebuf[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
waveInClose(this->hidden->hin);
|
waveInClose(this->hidden->hin);
|
||||||
this->hidden->hin = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->hout) {
|
if (this->hidden->audio_sem) {
|
||||||
waveOutClose(this->hidden->hout);
|
CloseHandle(this->hidden->audio_sem);
|
||||||
this->hidden->hout = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
|
@ -239,7 +282,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
if (this->hidden == NULL) {
|
if (this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
/* Initialize the wavebuf structures for closing */
|
/* Initialize the wavebuf structures for closing */
|
||||||
for (i = 0; i < NUM_BUFFERS; ++i)
|
for (i = 0; i < NUM_BUFFERS; ++i)
|
||||||
|
@ -269,7 +312,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_datatype) {
|
if (!valid_datatype) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SDL_SetError("Unsupported audio format");
|
return SDL_SetError("Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,36 +323,45 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
result = waveInOpen(&this->hidden->hin, devId, &waveformat,
|
result = waveInOpen(&this->hidden->hin, devId, &waveformat,
|
||||||
(DWORD_PTR) CaptureSound, (DWORD_PTR) this,
|
(DWORD_PTR) CaptureSound, (DWORD_PTR) this,
|
||||||
CALLBACK_FUNCTION);
|
CALLBACK_FUNCTION);
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return SetMMerror("waveInOpen()", result);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
|
result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
|
||||||
(DWORD_PTR) FillSound, (DWORD_PTR) this,
|
(DWORD_PTR) FillSound, (DWORD_PTR) this,
|
||||||
CALLBACK_FUNCTION);
|
CALLBACK_FUNCTION);
|
||||||
}
|
|
||||||
|
|
||||||
if (result != MMSYSERR_NOERROR) {
|
if (result != MMSYSERR_NOERROR) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SetMMerror("waveOutOpen()", result);
|
return SetMMerror("waveOutOpen()", result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SOUND_DEBUG
|
#ifdef SOUND_DEBUG
|
||||||
/* Check the sound device we retrieved */
|
/* Check the sound device we retrieved */
|
||||||
{
|
{
|
||||||
|
if (iscapture) {
|
||||||
|
WAVEINCAPS caps;
|
||||||
|
result = waveInGetDevCaps((UINT) this->hidden->hout,
|
||||||
|
&caps, sizeof (caps));
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return SetMMerror("waveInGetDevCaps()", result);
|
||||||
|
}
|
||||||
|
printf("Audio device: %s\n", caps.szPname);
|
||||||
|
} else {
|
||||||
WAVEOUTCAPS caps;
|
WAVEOUTCAPS caps;
|
||||||
|
|
||||||
result = waveOutGetDevCaps((UINT) this->hidden->hout,
|
result = waveOutGetDevCaps((UINT) this->hidden->hout,
|
||||||
&caps, sizeof(caps));
|
&caps, sizeof(caps));
|
||||||
if (result != MMSYSERR_NOERROR) {
|
if (result != MMSYSERR_NOERROR) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SetMMerror("waveOutGetDevCaps()", result);
|
return SetMMerror("waveOutGetDevCaps()", result);
|
||||||
}
|
}
|
||||||
printf("Audio device: %s\n", caps.szPname);
|
printf("Audio device: %s\n", caps.szPname);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Create the audio buffer semaphore */
|
/* Create the audio buffer semaphore */
|
||||||
this->hidden->audio_sem =
|
this->hidden->audio_sem =
|
||||||
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
||||||
if (this->hidden->audio_sem == NULL) {
|
if (this->hidden->audio_sem == NULL) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SDL_SetError("Couldn't create semaphore");
|
return SDL_SetError("Couldn't create semaphore");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,24 +369,46 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
this->hidden->mixbuf =
|
this->hidden->mixbuf =
|
||||||
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
|
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_zero(this->hidden->wavebuf);
|
||||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
SDL_memset(&this->hidden->wavebuf[i], 0,
|
|
||||||
sizeof(this->hidden->wavebuf[i]));
|
|
||||||
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
|
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
|
||||||
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
|
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
|
||||||
this->hidden->wavebuf[i].lpData =
|
this->hidden->wavebuf[i].lpData =
|
||||||
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
|
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
|
||||||
|
|
||||||
|
if (iscapture) {
|
||||||
|
result = waveInPrepareHeader(this->hidden->hin,
|
||||||
|
&this->hidden->wavebuf[i],
|
||||||
|
sizeof(this->hidden->wavebuf[i]));
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return SetMMerror("waveInPrepareHeader()", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = waveInAddBuffer(this->hidden->hin,
|
||||||
|
&this->hidden->wavebuf[i],
|
||||||
|
sizeof(this->hidden->wavebuf[i]));
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return SetMMerror("waveInAddBuffer()", result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
result = waveOutPrepareHeader(this->hidden->hout,
|
result = waveOutPrepareHeader(this->hidden->hout,
|
||||||
&this->hidden->wavebuf[i],
|
&this->hidden->wavebuf[i],
|
||||||
sizeof(this->hidden->wavebuf[i]));
|
sizeof(this->hidden->wavebuf[i]));
|
||||||
if (result != MMSYSERR_NOERROR) {
|
if (result != MMSYSERR_NOERROR) {
|
||||||
WINMM_CloseDevice(this);
|
|
||||||
return SetMMerror("waveOutPrepareHeader()", result);
|
return SetMMerror("waveOutPrepareHeader()", result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscapture) {
|
||||||
|
result = waveInStart(this->hidden->hin);
|
||||||
|
if (result != MMSYSERR_NOERROR) {
|
||||||
|
return SetMMerror("waveInStart()", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0; /* Ready to go! */
|
return 0; /* Ready to go! */
|
||||||
}
|
}
|
||||||
|
@ -351,8 +424,12 @@ WINMM_Init(SDL_AudioDriverImpl * impl)
|
||||||
impl->WaitDevice = WINMM_WaitDevice;
|
impl->WaitDevice = WINMM_WaitDevice;
|
||||||
impl->WaitDone = WINMM_WaitDone;
|
impl->WaitDone = WINMM_WaitDone;
|
||||||
impl->GetDeviceBuf = WINMM_GetDeviceBuf;
|
impl->GetDeviceBuf = WINMM_GetDeviceBuf;
|
||||||
|
impl->CaptureFromDevice = WINMM_CaptureFromDevice;
|
||||||
|
impl->FlushCapture = WINMM_FlushCapture;
|
||||||
impl->CloseDevice = WINMM_CloseDevice;
|
impl->CloseDevice = WINMM_CloseDevice;
|
||||||
|
|
||||||
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ XAUDIO2_PlayDevice(_THIS)
|
||||||
IXAudio2SourceVoice *source = this->hidden->source;
|
IXAudio2SourceVoice *source = this->hidden->source;
|
||||||
HRESULT result = S_OK;
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
if (!this->enabled) { /* shutting down? */
|
if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ XAUDIO2_PlayDevice(_THIS)
|
||||||
static void
|
static void
|
||||||
XAUDIO2_WaitDevice(_THIS)
|
XAUDIO2_WaitDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->enabled) {
|
if (SDL_AtomicGet(&this->enabled)) {
|
||||||
SDL_SemWait(this->hidden->semaphore);
|
SDL_SemWait(this->hidden->semaphore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ XAUDIO2_WaitDone(_THIS)
|
||||||
{
|
{
|
||||||
IXAudio2SourceVoice *source = this->hidden->source;
|
IXAudio2SourceVoice *source = this->hidden->source;
|
||||||
XAUDIO2_VOICE_STATE state;
|
XAUDIO2_VOICE_STATE state;
|
||||||
SDL_assert(!this->enabled); /* flag that stops playing. */
|
SDL_assert(!SDL_AtomicGet(&this->enabled)); /* flag that stops playing. */
|
||||||
IXAudio2SourceVoice_Discontinuity(source);
|
IXAudio2SourceVoice_Discontinuity(source);
|
||||||
#if SDL_XAUDIO2_WIN8
|
#if SDL_XAUDIO2_WIN8
|
||||||
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||||
|
@ -257,7 +257,6 @@ XAUDIO2_WaitDone(_THIS)
|
||||||
static void
|
static void
|
||||||
XAUDIO2_CloseDevice(_THIS)
|
XAUDIO2_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
if (this->hidden != NULL) {
|
|
||||||
IXAudio2 *ixa2 = this->hidden->ixa2;
|
IXAudio2 *ixa2 = this->hidden->ixa2;
|
||||||
IXAudio2SourceVoice *source = this->hidden->source;
|
IXAudio2SourceVoice *source = this->hidden->source;
|
||||||
IXAudio2MasteringVoice *mastering = this->hidden->mastering;
|
IXAudio2MasteringVoice *mastering = this->hidden->mastering;
|
||||||
|
@ -276,14 +275,12 @@ XAUDIO2_CloseDevice(_THIS)
|
||||||
if (ixa2 != NULL) {
|
if (ixa2 != NULL) {
|
||||||
IXAudio2_Release(ixa2);
|
IXAudio2_Release(ixa2);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->mixbuf);
|
|
||||||
if (this->hidden->semaphore != NULL) {
|
if (this->hidden->semaphore != NULL) {
|
||||||
SDL_DestroySemaphore(this->hidden->semaphore);
|
SDL_DestroySemaphore(this->hidden->semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(this->hidden);
|
||||||
this->hidden = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -345,12 +342,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
IXAudio2_Release(ixa2);
|
IXAudio2_Release(ixa2);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_zerop(this->hidden);
|
||||||
|
|
||||||
this->hidden->ixa2 = ixa2;
|
this->hidden->ixa2 = ixa2;
|
||||||
this->hidden->semaphore = SDL_CreateSemaphore(1);
|
this->hidden->semaphore = SDL_CreateSemaphore(1);
|
||||||
if (this->hidden->semaphore == NULL) {
|
if (this->hidden->semaphore == NULL) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: CreateSemaphore() failed!");
|
return SDL_SetError("XAudio2: CreateSemaphore() failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +364,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_format) {
|
if (!valid_format) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: Unsupported audio format");
|
return SDL_SetError("XAudio2: Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,11 +374,10 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
this->hidden->mixlen = this->spec.size;
|
this->hidden->mixlen = this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
|
this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (this->hidden->mixbuf == NULL) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
this->hidden->nextbuf = this->hidden->mixbuf;
|
this->hidden->nextbuf = this->hidden->mixbuf;
|
||||||
SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, 2 * this->hidden->mixlen);
|
||||||
|
|
||||||
/* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
|
/* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
|
||||||
Xbox360, this means 5.1 output, but on Windows, it means "figure out
|
Xbox360, this means 5.1 output, but on Windows, it means "figure out
|
||||||
|
@ -401,7 +395,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
this->spec.freq, 0, devId, NULL);
|
this->spec.freq, 0, devId, NULL);
|
||||||
#endif
|
#endif
|
||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: Couldn't create mastering voice");
|
return SDL_SetError("XAudio2: Couldn't create mastering voice");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +429,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: Couldn't create source voice");
|
return SDL_SetError("XAudio2: Couldn't create source voice");
|
||||||
}
|
}
|
||||||
this->hidden->source = source;
|
this->hidden->source = source;
|
||||||
|
@ -444,13 +436,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
/* Start everything playing! */
|
/* Start everything playing! */
|
||||||
result = IXAudio2_StartEngine(ixa2);
|
result = IXAudio2_StartEngine(ixa2);
|
||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: Couldn't start engine");
|
return SDL_SetError("XAudio2: Couldn't start engine");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
|
result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
|
||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
XAUDIO2_CloseDevice(this);
|
|
||||||
return SDL_SetError("XAudio2: Couldn't start source voice");
|
return SDL_SetError("XAudio2: Couldn't start source voice");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,10 +71,14 @@ static jclass mActivityClass;
|
||||||
|
|
||||||
/* method signatures */
|
/* method signatures */
|
||||||
static jmethodID midGetNativeSurface;
|
static jmethodID midGetNativeSurface;
|
||||||
static jmethodID midAudioInit;
|
static jmethodID midAudioOpen;
|
||||||
static jmethodID midAudioWriteShortBuffer;
|
static jmethodID midAudioWriteShortBuffer;
|
||||||
static jmethodID midAudioWriteByteBuffer;
|
static jmethodID midAudioWriteByteBuffer;
|
||||||
static jmethodID midAudioQuit;
|
static jmethodID midAudioClose;
|
||||||
|
static jmethodID midCaptureOpen;
|
||||||
|
static jmethodID midCaptureReadShortBuffer;
|
||||||
|
static jmethodID midCaptureReadByteBuffer;
|
||||||
|
static jmethodID midCaptureClose;
|
||||||
static jmethodID midPollInputDevices;
|
static jmethodID midPollInputDevices;
|
||||||
|
|
||||||
/* Accelerometer data storage */
|
/* Accelerometer data storage */
|
||||||
|
@ -118,21 +122,31 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
|
||||||
|
|
||||||
midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"getNativeSurface","()Landroid/view/Surface;");
|
"getNativeSurface","()Landroid/view/Surface;");
|
||||||
midAudioInit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midAudioOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"audioInit", "(IZZI)I");
|
"audioOpen", "(IZZI)I");
|
||||||
midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"audioWriteShortBuffer", "([S)V");
|
"audioWriteShortBuffer", "([S)V");
|
||||||
midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"audioWriteByteBuffer", "([B)V");
|
"audioWriteByteBuffer", "([B)V");
|
||||||
midAudioQuit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midAudioClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"audioQuit", "()V");
|
"audioClose", "()V");
|
||||||
|
midCaptureOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
|
"captureOpen", "(IZZI)I");
|
||||||
|
midCaptureReadShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
|
"captureReadShortBuffer", "([SZ)I");
|
||||||
|
midCaptureReadByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
|
"captureReadByteBuffer", "([BZ)I");
|
||||||
|
midCaptureClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
|
"captureClose", "()V");
|
||||||
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||||
"pollInputDevices", "()V");
|
"pollInputDevices", "()V");
|
||||||
|
|
||||||
bHasNewData = SDL_FALSE;
|
bHasNewData = SDL_FALSE;
|
||||||
|
|
||||||
if (!midGetNativeSurface || !midAudioInit ||
|
if (!midGetNativeSurface ||
|
||||||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) {
|
!midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose || !
|
||||||
|
!midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
|
||||||
|
!midPollInputDevices) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
||||||
}
|
}
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
|
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
|
||||||
|
@ -556,11 +570,14 @@ int Android_JNI_SetupThread(void)
|
||||||
static jboolean audioBuffer16Bit = JNI_FALSE;
|
static jboolean audioBuffer16Bit = JNI_FALSE;
|
||||||
static jobject audioBuffer = NULL;
|
static jobject audioBuffer = NULL;
|
||||||
static void* audioBufferPinned = NULL;
|
static void* audioBufferPinned = NULL;
|
||||||
|
static jboolean captureBuffer16Bit = JNI_FALSE;
|
||||||
|
static jobject captureBuffer = NULL;
|
||||||
|
|
||||||
int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
|
int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
|
||||||
{
|
{
|
||||||
jboolean audioBufferStereo;
|
jboolean audioBufferStereo;
|
||||||
int audioBufferFrames;
|
int audioBufferFrames;
|
||||||
|
jobject jbufobj = NULL;
|
||||||
jboolean isCopy;
|
jboolean isCopy;
|
||||||
|
|
||||||
JNIEnv *env = Android_JNI_GetEnv();
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
@ -570,15 +587,25 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i
|
||||||
}
|
}
|
||||||
Android_JNI_SetupThread();
|
Android_JNI_SetupThread();
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
|
||||||
audioBuffer16Bit = is16Bit;
|
|
||||||
audioBufferStereo = channelCount > 1;
|
audioBufferStereo = channelCount > 1;
|
||||||
|
|
||||||
if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
|
if (iscapture) {
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
|
||||||
|
captureBuffer16Bit = is16Bit;
|
||||||
|
if ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
|
||||||
|
/* Error during audio initialization */
|
||||||
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioRecord initialization!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
|
||||||
|
audioBuffer16Bit = is16Bit;
|
||||||
|
if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
|
||||||
/* Error during audio initialization */
|
/* Error during audio initialization */
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!");
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocating the audio buffer from the Java side and passing it as the return value for audioInit no longer works on
|
/* Allocating the audio buffer from the Java side and passing it as the return value for audioInit no longer works on
|
||||||
* Android >= 4.2 due to a "stale global reference" error. So now we allocate this buffer directly from this side. */
|
* Android >= 4.2 due to a "stale global reference" error. So now we allocate this buffer directly from this side. */
|
||||||
|
@ -586,31 +613,43 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i
|
||||||
if (is16Bit) {
|
if (is16Bit) {
|
||||||
jshortArray audioBufferLocal = (*env)->NewShortArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
|
jshortArray audioBufferLocal = (*env)->NewShortArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
|
||||||
if (audioBufferLocal) {
|
if (audioBufferLocal) {
|
||||||
audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal);
|
jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
|
||||||
(*env)->DeleteLocalRef(env, audioBufferLocal);
|
(*env)->DeleteLocalRef(env, audioBufferLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jbyteArray audioBufferLocal = (*env)->NewByteArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
|
jbyteArray audioBufferLocal = (*env)->NewByteArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
|
||||||
if (audioBufferLocal) {
|
if (audioBufferLocal) {
|
||||||
audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal);
|
jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
|
||||||
(*env)->DeleteLocalRef(env, audioBufferLocal);
|
(*env)->DeleteLocalRef(env, audioBufferLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioBuffer == NULL) {
|
if (jbufobj == NULL) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: could not allocate an audio buffer!");
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: could not allocate an audio buffer!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iscapture) {
|
||||||
|
captureBuffer = jbufobj;
|
||||||
|
} else {
|
||||||
|
audioBuffer = jbufobj;
|
||||||
|
}
|
||||||
|
|
||||||
isCopy = JNI_FALSE;
|
isCopy = JNI_FALSE;
|
||||||
if (audioBuffer16Bit) {
|
|
||||||
|
if (is16Bit) {
|
||||||
|
if (!iscapture) {
|
||||||
audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy);
|
audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy);
|
||||||
|
}
|
||||||
audioBufferFrames = (*env)->GetArrayLength(env, (jshortArray)audioBuffer);
|
audioBufferFrames = (*env)->GetArrayLength(env, (jshortArray)audioBuffer);
|
||||||
} else {
|
} else {
|
||||||
|
if (!iscapture) {
|
||||||
audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy);
|
audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy);
|
||||||
|
}
|
||||||
audioBufferFrames = (*env)->GetArrayLength(env, (jbyteArray)audioBuffer);
|
audioBufferFrames = (*env)->GetArrayLength(env, (jbyteArray)audioBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioBufferStereo) {
|
if (audioBufferStereo) {
|
||||||
audioBufferFrames /= 2;
|
audioBufferFrames /= 2;
|
||||||
}
|
}
|
||||||
|
@ -638,17 +677,74 @@ void Android_JNI_WriteAudioBuffer(void)
|
||||||
/* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
|
/* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
|
||||||
}
|
}
|
||||||
|
|
||||||
void Android_JNI_CloseAudioDevice(void)
|
int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
|
||||||
|
{
|
||||||
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
jboolean isCopy = JNI_FALSE;
|
||||||
|
jint br;
|
||||||
|
|
||||||
|
if (captureBuffer16Bit) {
|
||||||
|
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen / 2));
|
||||||
|
br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
|
||||||
|
if (br > 0) {
|
||||||
|
jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
|
||||||
|
br *= 2;
|
||||||
|
SDL_memcpy(buffer, ptr, br);
|
||||||
|
(*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, (jshort *)ptr, JNI_ABORT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen);
|
||||||
|
br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
|
||||||
|
if (br > 0) {
|
||||||
|
jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
|
||||||
|
SDL_memcpy(buffer, ptr, br);
|
||||||
|
(*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, (jbyte *)ptr, JNI_ABORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) br;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Android_JNI_FlushCapturedAudio(void)
|
||||||
|
{
|
||||||
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
#if 0 /* !!! FIXME: this needs API 23, or it'll do blocking reads and never end. */
|
||||||
|
if (captureBuffer16Bit) {
|
||||||
|
const jint len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer);
|
||||||
|
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||||
|
} else {
|
||||||
|
const jint len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer);
|
||||||
|
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (captureBuffer16Bit) {
|
||||||
|
const jint len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer);
|
||||||
|
(*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
|
||||||
|
} else {
|
||||||
|
const jint len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer);
|
||||||
|
(*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Android_JNI_CloseAudioDevice(const int iscapture)
|
||||||
{
|
{
|
||||||
JNIEnv *env = Android_JNI_GetEnv();
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
|
||||||
(*env)->CallStaticVoidMethod(env, mActivityClass, midAudioQuit);
|
if (iscapture) {
|
||||||
|
(*env)->CallStaticVoidMethod(env, mActivityClass, midCaptureClose);
|
||||||
|
if (captureBuffer) {
|
||||||
|
(*env)->DeleteGlobalRef(env, captureBuffer);
|
||||||
|
captureBuffer = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(*env)->CallStaticVoidMethod(env, mActivityClass, midAudioClose);
|
||||||
if (audioBuffer) {
|
if (audioBuffer) {
|
||||||
(*env)->DeleteGlobalRef(env, audioBuffer);
|
(*env)->DeleteGlobalRef(env, audioBuffer);
|
||||||
audioBuffer = NULL;
|
audioBuffer = NULL;
|
||||||
audioBufferPinned = NULL;
|
audioBufferPinned = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test for an exception and call SDL_SetError with its detail if one occurs */
|
/* Test for an exception and call SDL_SetError with its detail if one occurs */
|
||||||
|
|
|
@ -40,10 +40,12 @@ extern void Android_JNI_HideTextInput(void);
|
||||||
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
|
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
|
||||||
|
|
||||||
/* Audio support */
|
/* Audio support */
|
||||||
extern int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
|
extern int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
|
||||||
extern void* Android_JNI_GetAudioBuffer(void);
|
extern void* Android_JNI_GetAudioBuffer(void);
|
||||||
extern void Android_JNI_WriteAudioBuffer(void);
|
extern void Android_JNI_WriteAudioBuffer(void);
|
||||||
extern void Android_JNI_CloseAudioDevice(void);
|
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
|
||||||
|
extern void Android_JNI_FlushCapturedAudio(void);
|
||||||
|
extern void Android_JNI_CloseAudioDevice(const int iscapture);
|
||||||
|
|
||||||
#include "SDL_rwops.h"
|
#include "SDL_rwops.h"
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,80 @@ BOOL WIN_IsWindowsVistaOrGreater()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
|
||||||
|
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
|
||||||
|
will give you a name GUID. The full name is in the Windows Registry under
|
||||||
|
that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories
|
||||||
|
|
||||||
|
Note that drivers can report GUID_NULL for the name GUID, in which case,
|
||||||
|
Windows makes a best effort to fill in those 31 bytes in the usual place.
|
||||||
|
This info summarized from MSDN:
|
||||||
|
|
||||||
|
http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx
|
||||||
|
|
||||||
|
Always look this up in the registry if possible, because the strings are
|
||||||
|
different! At least on Win10, I see "Yeti Stereo Microphone" in the
|
||||||
|
Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
|
||||||
|
|
||||||
|
(Also, DirectSound shouldn't be limited to 32 chars, but its device enum
|
||||||
|
has the same problem.)
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
||||||
|
{
|
||||||
|
static const GUID nullguid = { 0 };
|
||||||
|
const unsigned char *ptr;
|
||||||
|
char keystr[128];
|
||||||
|
WCHAR *strw = NULL;
|
||||||
|
SDL_bool rc;
|
||||||
|
HKEY hkey;
|
||||||
|
DWORD len = 0;
|
||||||
|
char *retval = NULL;
|
||||||
|
|
||||||
|
if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) {
|
||||||
|
return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = (const char *) guid;
|
||||||
|
SDL_snprintf(keystr, sizeof (keystr),
|
||||||
|
"System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||||
|
ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
|
||||||
|
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
|
||||||
|
|
||||||
|
strw = WIN_UTF8ToString(keystr);
|
||||||
|
rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
|
||||||
|
SDL_free(strw);
|
||||||
|
if (!rc) {
|
||||||
|
return WIN_StringToUTF8(name); /* oh well. */
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
|
||||||
|
if (!rc) {
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
return WIN_StringToUTF8(name); /* oh well. */
|
||||||
|
}
|
||||||
|
|
||||||
|
strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR));
|
||||||
|
if (!strw) {
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
return WIN_StringToUTF8(name); /* oh well. */
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS);
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
if (!rc) {
|
||||||
|
SDL_free(strw);
|
||||||
|
return WIN_StringToUTF8(name); /* oh well. */
|
||||||
|
}
|
||||||
|
|
||||||
|
strw[len / 2] = 0; /* make sure it's null-terminated. */
|
||||||
|
|
||||||
|
retval = WIN_StringToUTF8(strw);
|
||||||
|
SDL_free(strw);
|
||||||
|
return retval ? retval : WIN_StringToUTF8(name);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __WIN32__ || __WINRT__ */
|
#endif /* __WIN32__ || __WINRT__ */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -59,6 +59,9 @@ extern void WIN_CoUninitialize(void);
|
||||||
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
|
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
|
||||||
extern BOOL WIN_IsWindowsVistaOrGreater();
|
extern BOOL WIN_IsWindowsVistaOrGreater();
|
||||||
|
|
||||||
|
/* You need to SDL_free() the result of this call. */
|
||||||
|
extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid);
|
||||||
|
|
||||||
#endif /* _INCLUDED_WINDOWS_H */
|
#endif /* _INCLUDED_WINDOWS_H */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -605,3 +605,4 @@
|
||||||
#define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL
|
#define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL
|
||||||
#define SDL_RenderSetIntegerScale SDL_RenderSetIntegerScale_REAL
|
#define SDL_RenderSetIntegerScale SDL_RenderSetIntegerScale_REAL
|
||||||
#define SDL_RenderGetIntegerScale SDL_RenderGetIntegerScale_REAL
|
#define SDL_RenderGetIntegerScale SDL_RenderGetIntegerScale_REAL
|
||||||
|
#define SDL_DequeueAudio SDL_DequeueAudio_REAL
|
||||||
|
|
|
@ -639,3 +639,4 @@ SDL_DYNAPI_PROC(int,SDL_SetWindowInputFocus,(SDL_Window *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return)
|
SDL_DYNAPI_PROC(int,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_RenderSetIntegerScale,(SDL_Renderer *a, SDL_bool b),(a,b),return)
|
SDL_DYNAPI_PROC(int,SDL_RenderSetIntegerScale,(SDL_Renderer *a, SDL_bool b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderGetIntegerScale,(SDL_Renderer *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderGetIntegerScale,(SDL_Renderer *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(Uint32,SDL_DequeueAudio,(SDL_AudioDeviceID a, void *b, Uint32 c),(a,b,c),return)
|
||||||
|
|
|
@ -34,11 +34,11 @@ void android_egl_context_backup();
|
||||||
void android_egl_context_restore();
|
void android_egl_context_restore();
|
||||||
|
|
||||||
#if SDL_AUDIO_DRIVER_ANDROID
|
#if SDL_AUDIO_DRIVER_ANDROID
|
||||||
void AndroidAUD_ResumeDevices(void);
|
void ANDROIDAUDIO_ResumeDevices(void);
|
||||||
void AndroidAUD_PauseDevices(void);
|
void ANDROIDAUDIO_PauseDevices(void);
|
||||||
#else
|
#else
|
||||||
static void AndroidAUD_ResumeDevices(void) {}
|
static void ANDROIDAUDIO_ResumeDevices(void) {}
|
||||||
static void AndroidAUD_PauseDevices(void) {}
|
static void ANDROIDAUDIO_PauseDevices(void) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -83,14 +83,14 @@ Android_PumpEvents(_THIS)
|
||||||
if (isPaused && !isPausing) {
|
if (isPaused && !isPausing) {
|
||||||
/* Make sure this is the last thing we do before pausing */
|
/* Make sure this is the last thing we do before pausing */
|
||||||
android_egl_context_backup();
|
android_egl_context_backup();
|
||||||
AndroidAUD_PauseDevices();
|
ANDROIDAUDIO_PauseDevices();
|
||||||
if(SDL_SemWait(Android_ResumeSem) == 0) {
|
if(SDL_SemWait(Android_ResumeSem) == 0) {
|
||||||
#else
|
#else
|
||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
if(SDL_SemTryWait(Android_ResumeSem) == 0) {
|
if(SDL_SemTryWait(Android_ResumeSem) == 0) {
|
||||||
#endif
|
#endif
|
||||||
isPaused = 0;
|
isPaused = 0;
|
||||||
AndroidAUD_ResumeDevices();
|
ANDROIDAUDIO_ResumeDevices();
|
||||||
/* Restore the GL Context from here, as this operation is thread dependent */
|
/* Restore the GL Context from here, as this operation is thread dependent */
|
||||||
if (!SDL_HasEvent(SDL_QUIT)) {
|
if (!SDL_HasEvent(SDL_QUIT)) {
|
||||||
android_egl_context_restore();
|
android_egl_context_restore();
|
||||||
|
@ -113,7 +113,7 @@ Android_PumpEvents(_THIS)
|
||||||
#else
|
#else
|
||||||
if(SDL_SemTryWait(Android_PauseSem) == 0) {
|
if(SDL_SemTryWait(Android_PauseSem) == 0) {
|
||||||
android_egl_context_backup();
|
android_egl_context_backup();
|
||||||
AndroidAUD_PauseDevices();
|
ANDROIDAUDIO_PauseDevices();
|
||||||
isPaused = 1;
|
isPaused = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -391,11 +391,24 @@ Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, vo
|
||||||
x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width;
|
x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width;
|
||||||
y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height;
|
y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height;
|
||||||
|
|
||||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
|
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
|
||||||
SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
|
if (!window_data->finger_touching) {
|
||||||
} else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
|
window_data->finger_touching = SDL_TRUE;
|
||||||
|
window_data->first_finger = id;
|
||||||
|
SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
|
||||||
|
SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
|
||||||
|
}
|
||||||
SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
|
SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
|
||||||
|
} else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
|
||||||
|
if ((window_data->finger_touching) && (window_data->first_finger == id)) {
|
||||||
|
SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y);
|
||||||
|
}
|
||||||
|
SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
|
||||||
} else {
|
} else {
|
||||||
|
if ((window_data->finger_touching) && (window_data->first_finger == id)) {
|
||||||
|
SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
|
||||||
|
window_data->finger_touching = SDL_FALSE;
|
||||||
|
}
|
||||||
SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
|
SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define _SDL_emscriptenvideo_h
|
#define _SDL_emscriptenvideo_h
|
||||||
|
|
||||||
#include "../SDL_sysvideo.h"
|
#include "../SDL_sysvideo.h"
|
||||||
|
#include "../../events/SDL_touch_c.h"
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
|
|
||||||
|
@ -45,6 +46,9 @@ typedef struct SDL_WindowData
|
||||||
SDL_bool external_size;
|
SDL_bool external_size;
|
||||||
|
|
||||||
int requested_fullscreen_mode;
|
int requested_fullscreen_mode;
|
||||||
|
|
||||||
|
SDL_bool finger_touching; /* for mapping touch events to mice */
|
||||||
|
SDL_FingerID first_finger;
|
||||||
} SDL_WindowData;
|
} SDL_WindowData;
|
||||||
|
|
||||||
#endif /* _SDL_emscriptenvideo_h */
|
#endif /* _SDL_emscriptenvideo_h */
|
||||||
|
|
|
@ -13,6 +13,7 @@ TARGETS = \
|
||||||
loopwavequeue$(EXE) \
|
loopwavequeue$(EXE) \
|
||||||
testatomic$(EXE) \
|
testatomic$(EXE) \
|
||||||
testaudioinfo$(EXE) \
|
testaudioinfo$(EXE) \
|
||||||
|
testaudiocapture$(EXE) \
|
||||||
testautomation$(EXE) \
|
testautomation$(EXE) \
|
||||||
testbounds$(EXE) \
|
testbounds$(EXE) \
|
||||||
testcustomcursor$(EXE) \
|
testcustomcursor$(EXE) \
|
||||||
|
@ -113,6 +114,9 @@ testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c
|
||||||
testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c
|
testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
testaudiocapture$(EXE): $(srcdir)/testaudiocapture.c
|
||||||
|
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
testatomic$(EXE): $(srcdir)/testatomic.c
|
testatomic$(EXE): $(srcdir)/testatomic.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely.
|
||||||
|
*/
|
||||||
|
#include "SDL.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SDL_Window *window = NULL;
|
||||||
|
static SDL_Renderer *renderer = NULL;
|
||||||
|
static SDL_AudioSpec spec;
|
||||||
|
static SDL_AudioDeviceID devid_in = 0;
|
||||||
|
static SDL_AudioDeviceID devid_out = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
loop()
|
||||||
|
{
|
||||||
|
SDL_bool please_quit = SDL_FALSE;
|
||||||
|
SDL_Event e;
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
if (e.type == SDL_QUIT) {
|
||||||
|
please_quit = SDL_TRUE;
|
||||||
|
} else if (e.type == SDL_KEYDOWN) {
|
||||||
|
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||||||
|
please_quit = SDL_TRUE;
|
||||||
|
}
|
||||||
|
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
|
if (e.button.button == 1) {
|
||||||
|
SDL_PauseAudioDevice(devid_out, SDL_TRUE);
|
||||||
|
SDL_PauseAudioDevice(devid_in, SDL_FALSE);
|
||||||
|
}
|
||||||
|
} else if (e.type == SDL_MOUSEBUTTONUP) {
|
||||||
|
if (e.button.button == 1) {
|
||||||
|
SDL_PauseAudioDevice(devid_in, SDL_TRUE);
|
||||||
|
SDL_PauseAudioDevice(devid_out, SDL_FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_GetAudioDeviceStatus(devid_in) == SDL_AUDIO_PLAYING) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||||
|
} else {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||||
|
}
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
|
if (please_quit) {
|
||||||
|
/* stop playing back, quit. */
|
||||||
|
SDL_Log("Shutting down.\n");
|
||||||
|
SDL_PauseAudioDevice(devid_in, 1);
|
||||||
|
SDL_CloseAudioDevice(devid_in);
|
||||||
|
SDL_PauseAudioDevice(devid_out, 1);
|
||||||
|
SDL_CloseAudioDevice(devid_out);
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_cancel_main_loop();
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that it would be easier to just have a one-line function that
|
||||||
|
calls SDL_QueueAudio() as a capture device callback, but we're
|
||||||
|
trying to test the API, so we use SDL_DequeueAudio() here. */
|
||||||
|
while (SDL_TRUE) {
|
||||||
|
Uint8 buf[1024];
|
||||||
|
const Uint32 br = SDL_DequeueAudio(devid_in, buf, sizeof (buf));
|
||||||
|
SDL_QueueAudio(devid_out, buf, br);
|
||||||
|
if (br < sizeof (buf)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* (argv[1] == NULL means "open default device.") */
|
||||||
|
const char *devname = argv[1];
|
||||||
|
SDL_AudioSpec wanted;
|
||||||
|
int devcount;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Enable standard application logging */
|
||||||
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
||||||
|
|
||||||
|
/* Load the SDL library */
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0);
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
|
SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
|
||||||
|
|
||||||
|
devcount = SDL_GetNumAudioDevices(SDL_TRUE);
|
||||||
|
for (i = 0; i < devcount; i++) {
|
||||||
|
SDL_Log(" Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_zero(wanted);
|
||||||
|
wanted.freq = 44100;
|
||||||
|
wanted.format = AUDIO_F32SYS;
|
||||||
|
wanted.channels = 1;
|
||||||
|
wanted.samples = 4096;
|
||||||
|
wanted.callback = NULL;
|
||||||
|
|
||||||
|
SDL_zero(spec);
|
||||||
|
|
||||||
|
/* DirectSound can fail in some instances if you open the same hardware
|
||||||
|
for both capture and output and didn't open the output end first,
|
||||||
|
according to the docs, so if you're doing something like this, always
|
||||||
|
open your capture devices second in case you land in those bizarre
|
||||||
|
circumstances. */
|
||||||
|
|
||||||
|
SDL_Log("Opening default playback device...\n");
|
||||||
|
devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wanted, &spec, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||||
|
if (!devid_out) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Log("Opening capture device %s%s%s...\n",
|
||||||
|
devname ? "'" : "",
|
||||||
|
devname ? devname : "[[default]]",
|
||||||
|
devname ? "'" : "");
|
||||||
|
|
||||||
|
devid_in = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0);
|
||||||
|
if (!devid_in) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Log("Ready! Hold down mouse or finger to record!\n");
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop(loop, 0, 1);
|
||||||
|
#else
|
||||||
|
while (1) { loop(); SDL_Delay(16); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue