Android - Getting audio to play through earpiece

I currently have code that reads a recording in from the devices mic using the AudioRecord class and then playing it back out using the AudioTrack class.

My problem is that when I play it out it plays via the speaker phone.

I want it to play out via the ear piece on the device.

Here is my code:

public class LoopProg extends Activity {

 boolean isRecording; //currently not used
 AudioManager am;
 int count = 0;

 /** Called when the activity is first created. */
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        am.setMicrophoneMute(true);
        while(count <= 1000000){
        Record record = new Record();  
        record.run();
        count ++;
        Log.d("COUNT", "Count is : " + count);
        }
    } 

   public class Record extends Thread{
      static final int bufferSize = 200000;
      final short[] buffer = new short[bufferSize];
      short[] readBuffer = new short[bufferSize];

      public void run() {  
      isRecording = true;
      android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

      int buffersize = AudioRecord.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
      AudioRecord arec = new AudioRecord(MediaRecorder.AudioSource.MIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize);
      AudioTrack atrack = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize, AudioTrack.MODE_STREAM);
      am.setRouting(AudioManager.MODE_NORMAL,1, AudioManager.STREAM_MUSIC);
      int ok = am.getRouting(AudioManager.ROUTE_EARPIECE);
      Log.d("ROUTING", "getRouting = " + ok);
      setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
      //am.setSpeakerphoneOn(true);
      Log.d("SPEAKERPHONE", "Is speakerphone on? : " + am.isSpeakerphoneOn());
      am.setSpeakerphoneOn(false);
      Log.d("SPEAKERPHONE", "Is speakerphone on? : " + am.isSpeakerphoneOn());
      atrack.setPlaybackRate(11025);

      byte[] buffer = new byte[buffersize];
      arec.startRecording();
      atrack.play();

      while(isRecording) {
                         arec.read(buffer, 0, buffersize);
                         atrack.write(buffer, 0, buffer.length);
                         }
      arec.stop();
      atrack.stop();
      isRecording = false;
      }
   } 
}

As you can see if the code I have tried using the AudioManager class and its methods including the deprecated setRouting method and nothing works, the setSpeakerphoneOn method seems to have no effect at all, neither does the routing method.

Has anyone got any ideas on how to get it to play via the earpiece instead of the spaker phone?


Solution 1:

Just got it to work on 2.2. I still needed the In_Call setup which I don't really like but I'll deal with it for now. I was able to ditch the call routing stuff which is deprecated now. I found you definitely need the Modify_Audio_Settings permission, no error without it but it the setSpeakerPhone method just does nothing. Here is the mock up of the code I used.

private AudioManager m_amAudioManager;  
m_amAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);  
m_amAudioManager.setMode(AudioManager.MODE_IN_CALL); 
m_amAudioManager.setSpeakerphoneOn(false); 

Solution 2:

Please use this code, works well:

    //PLAY ON EARPIECE
    mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
    audioManager.setMode(AudioManager.MODE_IN_CALL);
    audioManager.setSpeakerphoneOn(false);

    //PLAY ON SPEAKER
    mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    audioManager.setMode(AudioManager.MODE_IN_CALL);
    audioManager.setSpeakerphoneOn(true);

Solution 3:

There was some related discussion in this recent question:
Android - can I mute currently playing audio applications?

Based on the AudioManager source code, it seems that you must be in "call mode" before the setSpeakerphoneOn method has any effect.

However, I recently saw an application that could seamlessly switch between earpiece and speakerphone while still showing the current stream as the "media" stream, so I would be interested in any further answers.

Solution 4:

Misleaded by some answers here for quite a lot of time. I'm using Android 2.2. "audioManager.setSpeakerphoneOn(false);" is working.

audioManager.setSpeakerphoneOn(false);
...
mediaPlayer.setDataSource(..);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
mediaPlayer.prepare();

Solution 5:

public MediaPlayer m_mpSpeakerPlayer;

private AudioManager m_amAudioManager;

m_amAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

// 從Receiver Earpiece發音

m_amAudioManager.setSpeakerphoneOn(false);

m_amAudioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL); 

Log.i(TAG, String.valueOf(m_amAudioManager.getRouting(AudioManager.ROUTE_EARPIECE))); 

setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);

// 把聲音設定成從Earpiece出來
// 重點在這行,要把它設定為正在通話中
m_amAudioManager.setMode(AudioManager.MODE_IN_CALL);

// 開始放音樂
m_mpSpeakerPlayer.reset();

m_mpSpeakerPlayer.setDataSource("sdcard/receiver.mp3");

m_mpSpeakerPlayer.prepare();

m_mpSpeakerPlayer.start();

//最後再把它設定從Speaker放音,達成!

m_amAudioManager.setMode(AudioManager.MODE_NORMAL);