distributing work-in-progress android projects

I’ve made a small program (two buttons: one turns on and off a synth tone, the other a “sound field” tool that generates chimes similar to a windchime). The code is a Java audio library combined with a “wrapper” I wrote to allow you to use the library in Android.

I was wondering about the possibility of getting feedback. I don’t have any devices yet, am just working with the emulator. I’m wondering how much cpu the audio thread consumes on various devices, whether I’m keeping the efficiency high enough that it won’t interfere with game graphics.

From reading various posts, it seems that if I simply post the “debug” apk, people will not be able to run it. Is this true? There is also a “debug-unaligned” apk that was generated automatically. I’m not sure how I did it, but I also have a “release-unsigned” apk made yesterday. :clue: This is the first time I started thinking about the actual process of making a release. With Java, making a jar is pretty straightforward and easy.

Is it really needed to create the signed certificate to do any distribution?

As far as I know, no you don’t need to sign the APK. That’s only if you wish to distribute it on the Play Store. You can distribute the APK that your IDE generates and people who want to install your APK will have to enable an option in their developer settings on their phone to allow for third party applications (applications not installed through the Play Store). Is that what you’re asking?

As always, the first question is: what happened when you tried?

Signing the APK is not a big deal- in fact eclipse can do it for you. You don’t have to pay for a certificate or anything.

Post a link to the APK you’re creating and we can try it out.

Thanks!
I am just getting started with this and didn’t even know what to try! Very much a newbie with Android dev.

I have loaded the apk file to the following url:
http://hexara.com/androiddev/app-debug.apk

This is the file automatically generated by Android Studio, found in the directory:
[project name = AudioTest]/app/build/outputs/apk

It looked like creating a certificate, going through the signature process might not be such a big deal with Android Studio. But since it is new to me, and thus a mystery, I am not sure what complications might be involved. Does one have to be careful about picking various names and passwords, since one is encouraged to use the same certificate for the next 32 years or something like that? Questions like these make me want to bypass if possible for now and deal with them after a bit more research.

I just tried it and it works fine for me. The sounds play, although the one sound doesn’t seem to stop when I push the button again.

I do have the “other sources” box checked in my security settings.

[Edited]
@KevinWorkman – Thanks for trying the app, and the instructions on loading ‘debug’ apks.

I’m also curious if there is a way you can judge how much cpu is being consumed while the “windchime” and the synth tone are playing. There are up to about a dozen sounds being generated and playing concurrently, when you consider the overlapping bells, though I have provisioned for 20 playing at once. My hope is to keep the consumption below 10% so that there is plenty room for graphics.

I can’t seem to duplicate your error of the synth tone not turning off. The synth tone should completely die away after about a second or two at the most. Curious, now the ‘WindChime’ is causing a crash for me when turning it on a second time (after stopping it). [WindChime bug found, but haven’t fixed/updated yet–will probably do tomorrow.]

Time for some debugging!

I think I have a lead on a device I can borrow. The fellow says a client gave it to him for dev testing on a project he was hired for, and that the client had bought it for $10 and then not signed up for the pricey phone service that was part of the deal. Sounds a little iffy, but I’m not clear if any actual laws were broken in the process.

I have a Motorola Moto G android, which is not a powerful device.
The first time I ran it, as soon as I hit the “play” button the horn (?) sound started, but choppy. the sound would break ~ 2 times per second.
When I turned on the chimes it became a little worse, like 3 chops pers second. I tried to start/stop the sounds a few times, not sure if it really worked since the sound kept playing. after a few button presses I got a “force close”.

I plugged in my usb and opened logcat and started it again. this time the first sound didn’t chop at all, the choppiness started when I pressed the chime. After a few button presses I got this (sorry but logcat doesn’t allow a simple ctrl c ctrl v):

I fixed the error due to the ThreadPool being closed prematurely. (Error shown by teletubo.)

I didn’t realize until just now that opiop65 message was saying the same thing as KevinWorkman explained about the ‘other sources’ box in the security settings. So thanks for that!

My reading comprehension level: iffy. It helps me a lot to have an example as well as a statement of general theory/purpose.

So far though, while I am excited the gist of the program runs, I don’t understand the error (can’t recreate) where the sustain tone refused to turn off. Also, I may have to scale back hopes, if the code I wrote is unable to run without hogging cpu, if it can run at all without dropouts. Maybe this library, as currently written, will only work with the most powerful Android devices, or only with future devices, as they come up to or exceed the performance standards of desk tops of the last couple years.

Is the following useful/interesting? Maybe I should post elsewhere (audio thread, or under its own subject). Here is the Android wrapper code I wrote for the library. OK to share. Maybe it can be edited to allow another library to work on Android, e.g., TinySound. It only covers playback, though, not loading of sound files. I haven’t written that part yet.

public class AudioWrapper {

    private CoreMixer coreMix;
    public final int FRAME_SIZE;
    public final int SAMPLE_RATE;
    private volatile boolean playing;
    private Thread t;

    public AudioWrapper(CoreMixer cm) {
        this.FRAME_SIZE = 4;
        this.SAMPLE_RATE = 44100;
        this.coreMix = cm;
    }

    public void start() throws IllegalStateException {
        if(this.playing) {
            throw new IllegalStateException("Already running.");
        } else {
            coreMix.prepareToGo();
            playing = true;

            AudioWrapper.FrameMixerPlayer mixerPlayer =
                    new AudioWrapper.FrameMixerPlayer();
            t = new Thread(mixerPlayer);
            t.start();
        }
    }

    public void stop() throws IllegalStateException {
        if(!this.playing) {
            throw new IllegalStateException("Already stopped.");
        } else {
            playing = false;
            coreMix.setToStop();

            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t = null;
        }
    }

    private class FrameMixerPlayer implements Runnable {
        private FrameMixerPlayer() {}

        public void run() {

            int bufferSize = AudioTrack.getMinBufferSize(
                    SAMPLE_RATE,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT);

            AudioTrack audioTrack = new AudioTrack(
                    AudioManager.STREAM_MUSIC,
                    SAMPLE_RATE,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize,
                    AudioTrack.MODE_STREAM);

            audioTrack.play();

            short[] samples = new short[bufferSize];

            float[] e = new float[2];
            int i = 0;

            while(AudioWrapper.this.playing) {
                while(i < bufferSize) {
                    e[0] = 0;
                    e[1] = 0;
                    coreMix.getFrame(e);
                    samples[i++] = (short)(e[0] * 32767);
                    samples[i++] = (short)(e[1] * 32767);
                }
                audioTrack.write(samples, 0, bufferSize);
                i = 0;
            }
            System.out.println("FrameMixerPlayer.run exiting");
        }
    }
}

AudioTrack is the Android class used for audio playback. In later implementations, other forms besides loading an array of Shorts has become possible. I’ve not tested yet which might be the fastest. The data from my end is currently -1 to 1 (floats).

The only link to my AudioLibrary is with the class I wrote called CoreMixer. An instance is passed in when the wrapper is instantiated.

The CoreMixer class exposes a read() method which returns a frame of sound. The read() can easily be altered to retrieve a full buffer’s worth instead, depending on how the target audio library works. Perhaps I will try making that change in my library, though a lot of the functionality in it assumes working one frame at a time.
I also exposed prepareToGo() and setToStart() methods to handle some starting and cleanup chores in the library class.