I'm trying to get a sound (namely a small wav file representing the persons name - not auto generated) to play over a bluetooth headset while the phone is ringing. Essentially it would replace the default ring of the bluetooth device and replace it with the name of the caller!... well, anyway... it's not working.
I've been able to play the wav file directly on the headset within an activity, but when moved to the onReceive function of the broadcast receiver it fails to play the same sound over the headset while the cell phone is ringing...
I feel like I must be missing something. Is there something I can do to revise this code?
Thanks in advance
public void onReceive(Context context, Intent intent) {
mContext = context;
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))
{
System.out.println("Its Ringing");
AudioManager am = (AudioManager) mContext.getSystemService(mContext.AUDIO_SERVICE);
am.setBluetoothScoOn(true);
am.startBluetoothSco();
am.setMode(AudioManager.MODE_NORMAL);
try{
AssetFileDescriptor afd = mContext.getAssets().openFd("my.wav");
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
player.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
player.setOnPreparedListener(new OnPreparedListener(){
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
player.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
player.prepareAsync();
}catch(IOException ioe){
System.err.println(ioe.getLocalizedMessage());
}}}
You should be preparing/setting up your media player before you receive the phone call because this can take some time. Also, remove am.setMode(AudioManager.MODE_NORMAL);, you could replace it with am.setMode(AudioManager.STREAM_VOICE_CALL); but it is probably not necessary because you should already be in that mode if your BT device is paired/setup.
Related
I'm building an Android app that unmute phone when an Incoming call came in phone.
I use BroadcastReceiver to receive incoming call events. I switch phone from mute mode to Ring Mode when BroadcastReceiver receive incoming call events.
And expect Phone will vibrate and Play ringtone.
But Phone only vibrate, can't play ringtone though phone ring set to max sound.
I found many apps on play store those can unmute before call and play ringtone and vibrate both. Example: One App Link
My code Below:
public void onReceive(Context context, Intent intent) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
if (intent.getAction()!=null && intent.getAction().equals("android.intent.action.PHONE_STATE")){
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
audioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume/2, AudioManager.FLAG_PLAY_SOUND);
}
}
}
I'm working on something very similar. You actually have to play a ringtone after overriding the audio settings. But you only need to do this on Android 6.0+ Get an instance of the ringtone and play it when phone state is ringing else just stop it.
public void onReceive(Context context, Intent intent) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
Ringtone r = RingtoneManager.getRingtone(context, uri);
if (intent.getAction()!=null && intent.getAction().equals("android.intent.action.PHONE_STATE")){
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
audioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume/2, AudioManager.FLAG_PLAY_SOUND);
r.play();
}else {
r.stop();
}
}
}
Problems you'll run into with this implementation. You will get multiple ringtones playing because the onReceive method is called many times during Phone State changes. The provides a different context each time onReceive is called and creates a different instance of Ringtone each time. I launched a background service to fix this issue so I could hold a single reference to a context and thus a single reference to Ringtone.
Some devices may not have volume control and may operate at a fixed volume, and may not enable muting or changing the volume of audio streams.
isVolumeFixed()
This method will return true on such devices.
I am brand new (47 minutes) into Android development and have a problem that I have is likely to be a simple one.
Anyway, here it is.
I would like to use a web service which, given a url, spits back an Mp3 (browser instantly starts downloading it).
MediaPlayer player = new MediaPlayer();
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 20, 0);
String url = "http://www.gimme-an-mp3.com/xyz";
try {
player.setDataSource(url);
} catch (IOException e) {
e.printStackTrace();
}
player.prepareAsync();
player.start();
For some reason, the media player does not play my Mp3 file. Why? Do I have to first download it and then pass it to the media player?
you have to call player.start() only after player has been prepared.
before that, the player is still preparing.
player.prepareAsync();
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
more details can be found here http://developer.android.com/reference/android/media/MediaPlayer.html
and here Android: correct usage of PrepareAsync() in media player activity
I am trying to stream voice/audio (two way) between two Android devices Tablet and Mobile (over java sockets).
The Tablet can play received audio(voice) clearly, but the Mobile plays received audio as noise.
Then i set this audio mode in the code on tablet:
audioManager.setMode(AudioManager.MODE_IN_CALL);
This now results in Mobile receiving clear voice.
But the tablet goes silent, it does not play the received audio (or rather its not audible).
I am not sure what combination (if any) of AudioManager mode i should use here?
It's possible to handle the sound you want to play as Alarm.
Create a new class named AlarmController and try this code.
This worked for me on Android 4.4.2 (Huawei ascend P7) with each system volume (Media, Ringtone, Alarm) set to 0.
Context context;
MediaPlayer mp;
AudioManager mAudioManager;
int userVolume;
public AlarmController(Context c) { // constructor for my alarm controller class
this.context = c;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
//remeber what the user's volume was set to before we change it.
userVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
mp = new MediaPlayer();
}
public void playSound(String soundURI){
Uri alarmSound = null;
Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
try{
alarmSound = Uri.parse(soundURI);
}catch(Exception e){
alarmSound = ringtoneUri;
}
finally{
if(alarmSound == null){
alarmSound = ringtoneUri;
}
}
try {
if(!mp.isPlaying()){
mp.setDataSource(context, alarmSound);
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
mp.setLooping(true);
mp.prepare();
mp.start();
}
} catch (IOException e) {
Toast.makeText(context, "Your alarm sound was unavailable.", Toast.LENGTH_LONG).show();
}
// set the volume to what we want it to be. In this case it's max volume for the alarm stream.
mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_PLAY_SOUND);
}
public void stopSound(){
// reset the volume to what it was before we changed it.
mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, userVolume, AudioManager.FLAG_PLAY_SOUND);
mp.stop();
mp.reset();
}
public void releasePlayer(){
mp.release();
}
I hope this works for you. :)
In my app, I use the following code to play a short notification sound using MediaPlayer with STREAM_NOTIFICATION. The issue is that, when the app plays the notification sound and at the same time music is played at background by music player app, the notification sound will interrupt (pause) the music playing. How can I make my app's notification sound to be played simultaneously with the background music playback? Thanks.
AssetFileDescriptor afd =
mResources.openRawResourceFd(resId);
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
}
});
mediaPlayer.prepare();
mediaPlayer.start();
The behaviour described in the question seems to be specific for Android 5.x and below. For Android 6.x and above AudioManager behavior has changed and AudioSystem.STREAM_NOTIFICATION flag doesn't interrupt music playback anymore.
As workaround I would recommend to replace
mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
by
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
P.S. Not sure what exactly changed in Android platform but according to
https://android.googlesource.com/platform/frameworks/base/+/android-5.1.1_r37/media/java/android/media/AudioAttributes.java and https://android.googlesource.com/platform/frameworks/base/+/android-6.0.0_r26/media/java/android/media/AudioAttributes.java they treat AudioSystem.STREAM_NOTIFICATION as AudioSystem.STREAM_SYSTEM for both Android 5.x & 6.x:
public Builder setInternalLegacyStreamType(int streamType) {
switch(streamType) {
/*...*/
case AudioSystem.STREAM_SYSTEM:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
/*...*/
case AudioSystem.STREAM_NOTIFICATION:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
/*...*/
default:
Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
}
mUsage = usageForLegacyStreamType(streamType);
return this;
}
I have a working alarm app, but wanted to add a feature where the user gets the choice between "Play alarm continuously till acknowledged" and "play alarm sound once".
I then looked at my alrm ringing code expecting to see some kind of "repeat" flag which I could optionally remove - but there was none. So how do I play the alarm sound just once?
My existing code looks like this:
private void playSound(Context context, Uri alert)
{
mMediaPlayer = new MediaPlayer();
try
{
mMediaPlayer.setDataSource(context, alert);
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0)
{
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
}
catch (IOException e)
{
// oops!
}
}
Actually in each alarm sound there is a FLAG named ANDROID_LOOP which force your sound to loop. Unfortunatly you can't change that flag even using MediaPlayer.setLooping(false).
But you still can manually stop your player after a certain time. For example getDuration will give you the length of your sound.
int duration = mMediaPlayer.getDuration();
Runnable stopSoundRunnable = new Runnable() {
#Override
public void run() {
mMediaPlayer.stop();
}
};
mSoundHanlder.postDelayed(stopSoundRunnable, duration);