MediaControllerCompat - java.lang.IllegalArgumentException: Bad direction 3 - android

I'm issuing a simple command to my mediaControllerCompat:
controller.adjustVolume(-1, 0);
Yet my app FCs with...
java.lang.IllegalArgumentException: Bad direction 3
at android.os.Parcel.readException(Parcel.java:1469)
at android.os.Parcel.readException(Parcel.java:1419)
at android.media.IAudioService$Stub$Proxy.adjustStreamVolume(IAudioService.java:1097)
at android.media.AudioManager.adjustStreamVolume(AudioManager.java:952)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase.adjustVolume(MediaSessionCompat.java:1376)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase.access$1700(MediaSessionCompat.java:963)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase$MediaSessionStub.adjustVolume(MediaSessionCompat.java:1602)
at android.support.v4.media.session.MediaControllerCompat$MediaControllerImplBase.adjustVolume(MediaControllerCompat.java:969)
at android.support.v4.media.session.MediaControllerCompat.adjustVolume(MediaControllerCompat.java:252)
at pl.qus.xenoamp.NewMainActivity.onKeyDown(NewMainActivity.java:1149)
MainActivity being the caller of mentioned line... What is WRONG?!

This was an internal bug in the Android Support Library has been fixed as of version 23.1.0.
Previous Answer
This is a bug in the support library that affects pre-API 21 devices that use local playback (i.e., have not called setPlaybackToRemote()) - the order of parameters sent to AudioManager.adjustStreamVolume() as per the source code is incorrect - hence why the direction appearing as 3 - the value for STREAM_MUSIC.
You may be able to temporarily work around it by always calling setPlaybackToRemote() on pre-API 21 devices, passing in a VolumeProviderCompat that does correctly call AudioManager.adjustStreamVolume(), but you must also handle the other methods of VolumeProviderCompat such as retrieving the max volume (via getStreamMaxVolume()) and current volume (via getStreamVolume()) as well as setting the volume (via setStreamVolume()).

I came across the same error using API 23 (not the Support Library) and running on an M device. I solved it by listening for the error and calling an API 1 method in its place, when necessary.
try {
...
} catch (IllegalArgumentException e) {
audioManager.setStreamVolume(STREAM, VOLUME, FLAGS);
}
Since the Compat interface calls the internal methods for system volume control, you could also instantiate an instance AudioManager if you are not directly declaring one already.

Related

Making hands-free calls

In my application, I need to make a call to a number, but the call must be made hands-free. I tried many available methods, min the method from this link.
The application logs showed the action of switching to hands-free, but physically it had no effect.
I also tried to do it with the help of such code:
private void enableHandsFree() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException {
Class audioSystemClass = Class.forName("android.media.AudioSystem");
Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
// First 1 == FOR_MEDIA, second 1 == FORCE_SPEAKER. To go back to the default
// behavior, use FORCE_NONE (0).
setForceUse.invoke(null, 1, 1);
}
Unfortunately also without success. Is there any way to handle such a problem?
Tested on Android 10
Undocumented API calls have been progressively disallowed in the last few android versions. The code you posted may work on on older APIs (my guess would be <= 26), but it'll have no effect in the newer versions.
For security reasons, no app is allowed to control audio output used by other apps. The only app that can do that is the one that as audio focus. And you're specifically trying to control audio output of the Phone app

Android: Possible maximum number of audiosessions or effect engines for audio? (EQ, REV...)

for awhile now, I am working on a media playing app. In this app, I also programmed a little 5 Band EQ using mainly this code:
try
{
AppPreferencesClass ap = new AppPreferencesClass(ctx);
if (Activity_Player.eq != null)
{
Activity_Player.eq.Dispose();
}
Activity_Player.eq = new Android.Media.Audiofx.Equalizer(0, Activity_Player.mediaPlayerSessionId);
Activity_Player.eq.SetEnabled(true);
await Task.Run(() =>
{
if (Activity_Player.EqActive)
{
if (ap.getAwesomeSound())
{
Activity_Player.eq.SetBandLevel(0, Convert.ToInt16(Activity_Equalizer.awesomesound0));
Activity_Player.eq.SetBandLevel(1, Convert.ToInt16(Activity_Equalizer.awesomesound1));
Activity_Player.eq.SetBandLevel(2, Convert.ToInt16(Activity_Equalizer.awesomesound2));
Activity_Player.eq.SetBandLevel(3, Convert.ToInt16(Activity_Equalizer.awesomesound3));
Activity_Player.eq.SetBandLevel(4, Convert.ToInt16(Activity_Equalizer.awesomesound4));
}
else
{
Activity_Player.eq.SetBandLevel(0, Convert.ToInt16(ap.getEQ0()));
Activity_Player.eq.SetBandLevel(1, Convert.ToInt16(ap.getEQ1()));
Activity_Player.eq.SetBandLevel(2, Convert.ToInt16(ap.getEQ2()));
Activity_Player.eq.SetBandLevel(3, Convert.ToInt16(ap.getEQ3()));
Activity_Player.eq.SetBandLevel(4, Convert.ToInt16(ap.getEQ4()));
}
}
});
}
catch
{
}
For many days, this worked just fine but out of NO WHERE, the catch block sometimes gets activated. But only occasionally.On other times, try works fine but there are just no more changes to the audio being played. This is odd enough, since I never changed anything on this code after it starting working.
I then tried another phone (Samsung S4) on my code and the eq worked just perfectly.
So this got me googleing and I think I might have heard that there can only be as many audiosession IDs after you just would run out. I tested and the audio session ID used here is somewhere at 74,000.
So this could be an issue I thought but this would easialy be tested because I already had this very app running in the google play store just an older version of it. I am 100 percent positive, that in this version the EQ worked on my phone. Otherwise I would have not uploaded that version.
Anyway, I downloaded my old app from the play store and here we go:
It doesnt work anymore. The EQ in the old version also has simply NO effect on the audio. While ofcourse on my other phones this old version works perfectly.
Before I am going to reset my own personal phone I wanted to ask you guys if this could be infact the case.
Another thing is, that I am using many static variables in order to get the EQ to work right. Actually, the variable EQ itself is static. Do maybe static variables sort of leave a "trace" behind and maybe I have set the eq up just "too" many times? Although I am disposing of the object before intialising it again (see in my code).
Summing up:
1.) Can there maybe be a maxmium number of EQ or AudioSessionIDs and I have passed those?
2.) Can creating static variables over and over again in my code cause a memory leak so big, even deinstalling the app doesnt do anything?
Thank you!
This is the error log:
11-20 12:16:43.736 E/AudioEffect(16990): set(): AudioFlinger could not create effect, status: -38
11-20 12:16:43.736 E/AudioEffects-JNI(16990): Error setting AudioEffect
11-20 12:16:43.737 E/AudioEffect-JAVA(16990): Error code -19 when initializing AudioEffect.
Thread started: #311-20 12:16:43.745 V/MediaPlayerNative(16990): unrecognized message: (6, 0, 0)
After 2 days of googeling and trying evetything out, here is the issue:
NOT CALLING RELEASE() will have you eventually have to REBOOT your phone. It wont allow too many instances of an EQ to be set.
Solution:
if (eq != null)
{
eq.Release();
}

Sound metering react-native

Im building a react-native application.
Im trying to meter the current sound level (in decibel).
Libraries in use: react-native-audio and react-native-sound.
There is anybody familiar with this feature?
Thank you.
With the react-native-audio library, you can get the count for the only iOS.
For the currentMetering in Android, you need to customize in a native module. I have updated it add the following things in your package.json file instead of your code. You will get the currentMetering count for the Android as well as iOS.
"react-native-audio": "git+https://github.com/Harsh2402/react-native-audio.git",
You can use react-native-audio currentMetering value - in order to get the sound level in real-time.
First, you will have to initialise your recorder (which i will assume youve done). I use prepareRecordingAtPath in a similar way to below
AudioRecorder.prepareRecordingAtPath(audioPath, {
SampleRate: 22050,
Channels: 1,
AudioQuality: "Low",
AudioEncoding: "aac",
MeteringEnabled: true
});
then once you've called AudioRecorder.startRecording(); (Note you have access to .pause() and .stop() methods also
Now for handling the audio level, you are going to have to retrieve the data that is returned by the onProgress method. From what i remember, there should be some currentMetering value that you can access. Note that defining this behaviour will trigger the action every time a different decibel reading is retrieved. Like so
AudioRecorder.onProgress = data => {
let decibels = Math.floor(data.currentMetering);
//DO STUFF
};
Hope this helps,

Log.isLoggable problems with android 6.0 (Marshmallow / api 23 )

I'm using android Log.isLoggable api in order to determine whether my custom log tag is on and should I log. (I'm setting property using setprop log.tag. on the device).
As far as Docs says, and as I'm familiar with older version, it should return true if the log level in the property is equal or high than the one I'm checking in my code.
This works fine for Lollipop and below (api 22) it's seems that something was changed in Marshmallow, as I encounter inconsistency and buggy behavior, playing with the values of the tag will result sometimes with the wrong value returned from isLogabble(), for instance a concrete scenario I did a check in code :
boolean shouldLog = Log.isLoggable("mytag", Log.DEBUG);
Log.d("debug", "shouldLog = " + shouldLog);
I set log.tag.mytag value to some arbitrary string
launch my app, and see the isLoggable = false, that's OK
then I change log.tag.mytag to VERBOSE
launch my app, isLoggable still false , that's not OK! should be true now
same scenario is not reproducible at Lollipop and didn't encounter any other misbehaviors.
Any suggestions, do I miss something here?

PhoneStateListener - what can I expect from onCellInfoChanged?

I posted this on Android dev group. I'm hoping I can get some feedback here.
The PhoneStateListener's callbacks onCellLocationChanged and onSignalStrengthsChanged were the goto methods for when I wanted to handle cell and signal data changes in GSM and CDMA. With API 17+, I can see that there's a new callback (onCellInfoChanged) for handling both cell and signal changes.
Looking at the documentation, it's not clear what I can expect from the introduction of this new callback.
Will LTE changes always and only trigger onCellInfoChanged?
Will GSM/CDMA changed remain on the older callbacks?
Does one overlap with the other? (i.e. Both old and new get triggered for LTE or GSM/CDMA.)
It may very well be that different OEMs will have different implementations (sigh!), but I'm hoping there are guidelines that everyone's supposed to follow.
Can anyone shed some light on this?
Thanks,
Sebouh
I didn't test if but it looks from the code that both will be called.
I downloaded code source of Android 4.3(API 18) using the SDK Manager.
The following observations made me think that both would be called.
The class that triggers these events is: com.android.server.TelephonyRegistry
It notifies the listener though:
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow)
This same function calls for both type of notifications(Location and CellInfo) in a non exclusive way.
On line 256:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
r.callback.onCellLocationChanged(new Bundle(mCellLocation));
} catch (RemoteException ex) {
remove(r.binder);
}
}
This one will call onCellLocationChanged even on new LTE phone since there is nothing from the above code that would prevent this. This needs double checking that there is no upper layer that filters the events themselves
On line 300 in the same code:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
r.callback.onCellInfoChanged(mCellInfo);
} catch (RemoteException ex) {
remove(r.binder);
}
}
There are other things from the code that look like CDMA will be calling the newer API. For example com.android.internal.telephony.cdma.CdmaLteServiceStateTracker seems to be dealing with CDMA and LTE. Again it would require a more careful look but that should give you a good place to start.
You can also try to simulate that with the emulator.

Categories

Resources