Tuesday, July 22, 2014

OpenAL with Android NDK.

This posting is for future reference, if I ever have to get OpenAL working again under Android's NDK. It will also be useful to my peer game developers who intend to do the same.

Step 1

Get an Android port of openal-soft.

Step 2

I like to build static libraries for android game dev, instead of dynamic ones. So I replaced the jni/Android.mk with my own:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

OPENAL_DIR := OpenAL

AL_SOURCES := \
  $(OPENAL_DIR)/Alc/android.c              \
  $(OPENAL_DIR)/OpenAL32/alAuxEffectSlot.c \
  $(OPENAL_DIR)/OpenAL32/alBuffer.c        \
  $(OPENAL_DIR)/OpenAL32/alDatabuffer.c    \
  $(OPENAL_DIR)/OpenAL32/alEffect.c        \
  $(OPENAL_DIR)/OpenAL32/alError.c         \
  $(OPENAL_DIR)/OpenAL32/alExtension.c     \
  $(OPENAL_DIR)/OpenAL32/alFilter.c        \
  $(OPENAL_DIR)/OpenAL32/alListener.c      \
  $(OPENAL_DIR)/OpenAL32/alSource.c        \
  $(OPENAL_DIR)/OpenAL32/alState.c         \
  $(OPENAL_DIR)/OpenAL32/alThunk.c         \
  $(OPENAL_DIR)/Alc/ALc.c                  \
  $(OPENAL_DIR)/Alc/alcConfig.c            \
  $(OPENAL_DIR)/Alc/alcEcho.c              \
  $(OPENAL_DIR)/Alc/alcModulator.c         \
  $(OPENAL_DIR)/Alc/alcReverb.c            \
  $(OPENAL_DIR)/Alc/alcRing.c              \
  $(OPENAL_DIR)/Alc/alcThread.c            \
  $(OPENAL_DIR)/Alc/ALu.c                  \
  $(OPENAL_DIR)/Alc/bs2b.c                 \
  $(OPENAL_DIR)/Alc/null.c                 \
  $(OPENAL_DIR)/Alc/panning.c              \
  $(OPENAL_DIR)/Alc/mixer.c                \
  $(OPENAL_DIR)/Alc/audiotrack.c           \
  $(OPENAL_DIR)/Alc/opensles.c


LOCAL_MODULE    := openal
LOCAL_SRC_FILES := $(AL_SOURCES)

LOCAL_C_INCLUDES := \
  $(HOME)/src/openal-soft/jni/OpenAL \
  $(HOME)/src/openal-soft/jni/OpenAL/include \
  $(HOME)/src/openal-soft/jni/OpenAL/OpenAL32/Include \


LOCAL_CFLAGS += \
  -DAL_ALEXT_PROTOTYPES \

MAX_SOURCES_LOW ?= 4
MAX_SOURCES_START ?= 8
MAX_SOURCES_HIGH ?= 64

LOCAL_CFLAGS += -DMAX_SOURCES_LOW=$(MAX_SOURCES_LOW) -DMAX_SOURCES_START=$(MAX_SOURCES_START) -DMAX_SOURCES_HIGH=$(MAX_SOURCES_HIGH)
LOCAL_CFLAGS += -DPOST_FROYO

include $(BUILD_STATIC_LIBRARY)

Step 3

Get an Android port of freealut.

Step 4

Add an Android.mk file to src/ directory containing:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := alut

LOCAL_SRC_FILES := \
  alutBufferData.c \
  alutCodec.c \
  alutError.c \
  alutInit.c \
  alutInputStream.c \
  alutLoader.c \
  alutOutputStream.c \
  alutUtil.c \
  alutVersion.c \
  alutWaveform.c

LOCAL_C_INCLUDES := \
  $(HOME)/src/freealut/include \
  $(HOME)/src/openal-soft/jni/OpenAL/include \

#LOCAL_CFLAGS +=

include $(BUILD_STATIC_LIBRARY)

Step 5

Some config.h stuff does not properly make it into the source. Not sure why, so I manually edited alutInputStream.c alutInternal.h and alutUtil.c to overcome this.

Step 6

Now you can pull these static libraries into your build by adding to your project's Android.mk file something like this:

LOCAL_STATIC_LIBRARIES += alut openal
...
$(call import-module,openal-soft/jni)
$(call import-module,freealut/src)

UPDATE #1

When porting to MSWindows, I found that OpenAL is pretty tricky there as well. Some info for future reference:
  • You need to link against libOpenAL32.dll.a
  • You need to supply soft_oal.dll with your game, renamed as OpenAL32.dll
  • As with Android and OSX, the CMake stuff of freealut is horribly broken, so you need to pull in the sources to your project and hack around the platform specific stuff.

UPDATE #2

When building for 64bit arm, or arm64-v8a as it is known, I get crashes (SIGSEGV) in alSourcePlay. Maybe openal-soft is not 64 bit safe? The android port is pretty old, as the last change is from 2012.

Wednesday, July 16, 2014

Flight Simulation on touch screens.

My current project is biplane combat simulator. I have been developing it under GNU/Linux, and porting it to Android. It needs a commercially viable platform to run on, and I am pretty sure GNU/Linux games are not making money at the moment. This may change with the Steam box, but for now, I have to look at iOS, Android or maybe a console platform.

After porting my biplane game to Android, I learned a surprising fact: When it comes to flight simulators, there is absolutely no substitute whatsoever for a physical analog joystick. You really need the self-centering stick with plenty of instant feedback if you want to control an airplane.

The first substitute I tried was touch control, with a virtual joystick on the screen. I added snapping-to-center when you release your touch, so that there is some sort of self-centering going on. But this was not enough to make the plane controllable. The lack of tactile feedback means that you have little awareness of the absolute position of the virtual joystick without looking at the control graphics.

I may need to redo this touch control experiment with iOS though. Android is notoriously bad when it comes to responsive touch control. Try this for fun: swipe some content (web page, e.g.) up and down at roughly 5Hz or so. You will see that the motion of the content is opposite of the motion of your finger. If your finger goes up, the content still goes down from your swipe 100ms ago.

I thought that tilt-control (changing pitch and roll of the phone to directly control the virtual flight stick) would fix the awareness issue. But it comes with a loss of snap-to-center functionality. To center the control, you actually have to carefully move the device orientation back to its neutral position. Android now has sensor fusion and can use both gyroscope and accelerometer to accurately determine the gravity vector. But even using this (via Android sensor type 'Gravity') was not enough to constitute a usable control system.

So for now I will make a bold statement: Android and flight simulators do not mix. I guess it means I need to use another platform to release this for. Maybe PC, but then, so far I've not been able to get a project greenlit for Steam, and PC gaming seems to be synonymous to Steam gaming these days.