So, I'm trying to record a wave file from and Bluetooth Headset.
This is what I use to record
recorder = AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
BUFFER_SIZE)
And before starting recording I'm beginning and audio communication with my headset using
var am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
am!!.mode = 0
am!!.isBluetoothScoOn = true
am!!.startBluetoothSco()
am!!.mode = AudioManager.MODE_IN_COMMUNICATION
Well, it works wonders when recording in Android 6 (marshmallow), but when recording in Android 7 (nougat), it keeps recording from my phone's microphone and not the Bluetooth headset. Looking in the documentation, I didn't find anything regarding changes in Bluetooth SCO between versions. So.... what am I missing?
We had a similar problem when we tried to record a Bluetooth voice call. The problem was that the application started recording as soon as it received the telephony broadcast of the outgoing call, but the Bluetooth interface only connected a couple of milliseconds after the call has started.
We eventually solved this problem by applying a simple sleep before starting to record, and this fixed the problem.
Related
I'm looking to pair A2DP stereo sound with the interrupt functionality of AudioManager's MODE_IN_COMMUNICATION. The purpose of this pairing is to insert snippets of custom music into AM/FM broadcasts by using the music as something that "dials" the Android device and stops the AM/FM broadcast.
I have this working decently with SCO using the following code to start the "phone call".
Here is the AudioManager code:
AudioManager localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setMode(0);
localAudioManager.setBluetoothScoOn(true);
localAudioManager.startBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
Here is the MediaPlayer I'm trying to play:
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
mediaPlayer.setDataSource("https://wmbr.org/WMBR_Archive_128.m3u");
mediaPlayer.prepare();
mediaPlayer.start();
The audio produced by this code is low-quality and mono as opposed to stereo. I would like to change that.
The issue is that the Android Dev site for startBluetoothSco says:
Even if a SCO connection is established, the following restrictions apply on audio output streams so that they can be routed to SCO headset: - the stream type must be STREAM_VOICE_CALL - the format must be mono - the sampling must be 16kHz or 8kHz
Is there any existing way to combine stereo sound and the interrupt functionality?
Additional context: in this answer it seems that MODE_IN_COMMUNICATION and MODE_IN_CALL use the PHONE routing strategy. He also says
If your BT accessory supports the Hands-free profile it will use a SCO link for the voice audio, and the ACL channel used for A2DP should be closed to avoid interference between the two.
I'm assuming this means my only option is a custom routing strategy, and I'm not sure what that entails.
As we know,we could record voice via Bluetooth headset,we should use SCO link, but when a call coming, the system will lost sco link,so that, I can't get PCM data from SCO link. how to resolve it.
I'd try to this code,but it doesn't work.
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
am.startBluetoothSco();
am.setBluetoothScoOn(true);
when phone is ringing, can i record from SCO?
Android changes audio routing depending on its needs, and when the phone is ringing (and/or when the call is answered) the audio is re-routed to target device (earpiece, headphones, BT, etc..). It's impossible to start a single recording Object and get all the data (the data before, current and future voice during communication), but you have to monitoring the voicecall status (or the current Audio Routing state) and close the previous recording object and then create a new one using different settings.
If you are interested ONLY in your voice while your phone is ringing, you could do it by recording that data using UPLINK as the AudioSource of Recording object.
I am trying to record both Uplink and Downlink voice using Android. Regardless the law and everything, i am already aware, so please do not put comments related to the law.
The code below works fine, except when i mute the microphone, it wont record the downlink voice.
I am using Android 8.1. I've tried using a third party app called ACR on the same device, and it works fine, while i am muted, it still records the downlink voice.
val audioManager = applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val maximumVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, maximumVolume, 0)
val audioSource = MediaRecorder.AudioSource.MIC
val mediaRecorder = MediaRecorder()
mediaRecorder.apply {
setAudioSource(audioSource)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setAudioChannels(audioChannels)
setAudioSamplingRate(audioSamplingRate)
setAudioEncodingBitRate(audioEncodingBitRate)
setOutputFile(path)
prepare()
start()
This is not an issue. You set the MediaRecorder to use MIC as input, so if you MUTE the microphone it's obliviously that the input signat is lost/muted. When you use "downlink" word I expected to see a different input source as VOICECALL or DOWNLINK instead of MIC. Trying to record a voicecall using the MIC it's wrong in my opinion because: (1) you have to set max volume to speaker and redirect the voicecall through it (2) while recording a voicecall from the MIC the caller hears ALL what it happens around your device and all what you're saying to other people (3) this method records much noise and echoes. The right way is to record from VOICECALL but most of new devices (using newer Android version) prevents to record from this source and allows it only at System Apps. ACR uses a workaround by calling hidden API methods, but this method could stop stop work at any time due to Android updates.
I am connecting a mobile device with Android OS 4.1 to a Bluetooth device (device class = 1792), using BluetoothSco to route audio (voice). I've setup a BluetoothSocket using createRfcommSocketToServiceRecord successfully.
My settings:
Using AudioRecord and AudioTrack with frequency = 8000, MediaRecorder.AudioSource.MIC as the source for AudioRecord , AudioManager.STREAM_VOICE_CALL for the AudioTrack, and trying both MODE_IN_COMMUNICATION and MODE_IN_CALL for the AudioManager mode.
without success. I don't get audio on my device.
My questions:
Should I use MODE_IN_COMMUNICATION or MODE_IN_CALL?
Need I switch to MODE_NORMAL or other mode in order to play on device?
Can you suggest a code flow to make SCO audio play on a device?
Can you point out some working code to review?
Notes:
The "Media audio" profile (A2DP) is disabled on the device - only "Call audio" profile (HFP) is enabled.
Will gladly share some code, yet given existing SO Q&As it will probably look the same.
Regards.
I'm trying to play two files at the same time and route one to wired headset and the other to the BT headset. Is this even possible? Any ideas how I can achieve this? I'm targeting OS 2.3 and greater.
You can try creating two MediaPlayers with different stream types:
btPlayer = new MediaPlayer(...);
wiredPlayer = new MediaPlayer(...);
...
btPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
wiredPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
...
Of cause you'll need to put extra code to redirect btPlayer to bluetooth headset. For this you'll need to use startBluetoothSco() and setBluetoothScoOn().
Also note, that audio can be redirected to bluetooth headset only on AudioManager.STREAM_VOICE_CALL. But if you are using a2dp bluetooth device, you can redirect audio to this device in AudioManager.STREAM_MUSIC stream as well.