Android Visualizer FFT / waveform affected by device volume? - android

I'm working on some music analysis using the Visualizer class on Android 2.3.1. I am finding that the FFT and waveform magnitudes are affected by the volume of the device. This means that if the user has the volume turned down I receive little or not FFT data.
I've tested this on a Motorola Xoom, Samsung Galaxy Tab and the emulator and it behaves this way.
I am using the code below:
mp = new MediaPlayer();
mp.setDataSource("/sdcard/sine1.wav");
mp.prepare();
mp.setLooping(true);
mp.start();
int audioSessionID = mp.getAudioSessionId();
v = new Visualizer(audioSessionID);
v.setEnabled(true);
Looking at the docs for the Visualizer class it seems that if we are passing in a valid audio session id then the visualizer should operate upon this audio session. It appears that the Visualizer is operating upon the output mix.
Has anyone else encountered this or found a way around it?
Thanks

I was also facing the same problem, but it is working when i am enabled the Eqaulizer and Visualizer for same seession id.I dont know the reason for it ,i checked it remove the equalizer from visualizer class in api demos it is working as you said.
Equalizer mEqualizer = new Equalizer(0, SessionId);
mEqualizer.setEnabled(true); // need to enable equalizer
Visualizer mVisualizer = new Visualizer(SessionId);

There are two options for the Visualizer scaling mode:
SCALING_MODE_AS_PLAYED and SCALING_MODE_NORMALIZED
If you want the Visualizer to be normalized, as in it's consistent no matter what the volume is, then use SCALING_MODE_NORMALIZED.
mVisualizer.scalingMode = Visualizer.SCALING_MODE_AS_PLAYED
Keep in mind though that this drastically changes the values being sent to the Visualizer, so other adjustments may be needed.

Related

Android Webrtc change stream to STREAM_MUSIC

I have created a WebRTC session from one device to another, the device should be able to control the volume for music stream, but WebRTC is originally designed to stream voice_call so is using the voice_call channel and using the call volume control is not good behavior for non-call app.
I tried to change STREAM_VOICE_CALL to STREAM_MUSIC in WebRTC source WebRtcAudioTrack to use the stream music volume but the only change was android is detecting it as music but volume change with call volume.
I found the solution to this. You have to change the opensls player for this to happen
change this from here
// corresponds to android.media.AudioManager.STREAM_VOICE_CALL.
SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
RETURN_ON_ERROR(
(*player_config)
->SetConfiguration(player_config, SL_ANDROID_KEY_STREAM_TYPE,
&stream_type, sizeof(SLint32)),
false);
to this
// corresponds to android.media.AudioManager.STREAM_MUSIC.
SLint32 stream_type = SL_ANDROID_STREAM_MEDIA;
RETURN_ON_ERROR(
(*player_config)
->SetConfiguration(player_config, SL_ANDROID_KEY_STREAM_TYPE,
&stream_type, sizeof(SLint32)),
false);
do this here too

Modifying in-call voice playback in Android custom ROM

I would like to modify Android OS (official image from AOSP) to add preprocessing to a normal phone call playback sound.
I've already achieved this filtering for app audio playback (by modifying HAL and audioflinger).
I'm OK with targeting only a specific device (Nexus 5X). Also, I only need to filter playback - I don't care about recording (uplink).
UPDATE #1:
To make it clear - I'm OK with modifying Qualcomm-specific drivers, or whatever part that it is that runs on Nexus 5X and can help me modify in-call playback.
UPDATE #2:
I'm attempting to create a Java layer app that routes the phone playback to the music stream in real time.
I've already succeeded in installing it as a system app, getting permissions for initializing AudioRecord with AudioSource.VOICE_DOWNLINK. However, the recording gives blank samples; it doesn't record the voice call.
This is the code inside my worker thread:
// Start recording
int recBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);
mRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_DOWNLINK, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, recBufferSize);
// Start playback
int playBufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
mTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, playBufferSize, AudioTrack.MODE_STREAM);
mRecord.startRecording();;
mTrack.play();
int bufSize = 1024;
short[] buffer = new short[bufSize];
int res;
while (!interrupted())
{
// Pull recording buffers and play back
res = mRecord.read(buffer, 0, bufSize, AudioRecord.READ_NON_BLOCKING);
mTrack.write(buffer, 0, res, AudioTrack.WRITE_BLOCKING);
}
// Stop recording
mRecord.stop();
mRecord.release();
mRecord = null;
// Stop playback
mTrack.stop();
mTrack.release();;
mTrack = null;
I'm running on a Nexus 5X, my own AOSP custom ROM, Android 7.1.1. I need to find the place which will allow call recording to work - probably somewhere in hardware/qcom/audio/hal in platform code.
Also I've been looking at the function voice_check_and_set_incall_rec_usecase at hardware/qcom/audio/hal/voice.c However, I wasn't able to make sense of it (how to make it work the way I want it to).
UPDATE #3:
I've opened a more-specific question about using AudioSource.VOICE_DOWNLINK, which might draw the right attention and will eventually help me solve this question's problem as well.
There are several possible issues that come to my mind. The blank buffer might indicate that you have the wrong source selected. Also since according to https://developer.android.com/reference/android/media/AudioRecord.html#AudioRecord(int,%20int,%20int,%20int,%20int) you might not always get an exception even if something's wrong with the configuration, you might want to confirm whether your object has been initialized properly. If all else fails, you could also do an
"mRecord.setPreferredDevice(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);"
to route the phone's built-in earpiece directly to the input of your recorder. Yeah, it's kinda dirty and hacky, but perhaps suits the purpose.
The other thing what was puzzling me that instead of using the builder class you've tried to configure the object directly via its constructor. Is there a specific reason why you don't want to use AudioRecord.Builder (there's even a nice example at https://developer.android.com/reference/android/media/AudioRecord.Builder.html ) instead?

Increase MediaPlayer volume beyond 100%

Below code is working but not increasing the media player volume higher than the default max volume.Please help
AudioManager am =
(AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(
AudioManager.STREAM_MUSIC,
am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
0);
The MediaPlayer class's setVolume() method only accepts scalars in the range [0.0, 1.0], but the classes deriving from AudioEffect can be used to amplify the MediaPlayer's audio session.
For example, LoudnessEnhancer amplifies samples by a gain specified in millibels (i.e. hundredths of decibels):
MediaPlayer player = new MediaPlayer();
player.setDataSource("https://www.example.org/song.mp3");
player.prepare();
// Increase amplitude by 20%.
double audioPct = 1.2;
int gainmB = (int) Math.round(Math.log10(audioPct) * 2000);
LoudnessEnhancer enhancer = new LoudnessEnhancer(player.getAudioSessionId());
enhancer.setTargetGain(gainmB);
It's unclear from the documentation, but it appeared to me that LoudnessEnhancer doesn't work properly with negative gains, so you may still need to use MediaPlayer's setVolume() method if you want to decrease the volume.
DynamicsProcessing provides multiple stages across multiple channels, including an input gain stage.
For increasing the volume of the device beyond the system volume u have to go in engineers mode.for that save below code.and paste it in number entering box In calling option it will directly redirect you to the engineers mode
*#*#3646633#*#*
By this you can access the system settings one thing make sure that don't use this without care it may affect your system performance.

How can I setRate for Android MediaPlayer?

How can I implement
setRate(float f)
for my Android MediaPlayer, and secondly is it posible?
I believe this is the function you are looking for.
This sets the sampling rate at which the audio data will be consumed and played back, not the original sampling rate of the content. Setting it to half the sample rate of the content will cause the playback to last twice as long, but will also result in a negative pitch shift. The valid sample rate range is from 1Hz to twice the value returned by getNativeOutputSampleRate(int).
If you want to play mp3 directly using AudioTrack, you can either have a look at this example or convert your mp3 file to wav format, which enables AudioTrack to use it without hassle. This is the tradeoff you should account for if you want to adjust the playback rate easily.
Android 6.0 adds PlaybackParams for MediaPlayer, so you can now do this:
String recordingPath = recordingDirectory + File.separator + "music.mp3";
MediaPlayer audioPlayer = MediaPlayer.create(getApplicationContext(), Uri.parse(recordingPath));
audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
PlaybackParams params = new PlaybackParams();
params.setSpeed(0.75f);
audioPlayer.setPlaybackParams(params);
audioPlayer.start();
I don't have an Android 6 device yet, but this works for me in the emulator.
Based on the Android developer documentation, you may have to use SoundPool instead.
Android Developer: Media SoundPool-setRate
public final void setRate (int streamID, float rate)
Change playback rate. The playback rate allows the application to vary
the playback rate (pitch) of the sound. A value of 1.0 means playback
at the original frequency. A value of 2.0 means playback twice as
fast, and a value of 0.5 means playback at half speed. If the stream
does not exist, it will have no effect.
Parameters
streamID: a streamID returned by the play() function
rate: playback rate (1.0 = normal playback, range 0.5 to 2.0)

How to shut off the sound MediaRecorder plays when the state changes

My Android application uses MediaRecorder on a SurfaceHolder to show a live preview of what the camera is capturing. Every time the user presses the REC button on the app, the app starts to record.
Every time the state of the MediaRecorder switches to/from 'start', Android automatically (?) fires off a beep. This beep sounds different from phone to phone, which makes me think that this beep is natively attached to the state change of MediaRecorder.
The beep is not played if the volume of the phone is set to silent.
I google it and did some research but I couldn't find a way to turn this beep off. Is it possible? If so, how?
The app was tested on: Nexus One 2.3.4, Desire HD 2.3.3
Ok the accepted answer did not work for me. On a Galaxy Nexus Running 4.2.1 (Jelly Bean) when recording via MediaRecorder I needed to use AudioManager.STREAM_RING because AudiManager.STREAM_SYSTEM did not work. It would always play a "chime" sound at beginning of each recording.
Here is my solution using "STREAM_RING" and others.
// disable sound when recording.
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_ALARM,true);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_DTMF,true);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_MUSIC,true);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_RING,true);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_SYSTEM,true);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_VOICE_CALL,true);
// re-enable sound after recording.
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_ALARM,false);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_DTMF,false);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_MUSIC,false);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_RING,false);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_SYSTEM,false);
((AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_VOICE_CALL,false);
Also as the documentation states be sure to re-enable audio in the onPause() method.
I hope this helps someone tearing their hair out over this problem. This disables all sound streams. You can go through and work out which ones you specifically need. I found that different versions of android use different streams for the chime when mediarecorder runs. ie, STREAM_RING works for android 4.2.1 but for ICS it doesn't work.
Edit: As my comment below mentions, I can't get the sound disabled for Android OS 2.3.3 on a Samsung Galaxy S1. Anyone have luck with this?
Darrenp's solution helps to tidy up code but in a recent update to my phone (galaxy nexus android 4.3) the volume / recording beep started up again! The solution by user1944526 definitely helps. In an effort to make it easier to understand...
Use something like ,
// class variables.
Integer oldStreamVolume;
AudioManager audioMgr;
enableSound() {
setMuteAll(false);
if (audioMgr != null && oldStreamVolume != null) {
audioMgr.setStreamVolume(AudioManager.STREAM_RING, oldStreamVolume, 0);
}
}
disableSound() {
audioMgr = (AudioManager)activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
oldStreamVolume = audioMgr.getStreamVolume(AudioManager.STREAM_RING);
audioMgr.setStreamVolume(AudioManager.STREAM_RING, 0, 0);
}
For completeness each of those functions you could also call either darrenp's solution in a function or include all of the above STREAM_ lines. but for me now, these combined are working. Hope this helps someone...
try
((AudioManager)context.getSystemService(Context.AUDIO_SERVICE)).setStreamMute(AudioManager.STREAM_SYSTEM,true);
That mute all sounds.
Following on from #wired00's answer, the code can be simplified as follows:
private void setMuteAll(boolean mute) {
AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int[] streams = new int[] { AudioManager.STREAM_ALARM,
AudioManager.STREAM_DTMF, AudioManager.STREAM_MUSIC,
AudioManager.STREAM_RING, AudioManager.STREAM_SYSTEM,
AudioManager.STREAM_VOICE_CALL };
for (int stream : streams)
manager.setStreamMute(stream, mute);
}
This works fine for now but if more streams are introduced in the future, this method may need updating. A more robust approach (though perhaps overkill) is to use reflection to get all the STREAM_* static fields:
List<Integer> streams = new ArrayList<Integer>();
Field[] fields = AudioManager.class.getFields();
for (Field field : fields) {
if (field.getName().startsWith("STREAM_")
&& Modifier.isStatic(field.getModifiers())
&& field.getType() == int.class) {
try {
Integer stream = (Integer) field.get(null);
streams.add(stream);
} catch (IllegalArgumentException e) {
// do nothing
} catch (IllegalAccessException e) {
// do nothing
}
}
}
Interestingly, there seem to be some streams that are not documented, namely STREAM_BLUETOOTH_SCO, STREAM_SYSTEM_ENFORCED and STREAM_TTS. I'm guessing/hoping there's no harm in muting these too!
I just had this problem on a Lenovo K900 running Android 4.2.1.
setStreamMute doesn't seem to do anything for me, but setStreamVolume works...
AudioManager audioMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int oldStreamVolume = audioMgr.getStreamVolume(AudioManager.STREAM_RING);
audioMgr.setStreamVolume(AudioManager.STREAM_RING, 0, 0);
... do recording ...
audioMgr.setStreamVolume(AudioManager.STREAM_RING, oldStreamVolume, 0);
Add this code before the start:
AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true);
audioManager.setStreamMute(AudioManager.STREAM_MUSIC,true);
And add this code after the stop:
AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false);
audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);
There are countries/firmwares that use STREAM_SYSTEM and others using STREAM_MUSIC. There are also countries where this is illegal but use a different channel.

Categories

Resources