comparison android/src/org/libsdl/app/SDLAudioManager.java @ 1839:78abbabfd58d

Get Android build working again and update for SDL 2.0.7 (last version to support older versions of Android)
author Michael Pavone <pavone@retrodev.com>
date Sun, 14 Apr 2019 23:37:11 -0700
parents
children
comparison
equal deleted inserted replaced
1836:601ef72cc16f 1839:78abbabfd58d
1 package org.libsdl.app;
2
3 import android.media.*;
4 import android.util.Log;
5
6 public class SDLAudioManager
7 {
8 protected static final String TAG = "SDLAudio";
9
10 protected static AudioTrack mAudioTrack;
11 protected static AudioRecord mAudioRecord;
12
13 public static void initialize() {
14 mAudioTrack = null;
15 mAudioRecord = null;
16 }
17
18 // Audio
19
20 /**
21 * This method is called by SDL using JNI.
22 */
23 public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
24 int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
25 int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
26 int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
27
28 Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
29
30 // Let the user pick a larger buffer if they really want -- but ye
31 // gods they probably shouldn't, the minimums are horrifyingly high
32 // latency already
33 desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
34
35 if (mAudioTrack == null) {
36 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
37 channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
38
39 // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
40 // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
41 // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
42
43 if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
44 Log.e(TAG, "Failed during initialization of Audio Track");
45 mAudioTrack = null;
46 return -1;
47 }
48
49 mAudioTrack.play();
50 }
51
52 Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
53
54 return 0;
55 }
56
57 /**
58 * This method is called by SDL using JNI.
59 */
60 public static void audioWriteShortBuffer(short[] buffer) {
61 if (mAudioTrack == null) {
62 Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
63 return;
64 }
65
66 for (int i = 0; i < buffer.length; ) {
67 int result = mAudioTrack.write(buffer, i, buffer.length - i);
68 if (result > 0) {
69 i += result;
70 } else if (result == 0) {
71 try {
72 Thread.sleep(1);
73 } catch(InterruptedException e) {
74 // Nom nom
75 }
76 } else {
77 Log.w(TAG, "SDL audio: error return from write(short)");
78 return;
79 }
80 }
81 }
82
83 /**
84 * This method is called by SDL using JNI.
85 */
86 public static void audioWriteByteBuffer(byte[] buffer) {
87 if (mAudioTrack == null) {
88 Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
89 return;
90 }
91
92 for (int i = 0; i < buffer.length; ) {
93 int result = mAudioTrack.write(buffer, i, buffer.length - i);
94 if (result > 0) {
95 i += result;
96 } else if (result == 0) {
97 try {
98 Thread.sleep(1);
99 } catch(InterruptedException e) {
100 // Nom nom
101 }
102 } else {
103 Log.w(TAG, "SDL audio: error return from write(byte)");
104 return;
105 }
106 }
107 }
108
109 /**
110 * This method is called by SDL using JNI.
111 */
112 public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
113 int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
114 int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
115 int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
116
117 Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
118
119 // Let the user pick a larger buffer if they really want -- but ye
120 // gods they probably shouldn't, the minimums are horrifyingly high
121 // latency already
122 desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
123
124 if (mAudioRecord == null) {
125 mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
126 channelConfig, audioFormat, desiredFrames * frameSize);
127
128 // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
129 if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
130 Log.e(TAG, "Failed during initialization of AudioRecord");
131 mAudioRecord.release();
132 mAudioRecord = null;
133 return -1;
134 }
135
136 mAudioRecord.startRecording();
137 }
138
139 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");
140
141 return 0;
142 }
143
144 /** This method is called by SDL using JNI. */
145 public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
146 // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
147 //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
148 return mAudioRecord.read(buffer, 0, buffer.length);
149 }
150
151 /** This method is called by SDL using JNI. */
152 public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
153 // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
154 //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
155 return mAudioRecord.read(buffer, 0, buffer.length);
156 }
157
158
159 /** This method is called by SDL using JNI. */
160 public static void audioClose() {
161 if (mAudioTrack != null) {
162 mAudioTrack.stop();
163 mAudioTrack.release();
164 mAudioTrack = null;
165 }
166 }
167
168 /** This method is called by SDL using JNI. */
169 public static void captureClose() {
170 if (mAudioRecord != null) {
171 mAudioRecord.stop();
172 mAudioRecord.release();
173 mAudioRecord = null;
174 }
175 }
176
177 public static native int nativeSetupJNI();
178 }