Merge audio capture work back into the mainline.

This commit is contained in:
Ryan C. Gordon 2016-08-28 13:36:13 -04:00
commit 2da1ec8354
73 changed files with 2448 additions and 1144 deletions

View File

@ -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

View File

@ -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.

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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" />

View File

@ -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"
> >

View File

@ -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 */,

View File

@ -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 */,

View File

@ -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

View File

@ -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
/** /**

View File

@ -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.

View File

@ -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"
> >

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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 */,

View File

@ -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 */,

View File

@ -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 */,

View File

@ -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, &current_audio.inputDevices, &current_audio.inputDeviceCount); return add_audio_device(name, handle, &current_audio.inputDevices, &current_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);
} }
} }

View File

@ -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
{ {

View File

@ -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: */

View File

@ -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;

View File

@ -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) {

View File

@ -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. */
} }

View File

@ -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);
}
}
} }

View File

@ -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: */

View File

@ -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);

View File

@ -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. */

View File

@ -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. */
} }

View File

@ -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

View File

@ -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. */
} }

View File

@ -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;
}; };

View File

@ -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 */

View File

@ -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 */

View File

@ -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. */
} }

View File

@ -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: */

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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");
} }

View File

@ -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 */

View File

@ -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. */
} }

View File

@ -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

View File

@ -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 */

View File

@ -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. */
} }

View File

@ -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 */

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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();
} }

View File

@ -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. */
} }

View File

@ -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");
} }

View File

@ -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 */

View File

@ -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"

View File

@ -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: */

View File

@ -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: */

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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 */

View File

@ -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)

165
test/testaudiocapture.c Normal file
View File

@ -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;
}