RuntimePermission problem in latest tip?

I have recompiled both IntroJucer and an android app (which works fine on other platforms) and I get a JUCE Assertion failure in juce_android_OpenSL.cpp (153). Is it me or have you done something in that field over the past few weeks ?

I obviously DID check the "Specify Audio Permission  in the manifest" box in IntroJucer project...

<EDIT> I also have checked the manifest file and DO have the


<uses-permission android:name="android.permission.RECORD_AUDIO"/>
 

line in it...

Note that if I declare 0 audio inputs (

        audioDeviceManager->initialise (0, 2, 0, true, String(), 0);

)

the problem disappears (which is normal considering that it occurs due to a non-recognition of audio record permission) and the app runs fine. Also, I don't have the problem on MacOS nor iOS (didn't test it on Win nor Linux).

And the problem did not occur until I downlodaded latest JUCE tip (I previously had

        audioDeviceManager->initialise (2, 2, 0, true, String(), 0);

)

I am using latest version of Android tools (as of March 5, 2016),  and MacOS 10.11.3

Hi,

Yes, this is a restriction added in Android API Level 23 which we now added support for.

Let me explain. In the world of Android M, it's not enough anymore to specify the permission in the manifest. If you compile your app for API Level 23 or higher, you now additinally have to explicitly request that permission at runtime, otherwise Android won't let you use audio inputs. That assert you hit—I just added it to make sure that everyone notices the new way of doing things, instead of wondering why their app's audio input doesn't work on Android M.

Here's how it works:

Instead of 

audioDeviceManager->initialise (2, 2, 0, true, String(), 0);

you now have to write this:

RuntimePermissions::request (
    RuntimePermissions::recordAudio,
    /* >> callback to be called when Android decides to grant you the permissions << */
);

The callback will be called asynchronously. Sorry, that's an Android restriction, because what happens between the request and the callback is that Android will present this dialogue to the user:

The callback is a function with this signature: void callback (bool permissionWasGranted) { ... }  When called, the argument tells you what the user chose, and then you have to react to that, such as actually initialising your audio device manager. The easiest way to achieve this in code is with a lambda, for example like this:

RuntimePermissions::request (
    RuntimePermissions::recordAudio,
    [] (bool wasGranted) {
        int numInputChannels = wasGranted ? 2 : 0;
        sharedAudioDeviceManager->initialise (numInputChannels, 2, 0, true, String(), 0);
    }
);

Read the documentation of RuntimePermissions for more info. If it's still unclear, please post...

Totally clear. Thanx for taking the time to explain.

This seems to work for API Level 23 (Android 6) but failed for Android 21 (5.1).

I had to comment out the

androidRunTimePermissionsCallback (true, ptrToCallback);

line to get it to compile and run. I also had to specify 0 audio input in the audioDeviceManager initialise call.

This is ok for me because in this exampleI don't use audio inputs.

But I suppose this is an abnormal behavior ?

That is odd, if you compile for Android 21 it should just work. There, the whole runtime permissions stuff should compile and then just not do anything.

Maybe you forgot to specify the permission in the app manifest?

Well it is odd but if I only replace 21 with 23 in the IntroJucer project it compiles and runs with no problem.

In both cases I checked the "Specify audio record permission in the manifest" box and the manifest file does contain the uses_permission line. To be honnest, I don't understand why I need that since I am not using audio inputs anyway... But I did it just in case...

I even used the magic "Invalidate caches / Restart" command from the File menu. No more success...

The error I get in the API level 21 case is:

"error: cannot find symbol method androidRuntimePermissionsCallback(boolean,long)"

for the .java file. Which is why it works when I comment out the call as said before.

Could it be a library problem ? I am compiling on Mac0S 10.11.3 with latest updates from Android Studio. Any hint ?

Could you please post the exact code that you use in your app to request the permissions and initialise audio outputs?

Also, do you get the same error if you try to compile the Juce Demo? It uses audio inputs and outputs on Android and compiled just fine for API level 21 last time I checked.

I just tried the Juce Demo and I got the same problem. Works for API level 23, not 21.

I'm going to re-install all API 21 libraries and see what happens. If it works on your side that's the only thing I can think of...

OK let me try this again. I'll post here shortly.

Yes, I can reproduce the problem now with the Juce Demo. I'll fix this as soon as possible!

OK, that was a bug in our Java code. Should be fixed now. Please update to the newest tip, re-Introjuce your app and try again!

Ah !  This was driving me nuts !!! Glad you found the bug (and the fix...) Now of course when I downloaded the tip I bumped against the empty() syndrom... which you fixed in the meantime. So everything's back on tracks now (as far as I can tell...).

Thanks

I think I’m seeing this (or similar) at the moment (Latest Tip, building for Nexus 5/Android 6.0.1) - Strange thing is, the DemoRunner works fine (all the demos I tried, at least, including the FFT/Sonogram) - If I build the PIP for SimpleFFTDemo in seclusion {AND REMEMBERING TO tick the AudioRecording Permission}, the demo stops on a line saying I probably haven’t requested the AudioRecording permission :frowning: . Am I missing something? Seems very reproducible here (Latest Android Studio WIn10 x64)

Just to confirm, you’ve set the Audio Input Required setting in the Projucer’s Android exporter to Enabled and re-saved the project? Can you put a breakpoint at line 264 of AudioRecordingDemo.h on this line:

int numInputChannels = granted ? 2 : 0;

and check what the value of granted is?

Hi, Ed,
Thanks.
{I forgot to say the develop branch?}
I can confirm some of that (I’m on a different machine at the mo). Yes I changed the Audio input Required flag, i think I saved and reloaded the project (one of the things I tested), not sure about that line (from memory, there was something after the test … but perhaps you’re version is right… I didn’t inspect the granted flag… but I also didn’t check the 2 inputs were requested - assuming PIP would do that.) - As I said, I know the DemoRunner version works, just a PIP issue. May get a chance to check later or Friday PM.

Looks like in chans is 1 and I can confirm the flag is set on Projucer

… and the manifest


Hope this helps

It looks like the SimpleFFTDemo.h is just missing a call to RuntimePermissions::request(), like so:

RuntimePermissions::request (RuntimePermissions::recordAudio,
                            [this] (bool granted)
                            {
                                 int numInputChannels = granted ? 2 : 0;
                                 setAudioChannels (numInputChannels, 2);
                             });

This is only really needed on Android, and since the FFT demo doesn’t have an Android exporter by default it was never added. I’ll add it now, but you just need to add the above lines to the SimpleFFTDemo constructor, replacing the setAudioChannels() line.

2 Likes

Thanks, ed
Leads me to think I may have spotted something else, though