Compare commits

...

No commits in common. "0.1.0" and "main" have entirely different histories.
0.1.0 ... main

59 changed files with 6444 additions and 8639 deletions

166
.clang-format Normal file
View File

@ -0,0 +1,166 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: NoIndent
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.so.0 filter=lfs diff=lfs merge=lfs -text

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.vscode
.vs
visualc/x64
build/
android/buildandroid/

143
CMakeLists.txt Normal file
View File

@ -0,0 +1,143 @@
# CMake Project for FAudioGMS
cmake_minimum_required(VERSION 2.8.12)
project(FAudioGMS C)
#Options
option(BUILD_SHARED_LIBS "Build shared library" ON)
SET(LIB_MAJOR_VERSION "0")
SET(LIB_MINOR_VERSION "2")
SET(LIB_REVISION "0")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
# Build Type
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
# By default, we use Release
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE
STRING "Choose the type of build." FORCE
)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "Debug" "Release" "RelWithDebInfo"
)
endif()
# Platform Flags
if(APPLE)
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
set(LOBJC "objc")
elseif(WIN32)
# "FAudioGMS.dll", not "libFAudioGMS.dll"
set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif()
if(UNIX)
SET(BIN_RPATH "\$ORIGIN;\$ORIGIN/assets") #thanks yoyo games
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ${BIN_RPATH})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
endif()
# Source lists
add_library(FAudioGMS
#Public header
src/FAudioGMS.h
#Source files
lib/dr_wav.h
src/FAudioGMS.c
)
# FAudio Source lists
add_library(FAudio STATIC
# Public Headers
lib/FAudio/include/F3DAudio.h
lib/FAudio/include/FACT3D.h
lib/FAudio/include/FACT.h
lib/FAudio/include/FAPOBase.h
lib/FAudio/include/FAPOFX.h
lib/FAudio/include/FAPO.h
lib/FAudio/include/FAudioFX.h
lib/FAudio/include/FAudio.h
# Internal Headers
lib/FAudio/src/FACT_internal.h
lib/FAudio/src/FAudio_internal.h
lib/FAudio/src/stb.h
lib/FAudio/src/stb_vorbis.h
# Source Files
lib/FAudio/src/F3DAudio.c
lib/FAudio/src/FACT3D.c
lib/FAudio/src/FACT.c
lib/FAudio/src/FACT_internal.c
lib/FAudio/src/FAPOBase.c
lib/FAudio/src/FAPOFX.c
lib/FAudio/src/FAPOFX_echo.c
lib/FAudio/src/FAPOFX_eq.c
lib/FAudio/src/FAPOFX_masteringlimiter.c
lib/FAudio/src/FAPOFX_reverb.c
lib/FAudio/src/FAudio.c
lib/FAudio/src/FAudioFX_reverb.c
lib/FAudio/src/FAudioFX_volumemeter.c
lib/FAudio/src/FAudio_internal.c
lib/FAudio/src/FAudio_internal_simd.c
lib/FAudio/src/FAudio_operationset.c
lib/FAudio/src/FAudio_platform_sdl2.c
lib/FAudio/src/FAudio_platform_win32.c
)
# Build flags
if(NOT MSVC)
set_property(TARGET FAudioGMS PROPERTY COMPILE_FLAGS "-std=gnu99 -Wall -Wno-strict-aliasing -pedantic")
set_property(TARGET FAudio PROPERTY COMPILE_FLAGS "-fPIC")
endif()
# includes
target_include_directories(FAudioGMS PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/FAudio/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/SDL/include>
)
target_include_directories(FAudio PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/FAudio/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/SDL/include>
)
# Soname
set_target_properties(FAudioGMS PROPERTIES OUTPUT_NAME "FAudioGMS"
VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION}
)
# Internal Dependencies
target_link_libraries(FAudioGMS PRIVATE FAudio ${LOBJC})
# SDL2 Dependency
if (DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES)
message(STATUS "using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES")
target_include_directories(FAudioGMS PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_include_directories(FAudio PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(FAudioGMS PUBLIC ${SDL2_LIBRARIES})
else()
# Only try to autodetect if both SDL2 variables aren't explicitly set
find_package(SDL2 CONFIG)
if (TARGET SDL2::SDL2)
message(STATUS "using TARGET SDL2::SDL2")
target_link_libraries(FAudioGMS PUBLIC SDL2::SDL2)
target_link_libraries(FAudio PUBLIC SDL2::SDL2)
elseif (TARGET SDL2)
message(STATUS "using TARGET SDL2")
target_link_libraries(FAudioGMS PUBLIC SDL2)
target_link_libraries(FAudio PUBLIC SDL2)
else()
message(STATUS "no TARGET SDL2::SDL2, or SDL2, using variables")
target_include_directories(FAudioGMS PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_include_directories(FAudio PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(FAudioGMS PUBLIC ${SDL2_LIBRARIES})
endif()
endif()

View File

@ -10,10 +10,63 @@ FAudioGMS can leak memory if used improperly, so keep track of your sound instan
As a final addendum, if the YoYo Games circus needs a new clown for tasks like fixing the audio engine that's been mostly broken for a decade, I am a highly skilled programmer and I work for competitive rates. You know where to find me.
## Usage
If you are on Windows, make SURE "Use x64 Windows runtime" is checked under Game Options -> Windows!
Place your audio files in Included Files. The `.yymps` has an example structure.
Make sure the `AUDIO` object is created once at the start of your game.
You can use the documented wrapper functions included in the `.yymps` to control audio,
or you can just use the C API directly and wrap it yourself.
Detailed API documentation can be found [here](http://moonside.games/docs/FAudioGMS/#/latest/).
## Platforms
FAudio itself is cross-platform and has been deployed by hundreds of games across many platforms.
FAudioGMS intends to support all the platforms that FAudio does,
but I need to get around to personally building and testing it for these platforms.
I will not be supporting 32-bit Windows. Catch up to 2004 and switch to 64-bit.
### Tested
- Windows (64-bit)
- Linux
- Android (I will not help you if it breaks, sorry, Android sucks, ask Nik if you need help)
### Theoretical
- OSX
- Nintendo Switch
- Xbox One
- iOS
### Not Supported
- Windows (32-bit)
- HTML5 (if someone wants to try this go ahead but I'm not touching that garbage with a 10 foot pole)
## Dependencies
FAudioGMS depends on FAudio (obviously) and SDL2. We avoid directly depending on the C runtime.
## Building
### Windows
Open the project contained in the `visualc` directory in Visual Studio and build.
### OSX/Linux
```sh
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=/usr/bin/clang -S . -B ./build
cd ./build
make
```
### Console Platforms
You will need to show proof of NDA to obtain SDL source for your platform.
## License
This library is licensed under the zlib license. See LICENSE file for details.

69
android/Android.mk Normal file
View File

@ -0,0 +1,69 @@
# FAudioGMS Android.mk file
# PS: Expect hell
SAVED_LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(SAVED_LOCAL_PATH)
SDL_PATH := $(LOCAL_PATH)/../lib/SDL
FAUDIO_PATH := $(LOCAL_PATH)/../lib/FAudio
FAUDIOGMS_PATH := $(LOCAL_PATH)/..
# First we import SDL 2
include $(SDL_PATH)/Android.mk
# Then we compile FAudio as a static library
include $(CLEAR_VARS)
LOCAL_PATH := $(SAVED_LOCAL_PATH)
LOCAL_MODULE := FAudio_static
LOCAL_MODULE_FILENAME := libFAudio
LOCAL_SHARED_LIBRARIES := SDL2
LOCAL_C_INCLUDES := $(SDL_PATH)/include $(FAUDIO_PATH)/include $(FAUDIO_PATH)/src
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_LDLIBS :=
LOCAL_EXPORT_LDLIBS := -ldl -llog -landroid
LOCAL_SRC_FILES := \
$(FAUDIO_PATH)/src/F3DAudio.c \
$(FAUDIO_PATH)/src/FACT3D.c \
$(FAUDIO_PATH)/src/FACT.c \
$(FAUDIO_PATH)/src/FACT_internal.c \
$(FAUDIO_PATH)/src/FAPOBase.c \
$(FAUDIO_PATH)/src/FAPOFX.c \
$(FAUDIO_PATH)/src/FAPOFX_echo.c \
$(FAUDIO_PATH)/src/FAPOFX_eq.c \
$(FAUDIO_PATH)/src/FAPOFX_masteringlimiter.c \
$(FAUDIO_PATH)/src/FAPOFX_reverb.c \
$(FAUDIO_PATH)/src/FAudio.c \
$(FAUDIO_PATH)/src/FAudioFX_reverb.c \
$(FAUDIO_PATH)/src/FAudioFX_volumemeter.c \
$(FAUDIO_PATH)/src/FAudio_internal.c \
$(FAUDIO_PATH)/src/FAudio_internal_simd.c \
$(FAUDIO_PATH)/src/FAudio_operationset.c \
$(FAUDIO_PATH)/src/FAudio_platform_sdl2.c \
$(FAUDIO_PATH)/src/FAudio_platform_win32.c \
$(FAUDIO_PATH)/src/XNA_Song.c \
$(FAUDIO_PATH)/src/FAudio_gstreamer.c
include $(BUILD_STATIC_LIBRARY)
# And then we do our stuff...
include $(CLEAR_VARS)
LOCAL_PATH := $(SAVED_LOCAL_PATH)
LOCAL_MODULE := FAudioGMS
# Tell ndk-build we rely on these two fellas:
LOCAL_SHARED_LIBRARIES := SDL2 FAudio_static
LOCAL_C_INCLUDES := $(SDL_PATH)/include $(FAUDIO_PATH)/include $(FAUDIOGMS_PATH)/src
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := $(FAUDIOGMS_PATH)/src/FAudioGMS.c $(LOCAL_PATH)/FAudioGMS_JNI.c
include $(BUILD_SHARED_LIBRARY)

468
android/FAudioGMS_JNI.c Normal file
View File

@ -0,0 +1,468 @@
/* FAudioGMS - Game Maker FAudio bindings in C
*
* Copyright (c) 2021 Evan Hemsley
*
* 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.
*
* Evan "cosmonaut" Hemsley <evan@moonside.games>
*
*/
/* These are the Native -> JNI conv wrappers, they must only be built for Android */
#ifdef __ANDROID__
/* no mangling please */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <jni.h>
#include <FAudioGMS.h>
/*
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1Init
JNIEXPORT: export this function for JNI
jdouble: return type, a GameMaker function must always return something
JNICALL: JNI calling convention
Java_class_path_here_classNameHere_Function_Name_Here
classpath: org.screwyoyo.faudiogms
classname: FAudioGMSNative
function name: FAudioGMSNative_FAudioGMS_1Init
underscores must be escaped with _1
*/
/* replace this with -1.0 or NAN if you wish... */
/* ideally, a jdouble should map to a double */
#define NOTHING ((jdouble)0.0)
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1Init
(JNIEnv* jniEnv, jclass jniThis, jdouble _spatialDistanceScale, jdouble _timestep)
{
FAudioGMS_Init(_spatialDistanceScale, _timestep);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StaticSound_1LoadWAV
(JNIEnv* jniEnv, jclass jniThis, jstring _filePath)
{
jboolean isCopy;
const char* filePath;
jdouble ret;
filePath = (*jniEnv)->GetStringUTFChars(jniEnv, _filePath, &isCopy);
ret = FAudioGMS_StaticSound_LoadWAV((char *)filePath);
(*jniEnv)->ReleaseStringUTFChars(jniEnv, _filePath, filePath);
return ret;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StaticSound_1CreateSoundInstance
(JNIEnv* jniEnv, jclass jniThis, jdouble _staticSoundID)
{
return (jdouble)FAudioGMS_StaticSound_CreateSoundInstance(_staticSoundID);
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StaticSound_1Destroy
(JNIEnv* jniEnv, jclass jniThis, jdouble _staticSoundID)
{
FAudioGMS_StaticSound_Destroy(_staticSoundID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StreamingSound_1LoadOGG
(JNIEnv* jniEnv, jclass jniThis, jstring _filepath, jdouble _bufferSizeInBytes)
{
jboolean isCopy;
const char* filepath;
jdouble ret;
filepath = (*jniEnv)->GetStringUTFChars(jniEnv, _filepath, &isCopy);
ret = FAudioGMS_StreamingSound_LoadOGG((char *)filepath, _bufferSizeInBytes);
(*jniEnv)->ReleaseStringUTFChars(jniEnv, _filepath, filepath);
return ret;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Play
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_Play(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Pause
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_Pause(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Stop
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_Stop(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1QueueSyncPlay
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_QueueSyncPlay(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SyncPlay
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_SoundInstance_SyncPlay();
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetPlayRegion
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _startInMilliseconds, jdouble _endInMilliseconds)
{
FAudioGMS_SoundInstance_SetPlayRegion(_soundInstanceID, _startInMilliseconds, _endInMilliseconds);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetLoop
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _loop)
{
FAudioGMS_SoundInstance_SetLoop(_soundInstanceID, _loop);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetPan
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _pan)
{
FAudioGMS_SoundInstance_SetPan(_soundInstanceID, _pan);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetPitch
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _pitch)
{
FAudioGMS_SoundInstance_SetPitch(_soundInstanceID, _pitch);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetVolume
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _volume)
{
FAudioGMS_SoundInstance_SetVolume(_soundInstanceID, _volume);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Set3DPosition
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _x, jdouble _y, jdouble _z)
{
FAudioGMS_SoundInstance_Set3DPosition(_soundInstanceID, _x, _y, _z);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Set3DVelocity
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _xVelocity, jdouble _yVelocity, jdouble _zVelocity)
{
FAudioGMS_SoundInstance_Set3DVelocity(_soundInstanceID, _xVelocity, _yVelocity, _zVelocity);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Set3DOrientation
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _xFront, jdouble _yFront, jdouble _zFront, jdouble _xTop, jdouble _yTop, jdouble _zTop)
{
FAudioGMS_SoundInstance_Set3DOrientation(_soundInstanceID, _xFront, _yFront, _zFront, _xTop, _yTop, _zTop);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetTrackPositionInSeconds
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _trackPositionInSeconds)
{
FAudioGMS_SoundInstance_SetTrackPositionInSeconds(_soundInstanceID, _trackPositionInSeconds);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetVolumeOverTime
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _volume, jdouble _milliseconds)
{
FAudioGMS_SoundInstance_SetVolumeOverTime(_soundInstanceID, _volume, _milliseconds);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetLowPassFilter
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _lowPassFilter, jdouble _Q)
{
FAudioGMS_SoundInstance_SetLowPassFilter(_soundInstanceID, _lowPassFilter, _Q);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetHighPassFilter
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _highPassFilter, jdouble _Q)
{
FAudioGMS_SoundInstance_SetHighPassFilter(_soundInstanceID, _highPassFilter, _Q);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetBandPassFilter
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _bandPassFilter, jdouble _Q)
{
FAudioGMS_SoundInstance_SetBandPassFilter(_soundInstanceID, _bandPassFilter, _Q);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1QueueSoundInstance
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _queueSoundInstanceID)
{
FAudioGMS_SoundInstance_QueueSoundInstance(_soundInstanceID, _queueSoundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1GetPitch
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
return (jdouble)FAudioGMS_SoundInstance_GetPitch(_soundInstanceID);
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1GetVolume
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
return (jdouble)FAudioGMS_SoundInstance_GetVolume(_soundInstanceID);
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1GetTrackLengthInSeconds
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
return (jdouble)FAudioGMS_SoundInstance_GetTrackLengthInSeconds(_soundInstanceID);
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1GetTrackPositionInSeconds
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
return (jdouble)FAudioGMS_SoundInstance_GetTrackPositionInSeconds(_soundInstanceID);
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1Destroy
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_Destroy(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1DestroyWhenFinished
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID)
{
FAudioGMS_SoundInstance_DestroyWhenFinished(_soundInstanceID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1EffectChain_1Create
(JNIEnv* jniEnv, jclass jniThis)
{
return (jdouble)FAudioGMS_EffectChain_Create();
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1EffectChain_1AddDefaultReverb
(JNIEnv* jniEnv, jclass jniThis, jdouble _effectChainID)
{
FAudioGMS_EffectChain_AddDefaultReverb(_effectChainID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1EffectChain_1AddReverb
(JNIEnv* jniEnv, jclass jniThis,
jdouble _effectChainID,
jdouble _wetDryMix,
jdouble _reflectionsDelay,
jdouble _reverbDelay,
jdouble _earlyDiffusion,
jdouble _lateDiffusion,
jdouble _lowEQGain,
jdouble _lowEQCutoff,
jdouble _highEQGain,
jdouble _highEQCutoff,
jdouble _reflectionsGain,
jdouble _reverbGain,
jdouble _decayTime,
jdouble _density,
jdouble _roomSize)
{
FAudioGMS_EffectChain_AddReverb(
_effectChainID,
_wetDryMix,
_reflectionsDelay,
_reverbDelay,
_earlyDiffusion,
_lateDiffusion,
_lowEQGain,
_lowEQCutoff,
_highEQGain,
_highEQCutoff,
_reflectionsGain,
_reverbGain,
_decayTime,
_density,
_roomSize);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1EffectChain_1Destroy
(JNIEnv* jniEnv, jclass jniThis, jdouble _effectChainID)
{
FAudioGMS_EffectChain_Destroy(_effectChainID);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetEffectChain
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _effectChainID, jdouble _effectGain)
{
FAudioGMS_SoundInstance_SetEffectChain(_soundInstanceID, _effectChainID, _effectGain);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SoundInstance_1SetEffectGain
(JNIEnv* jniEnv, jclass jniThis, jdouble _soundInstanceID, jdouble _effectGain)
{
FAudioGMS_SoundInstance_SetEffectGain(_soundInstanceID, _effectGain);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetMasteringEffectChain
(JNIEnv* jniEnv, jclass jniThis, jdouble _effectChainID, double _effectGain)
{
FAudioGMS_SetMasteringEffectChain(_effectChainID, _effectGain);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetMasteringEffectGain
(JNIEnv* jniEnv, jclass jniThis, jdouble _effectGain)
{
FAudioGMS_SetMasteringEffectGain(_effectGain);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetListenerPosition
(JNIEnv* jniEnv, jclass jniThis, jdouble _x, jdouble _y, jdouble _z)
{
FAudioGMS_SetListenerPosition(_x, _y, _z);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetListenerVelocity
(JNIEnv* jniEnv, jclass jniThis, jdouble _xVelocity, jdouble _yVelocity, jdouble _zVelocity)
{
FAudioGMS_SetListenerVelocity(_xVelocity, _yVelocity, _zVelocity);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1SetListenerOrientation
(JNIEnv* jniEnv, jclass jniThis, jdouble _xFront, jdouble _yFront, jdouble _zFront, jdouble _xTop, jdouble _yTop, jdouble _zTop)
{
FAudioGMS_SetListenerOrientation(_xFront, _yFront, _zFront, _xTop, _yTop, _zTop);
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1PauseAll
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_PauseAll();
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1ResumeAll
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_ResumeAll();
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1StopAll
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_StopAll();
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1Update
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_Update();
return NOTHING;
}
JNIEXPORT jdouble JNICALL
Java_org_screwyoyo_faudiogms_FAudioGMSNative_FAudioGMS_1Destroy
(JNIEnv* jniEnv, jclass jniThis)
{
FAudioGMS_Destroy();
return NOTHING;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ANDROID__ */
/* Do nothing for other platforms, because they, thankly, do not require JNI bindings... */

8
android/build.ndk.cmd Normal file
View File

@ -0,0 +1,8 @@
cd /d %~dp0
mkdir buildandroid
call ndk-build NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=Android.mk APP_ABI="armeabi-v7a arm64-v8a x86 x86_64" APP_PLATFORM=android-16 APP_MODULES="SDL2 FAudio_static FAudioGMS" NDK_OUT=buildandroid\obj NDK_LIBS_OUT=buildandroid\lib
xcopy /e /r /y buildandroid\lib ..\gamemaker\extensions\FAudioGMS\AndroidSource\libs
rd /s /q buildandroid

24
android/build.ndk.sh Normal file
View File

@ -0,0 +1,24 @@
#!/bin/sh
cd `dirname $0`
# rm -rf buildandroid
mkdir -p buildandroid
# Make sure you have ndk-build and Android Sdk stuff in your $PATH!
ndk-build \
NDK_PROJECT_PATH=null \
APP_BUILD_SCRIPT=Android.mk \
APP_ABI="armeabi-v7a arm64-v8a x86 x86_64" \
APP_PLATFORM=android-16 \
APP_MODULES="SDL2 FAudio_static FAudioGMS" \
NDK_OUT=buildandroid/obj \
NDK_LIBS_OUT=buildandroid/lib
# Update gamemaker project folder..
cp -rf buildandroid/lib/* ../gamemaker/extensions/FAudioGMS/AndroidSource/libs
rm -rf buildandroid
# we're done here.

View File

@ -0,0 +1,58 @@
{
"resources": [
{"id":{"name":"AUDIO","path":"objects/AUDIO/AUDIO.yy",},"order":0,},
{"id":{"name":"FAudioGMS","path":"extensions/FAudioGMS/FAudioGMS.yy",},"order":0,},
{"id":{"name":"FAudioGMS_Scripts","path":"scripts/FAudioGMS_Scripts/FAudioGMS_Scripts.yy",},"order":0,},
{"id":{"name":"Room1","path":"rooms/Room1/Room1.yy",},"order":0,},
],
"Options": [
{"name":"Linux","path":"options/linux/options_linux.yy",},
{"name":"macOS","path":"options/mac/options_mac.yy",},
{"name":"Main","path":"options/main/options_main.yy",},
{"name":"Windows","path":"options/windows/options_windows.yy",},
{"name":"operagx","path":"options/operagx/options_operagx.yy",},
],
"isDnDProject": false,
"isEcma": false,
"tutorialPath": "",
"configs": {
"name": "Default",
"children": [],
},
"RoomOrderNodes": [
{"roomId":{"name":"Room1","path":"rooms/Room1/Room1.yy",},},
],
"Folders": [
{"folderPath":"folders/Sprites.yy","order":1,"resourceVersion":"1.0","name":"Sprites","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Tile Sets.yy","order":2,"resourceVersion":"1.0","name":"Tile Sets","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Sounds.yy","order":3,"resourceVersion":"1.0","name":"Sounds","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Paths.yy","order":4,"resourceVersion":"1.0","name":"Paths","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Scripts.yy","order":5,"resourceVersion":"1.0","name":"Scripts","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Shaders.yy","order":6,"resourceVersion":"1.0","name":"Shaders","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Fonts.yy","order":7,"resourceVersion":"1.0","name":"Fonts","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Timelines.yy","order":8,"resourceVersion":"1.0","name":"Timelines","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Objects.yy","order":9,"resourceVersion":"1.0","name":"Objects","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Rooms.yy","order":10,"resourceVersion":"1.0","name":"Rooms","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Sequences.yy","order":11,"resourceVersion":"1.0","name":"Sequences","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Animation Curves.yy","order":12,"resourceVersion":"1.0","name":"Animation Curves","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Notes.yy","order":13,"resourceVersion":"1.0","name":"Notes","tags":[],"resourceType":"GMFolder",},
{"folderPath":"folders/Extensions.yy","order":14,"resourceVersion":"1.0","name":"Extensions","tags":[],"resourceType":"GMFolder",},
],
"AudioGroups": [
{"targets":-1,"resourceVersion":"1.3","name":"audiogroup_default","resourceType":"GMAudioGroup",},
],
"TextureGroups": [
{"isScaled":true,"autocrop":true,"border":2,"mipsToGenerate":0,"groupParent":null,"targets":-1,"resourceVersion":"1.3","name":"Default","resourceType":"GMTextureGroup",},
],
"IncludedFiles": [
{"CopyToMask":-1,"filePath":"datafiles/audio/static","resourceVersion":"1.0","name":"Put your static audio here.txt","resourceType":"GMIncludedFile",},
{"CopyToMask":-1,"filePath":"datafiles/audio/streaming","resourceVersion":"1.0","name":"Put your streaming audio here.txt","resourceType":"GMIncludedFile",},
],
"MetaData": {
"IDEVersion": "2.3.6.595",
},
"resourceVersion": "1.4",
"name": "FAudioGMSTemplate",
"tags": [],
"resourceType": "GMProject",
}

View File

@ -0,0 +1,142 @@
package ${YYAndroidPackageName}; /* this class will reside in Runner's package namespace */
import java.lang.String;
import android.util.Log;
import android.content.Intent;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.app.Dialog;
import android.view.MotionEvent;
import org.screwyoyo.faudiogms.FAudioGMSNative;
import org.libsdl.app.SDLActivity;
import org.libsdl.app.SDL;
import org.libsdl.app.SDLAudioManager;
import com.yoyogames.runner.RunnerJNILib;
import android.content.res.AssetManager;
public class FAudioGMSBridge extends FAudioGMSNative implements IExtensionBase
{
public SDLActivity sdl;
public boolean handlenativepause; /* automatically pause all sounds on onPause or not? */
public boolean paused; /* are we currently paused */
public FAudioGMSBridge()
{
super();
handlenativepause = true; /* set this to false if you wish to handle pauses manually */
paused = false; /* this one must be false at initialization */
SDL.setContext(RunnerJNILib.GetApplicationContext());
sdl = new SDLActivity();
}
public void Init()
{
SDL.setContext(RunnerJNILib.GetApplicationContext());
sdl.onCreate(null);
}
public void onStart()
{
SDL.setContext(RunnerJNILib.GetApplicationContext());
sdl.onStart();
}
public void onRestart()
{
onStart();
}
public void onStop()
{
sdl.onStop();
}
public void onDestroy()
{
sdl.onDestroy();
}
public void onPause()
{
sdl.onPause();
if (handlenativepause && !paused)
{
paused = true;
FAudioGMS_PauseAll();
}
}
public void onResume()
{
sdl.onResume();
if (handlenativepause && paused)
{
paused = false;
FAudioGMS_ResumeAll();
}
}
public void onWindowFocusChanged(boolean hasFocus)
{
sdl.onWindowFocusChanged(hasFocus);
}
public void onConfigurationChanged(Configuration newConfig)
{
sdl.onConfigurationChanged(newConfig);
}
public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults)
{
sdl.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
public Dialog onCreateDialog(int id)
{
return null;
}
public boolean onTouchEvent(final MotionEvent event)
{
return false;
}
public boolean onGenericMotionEvent(MotionEvent event)
{
return false;
}
public boolean dispatchKeyEvent(KeyEvent event)
{
return false;
}
public boolean dispatchGenericMotionEvent(MotionEvent event)
{
return false;
}
public boolean performClick()
{
return false;
}
public void onNewIntent(android.content.Intent newIntent)
{
}
public void onActivityResult(int requestCode, int resultCode, Intent data){}
public boolean onKeyLongPress(int keyCode, KeyEvent event){return false;}
public boolean onCreateOptionsMenu( Menu menu ){return false;}
public boolean onOptionsItemSelected( MenuItem item ){return false;}
public boolean onKeyDown( int keyCode, KeyEvent event )
{ return false;}
public boolean onKeyUp( int keyCode, KeyEvent event ){return false;}
}

View File

@ -0,0 +1,15 @@
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 28
}
repositories {
mavenCentral()
}
dependencies {
compile 'com.getkeepsafe.relinker:relinker:1.4.4'
}

View File

@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.screwyoyo.faudiogms">
</manifest>

View File

@ -0,0 +1,22 @@
package org.libsdl.app;
import android.hardware.usb.UsbDevice;
interface HIDDevice
{
public int getId();
public int getVendorId();
public int getProductId();
public String getSerialNumber();
public int getVersion();
public String getManufacturerName();
public String getProductName();
public UsbDevice getDevice();
public boolean open();
public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report);
public boolean getFeatureReport(byte[] report);
public void setFrozen(boolean frozen);
public void close();
public void shutdown();
}

View File

@ -0,0 +1,649 @@
package org.libsdl.app;
import android.content.Context;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.os.*;
//import com.android.internal.util.HexDump;
import java.lang.Runnable;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.UUID;
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
private static final String TAG = "hidapi";
private HIDDeviceManager mManager;
private BluetoothDevice mDevice;
private int mDeviceId;
private BluetoothGatt mGatt;
private boolean mIsRegistered = false;
private boolean mIsConnected = false;
private boolean mIsChromebook = false;
private boolean mIsReconnecting = false;
private boolean mFrozen = false;
private LinkedList<GattOperation> mOperations;
GattOperation mCurrentOperation = null;
private Handler mHandler;
private static final int TRANSPORT_AUTO = 0;
private static final int TRANSPORT_BREDR = 1;
private static final int TRANSPORT_LE = 2;
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
static class GattOperation {
private enum Operation {
CHR_READ,
CHR_WRITE,
ENABLE_NOTIFICATION
}
Operation mOp;
UUID mUuid;
byte[] mValue;
BluetoothGatt mGatt;
boolean mResult = true;
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mValue = value;
}
public void run() {
// This is executed in main thread
BluetoothGattCharacteristic chr;
switch (mOp) {
case CHR_READ:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Reading characteristic " + chr.getUuid());
if (!mGatt.readCharacteristic(chr)) {
Log.e(TAG, "Unable to read characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case CHR_WRITE:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing characteristic " + chr.getUuid() + " value=" + HexDump.toHexString(value));
chr.setValue(mValue);
if (!mGatt.writeCharacteristic(chr)) {
Log.e(TAG, "Unable to write characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case ENABLE_NOTIFICATION:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing descriptor of " + chr.getUuid());
if (chr != null) {
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
int properties = chr.getProperties();
byte[] value;
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
} else {
Log.e(TAG, "Unable to start notifications on input characteristic");
mResult = false;
return;
}
mGatt.setCharacteristicNotification(chr, true);
cccd.setValue(value);
if (!mGatt.writeDescriptor(cccd)) {
Log.e(TAG, "Unable to write descriptor " + mUuid.toString());
mResult = false;
return;
}
mResult = true;
}
}
}
}
public boolean finish() {
return mResult;
}
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
return null;
return valveService.getCharacteristic(uuid);
}
static public GattOperation readCharacteristic(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.CHR_READ, uuid);
}
static public GattOperation writeCharacteristic(BluetoothGatt gatt, UUID uuid, byte[] value) {
return new GattOperation(gatt, Operation.CHR_WRITE, uuid, value);
}
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
}
}
public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
mManager = manager;
mDevice = device;
mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
mIsRegistered = false;
mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
mOperations = new LinkedList<GattOperation>();
mHandler = new Handler(Looper.getMainLooper());
mGatt = connectGatt();
// final HIDDeviceBLESteamController finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// finalThis.checkConnectionForChromebookIssue();
// }
// }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
public String getIdentifier() {
return String.format("SteamController.%s", mDevice.getAddress());
}
public BluetoothGatt getGatt() {
return mGatt;
}
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
private BluetoothGatt connectGatt(boolean managed) {
if (Build.VERSION.SDK_INT >= 23) {
try {
return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
} catch (Exception e) {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
} else {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
}
private BluetoothGatt connectGatt() {
return connectGatt(false);
}
protected int getConnectionState() {
Context context = mManager.getContext();
if (context == null) {
// We are lacking any context to get our Bluetooth information. We'll just assume disconnected.
return BluetoothProfile.STATE_DISCONNECTED;
}
BluetoothManager btManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
if (btManager == null) {
// This device doesn't support Bluetooth. We should never be here, because how did
// we instantiate a device to start with?
return BluetoothProfile.STATE_DISCONNECTED;
}
return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
}
public void reconnect() {
if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
mGatt.disconnect();
mGatt = connectGatt();
}
}
protected void checkConnectionForChromebookIssue() {
if (!mIsChromebook) {
// We only do this on Chromebooks, because otherwise it's really annoying to just attempt
// over and over.
return;
}
int connectionState = getConnectionState();
switch (connectionState) {
case BluetoothProfile.STATE_CONNECTED:
if (!mIsConnected) {
// We are in the Bad Chromebook Place. We can force a disconnect
// to try to recover.
Log.v(TAG, "Chromebook: We are in a very bad state; the controller shows as connected in the underlying Bluetooth layer, but we never received a callback. Forcing a reconnect.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
else if (!isRegistered()) {
if (mGatt.getServices().size() > 0) {
Log.v(TAG, "Chromebook: We are connected to a controller, but never got our registration. Trying to recover.");
probeService(this);
}
else {
Log.v(TAG, "Chromebook: We are connected to a controller, but never discovered services. Trying to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
}
else {
Log.v(TAG, "Chromebook: We are connected, and registered. Everything's good!");
return;
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.v(TAG, "Chromebook: We have either been disconnected, or the Chromebook BtGatt.ContextMap bug has bitten us. Attempting a disconnect/reconnect, but we may not be able to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
case BluetoothProfile.STATE_CONNECTING:
Log.v(TAG, "Chromebook: We're still trying to connect. Waiting a bit longer.");
break;
}
final HIDDeviceBLESteamController finalThis = this;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finalThis.checkConnectionForChromebookIssue();
}
}, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
private boolean isRegistered() {
return mIsRegistered;
}
private void setRegistered() {
mIsRegistered = true;
}