Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AudioTrack release

I am wondering if I need to call release on an audio track?

For example, in my following code I instantiate a AudioTrack instance in a method, and do not call release on it (because that stops play).

What are the repercussions of this?

public void playTone()
{
    float[] output = createTone();

    AudioTrack track = new AudioTrack(AudioManager.STREAM_RING, 44100,
            AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            (output.length*4),
            AudioTrack.MODE_STATIC);

    short[] result =  new short[output.length];

    for(int i = 0; i < output.length; i++)
        result[i] = (short) ((output[i])*32768);

    track.write(result, 0, output.length);
    track.play();
}
like image 811
Scorb Avatar asked Feb 17 '16 00:02

Scorb


People also ask

What is Android AudioTrack?

android.media.AudioTrack. The AudioTrack class manages and plays a single audio resource for Java applications. It allows streaming of PCM audio buffers to the audio sink for playback.

What is audio track?

Term: Track (audio) Definition: A single stream of recorded sound with no location in a sound field. Although the term track has historically been used in the context of fixed media, e.g., "a four-track tape," this glossary's definition focuses on the processed signal and not the storage medium.


2 Answers

This causes a temporary resource leak, but not a permanent one. Eventually, the garbage collector will release all the memory and resources. But you might want to call release() to avoid errors, because "eventually" might not be soon enough.

I've verified on an Android 4.4.2 device that when a streaming AudioTrack is no longer referenced anywhere, and garbage collection is run, it will be finalized, whether or not stop() has been called.

In Android's source code (I looked at Android N's), finalize() calls the same native function as release() does:

static void android_media_AudioTrack_finalize(JNIEnv *env,  jobject thiz) {
    //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
    android_media_AudioTrack_release(env, thiz);
}

So yes, eventually, the resources will be released without you needing to call release() explicitly.

But this could be a problem if too many AudioTracks are created in a short period of time. Creating and dereferencing them in a loop:

for (...) {
    new AudioTrack(...);
}

I eventually get this error in my logs:

E/AudioTrack-JNI: Error initializing AudioTrack
E/android.media.AudioTrack: Error code -20 when initializing AudioTrack.
E/AudioTrack: AudioFlinger could not create track, status: -12

Garbage collection didn't fix this; it wasn't run because there was enough normal heap memory available. Other resources, of the type that release() releases, ran out. This error didn't trigger immediate garbage collection. Calling release(), of course, fixes this problem.

like image 184
Dan Getz Avatar answered Oct 03 '22 13:10

Dan Getz


If you don't call release(), you will leak the native memory behind the Java AudioTrack object. AudioTrack is not all entirely Java, so the call is required to let the native code to free its own memory because it won't be garbage collected.

You should always call release() when done to avoid problems related to consuming too much memory in your app.

like image 20
Doug Stevenson Avatar answered Oct 03 '22 13:10

Doug Stevenson