h6ah4i / android-openslmediaplayer

Re-implementation of Android's MediaPlayer and audio effect classes based on OpenSL ES APIs.
https://openslmediaplayer.h6ah4i.com
Apache License 2.0
418 stars 97 forks source link

UnsupportedOperationException: Control lost #14

Closed roomtek closed 8 years ago

roomtek commented 8 years ago

List masterlist = new ArrayList<>();

IEqualizer.Settings eqsettings = equalizer.getProperties();

        int count = getNumberOfPresets();

        for (short i = 0; i < count; i++) {
            // loops through presets
            try {
                EQPresetDO preset = new EQPresetDO();
                preset.id = i;
                preset.name = equalizer.getPresetName(i);
                preset.bands = new short[bandscount];
                preset.bandstoapply = new short[bandscount];
                preset.minRANGEmax = minRANGEmax;

                equalizer.usePreset(i);

                for (short n = 0; n < bandscount; n++) {
                    // loops through preset bands
                    preset.bandstoapply[n] = equalizer.getBandLevel(n);
                    preset.bands[n] = (short) (preset.bandstoapply[n] + maxEQLevel);
                }

                masterlist.add(preset);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

This exception occurs after the completed MediaPlayer switches to the next MediaPlayer when gaplessplayback is setup, and then the above code runs:

W/System.err: java.lang.UnsupportedOperationException: Control lost W/System.err: at com.h6ah4i.android.media.opensl.OpenSLMediaPlayer.parseResultAndThrowException(OpenSLMediaPlayer.java:1034) W/System.err: at com.h6ah4i.android.media.opensl.OpenSLMediaPlayer.parseResultAndThrowExceptForIOExceptions(OpenSLMediaPlayer.java:999) W/System.err: at com.h6ah4i.android.media.opensl.OpenSLMediaPlayer.access$100(OpenSLMediaPlayer.java:42) W/System.err: at com.h6ah4i.android.media.opensl.OpenSLMediaPlayer$Internal.parseResultAndThrowExceptForIOExceptions(OpenSLMediaPlayer.java:845) W/System.err: at com.h6ah4i.android.media.opensl.audiofx.OpenSLAudioEffect.parseResultAndThrowExceptForIOExceptions(OpenSLAudioEffect.java:43) W/System.err: at com.h6ah4i.android.media.opensl.audiofx.OpenSLHQEqualizer.usePreset(OpenSLHQEqualizer.java:314)

h6ah4i commented 8 years ago

Hi. I tried to reproduce the same exception, but I was not able to get it.

Here is a simplified version of your code and I put this method into GlobalAppController of the demo app and invoked it when I press a button.

    private void hqEqualizerIssueCheck() {
        IEqualizer equalizer = getHQEqualizer();

        int count = equalizer.getNumberOfPresets();

        for (short i = 0; i < count; i++) {
            // loops through presets
            try {
                String name = equalizer.getPresetName(i);
                short bandscount = equalizer.getNumberOfBands();

                equalizer.usePreset(i);

                for (short n = 0; n < bandscount; n++) {
                    // loops through preset bands
                    equalizer.getBandLevel(n);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Could you upload your project or full of the sample code which can reproduce the same issue?

roomtek commented 8 years ago

Ok. The full story is this. I created an array to hold the mediaplayer objects (ITMPlayer)

private ITMPlayer[] imediaplayer = new ITMPlayer[2];

int activemediaplayer = 0;

OpenSLMediaPlayerContext.Parameters params = new OpenSLMediaPlayerContext.Parameters();

        // https://github.com/h6ah4i/android-openslmediaplayer/wiki/OpenSL-prefixed-API-classes

        params.options = OpenSLMediaPlayerContext.OPTION_USE_PREAMP |
                OpenSLMediaPlayerContext.OPTION_USE_HQ_EQUALIZER |
                OpenSLMediaPlayerContext.OPTION_USE_BASSBOOST |
                OpenSLMediaPlayerContext.OPTION_USE_HQ_VISUALIZER |
                OpenSLMediaPlayerContext.OPTION_USE_ENVIRONMENAL_REVERB |
                OpenSLMediaPlayerContext.OPTION_USE_VIRTUALIZER;
        params.streamType = AudioManager.STREAM_MUSIC;
        params.shortFadeDuration = 25; // [milli seconds]
        params.longFadeDuration = 300; // [milli seconds]
        params.resamplerQuality = OpenSLMediaPlayerContext.RESAMPLER_QUALITY_HIGH;
        params.hqEqualizerImplType = OpenSLMediaPlayerContext.HQ_EAUALIZER_IMPL_BASIC_PEAKING_FILTER;

        if (factory == null)
            factory = new OpenSLMediaPlayerFactory(playbackService.getApplicationContext(), params);

imediaplayer[activemediaplayer] = new ITMPlayer(factory.createMediaPlayer(), activemediaplayer);

where ITMPlayer is:

public class ITMPlayer {
    private IBasicMediaPlayer mediaplayer;
    private int tag;
    private IEqualizer equalizer;

public ITMPlayer(IBasicMediaPlayer mediaPlayer, int tag) {
        this.mediaplayer = mediaPlayer;
        this.tag = tag; 
    }
}

The ITMPlayer has its own mediaplayer object, and equalizer object.

the usePreset works properly on the first mediaplayer object. When I setup the gap-less playback, and then try to access the equalizer object associated with the "idle" mediplayer, after it becomes active (playback has completed on the first media player) the error occurs.

idlemediaplayer = imediaplayer[1];
imediaplayer[0].setNextMediaPlayer(idlemediaplayer);

I access each equalizer object like this:

IEqualizer equalizer = imediaplayer[activemediaplayer].equalizer;
...
equalizer.usePreset(i)
h6ah4i commented 8 years ago

Thanks for your additional information.

The behavior is by design of this library. The OpenSLHQEqualizer class can be instantiated only one instance. Call createHqEqualizer() once and share the returned instance between two media players.

Here is an architecture diagram. The HQEqualizer unit is inserted right after the AudioMixer unit and that's why only one instance can be permitted.

image source: https://github.com/h6ah4i/android-openslmediaplayer/wiki/System-Architecture

roomtek commented 8 years ago

Brilliant!. Thanks for this information. I will start out to implement this change.

roomtek commented 8 years ago

Thanks. I am now able to get the equalizer presets on both players

device-2015-12-27-003257