Mercurial > repos > blastem
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 } |