ACTION_HEADSET_PLUG not documented extra strange "state"? - android

I'm doing some test with Intent.ACTION_HEADSET_PLUG.
Giving the fact that the following code should be the one who give the responses (From com.android.server.HeadsetObserver class 2.2.1 r1):
private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
if ((headsetState & headset) != (prevHeadsetState & headset)) {
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
int state = 0;
int microphone = 0;
if ((headset & HEADSETS_WITH_MIC) != 0) {
microphone = 1;
}
if ((headsetState & headset) != 0) {
state = 1;
}
intent.putExtra("state", state);
intent.putExtra("name", headsetName);
intent.putExtra("microphone", microphone);
if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
// TODO: Should we require a permission?
ActivityManagerNative.broadcastStickyIntent(intent, null);
}
}
And in the documentation they say: state - 0 for unplugged, 1 for plugged.
I strangely get two different state by plugging two different headsets:
0 = unplugged
1 = Headset with microphone
2 = Headset without microphone
The question is: where the State 2 (two) come from? Can someone enlighten me?
Thanks

I am using that extra state myself in one of my applications. One of your headsets has a mic the other doesn't. Also make sure you a plugging it in all the way, but don't break anything :)
0 - unplugged as in no headset attached to the device
1 - headset with microphone as in wired headset that had a mic so you can talk and the device uses it as a input as you talk
2 - a headset with no microphone as in your regular old stereo headset that you would normally hook up to your stereo system to listen to music with
This is extremely good info to verify that what was just connected is a wired headset that you expect to be able to talk in to and be heard correctly.

Related

Android charging or plugged to a power source states

I have an dashcam which automatically starts and stops recording based on charging (start on charging and stop when it stops charging)
So I have something like this at the BroadcastReceiver.onReceive
Intent.ACTION_POWER_CONNECTED -> {
startRecording()
}
Intent.ACTION_POWER_DISCONNECTED -> {
stopRecording()
}
Some users reported that recording stops when their device becomes fully charged though it is still plugged to a power source via USB.
So it seems BatteryManager sends the event that the power is not connected.
What can I do in this case to know for sure that it is still plugged to a source power?
Mb should I use the following solution?
Intent.ACTION_BATTERY_CHANGED -> {
val plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0
// conditionally it looks like this: if (plugged) startRec() else stopRec()
}

Get current audio output Android

I want to get current playing audio device (like phone, wired headphones or bluetooth device). Do you know how to get?
My code:
val manager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
return if (manager.isBluetoothScoOn) "Bluetooth"
else if (!manager.isBluetoothScoOn && !manager.isSpeakerphoneOn) "Wired"
else "Phone"

Check if Android device has an internal speaker

How to check if a device running Android has a speaker on it or not? Meaning is it able to play audio?
Are there any Configuration qualifiers for it? and what about programmatically
EDIT: just bought an Android Wear watch and it does NOT have a speaker so not sure how I would check this
Since API level 21 (most Android Wear based on this level), Android provide a feature, PackageManager.FEATURE_AUDIO_OUTPUT, witch can be used to detect whether there is a way to output the audio.
I tested this feature on my MOTO 360 (no speaker), it don't has this feature, and Ticwatch (with speaker) do have this feature.
But when I connected a Bluetooth headset to the MOTO 360, it still don't have this feature, this confused me.
So I use AudioManager.isBluetoothA2dpOn() for further check.
The detection code can be like this:
public boolean hasAudioOutput() {
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
PackageManager packageManager = getPackageManager();
if (audioManager.isBluetoothA2dpOn()) {
// Adjust output for Bluetooth.
return true;
} else if (audioManager.isBluetoothScoOn()) {
// Adjust output for Bluetooth of sco.
return true;
} else if (audioManager.isWiredHeadsetOn()) {
// Adjust output for headsets
return true;
} else if (audioManager.isSpeakerphoneOn()) {
// Adjust output for Speakerphone.
return true;
} else if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
// Has internal speaker or other form of audio output.
return true;
} else {
// No device for audio output.
return false;
}
}
Android API doesn't have any such qualifiers neither there is any library method.
But just a raw idea, try playing some audio and simultaneously record through the mic.
Check if they are same.
This is not a fool proof way, but just a thought!
Probably most android phones have a speaker i guess :P /.. But if you are asking if you can check whether its connected to a speaker or headphones or something like that..then you can use
if (isBluetoothA2dpOn()) {
// Adjust output for Bluetooth.
} else if (isSpeakerphoneOn()) {
// Adjust output for Speakerphone.
} else if (isWiredHeadsetOn()) {
// Adjust output for headsets
} else {
// If audio plays and noone can hear it, is it still playing?
}
SOURCE: http://developer.android.com/training/managing-audio/audio-output.html#CheckHardware

Arduino Mega receiving correct data through Serial 0, but not Serial 1-3

I currently have a HC-06 Bluetooth device connected to my Arduino Mega 2560 in order to receive strings sent from an Android device. With the HC-06 on Serial 0, I am receiving the data without error with the following code:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
}
void loop() {
if(stringComplete) {
ParseSerialData(); // Parse the received data
inString = ""; // Reset inString to empty
stringComplete = false; // Reset the system for further input of data
}
}
void serialEvent() {
while(Serial.available() && stringComplete == false) {
char inChar = Serial.read();
inData[index] = inChar; // Store it in char array
index++;
if (inChar == '\n') { // Check for termination character
index = 0; // Reset the index
stringComplete = true; // Set completion of read to true
} else {
inString += inChar; // Also store as string
}
}
}
When I try to replace "Serial" with "Serial1" and "serialEvent()" with "serialEvent1()" and move the Bluetooth device to the TX1 and RX1, this program no longer works.
I have read that some people had similar problems when using AVR-GCC 4.4.x and solved the issue by downgrading to 4.3.x, but I have 4.3.2 (on Windows 8.1, same problem has arisen with Arduino IDE 1.0.3, 1.0.5-r2, and 1.5.6-r2).
I added the following print statements (with Serial 0 to print to the monitor on my PC) to the code with the Bluetooth device still on Serial 1:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
Serial.println("Setting up...");
}
void loop() {
if(stringComplete) {
ParseSerialData();
inString = "";
stringComplete = false;
}
}
void serialEvent1() {
Serial.println("In serialEvent1...");
while(Serial1.available() && stringComplete == false) {
Serial.println("Char in...");
char inChar = Serial1.read();
Serial.println("WTF");
Serial.println(inChar);
Serial.println("WTF2");
inData[index] = inChar;
index++;
if (inChar == '\n'){
Serial.println("Termination char read...");
index = 0;
stringComplete = true;
}else{
inString += inChar;
}
}
}
Doing this, on the monitor I get:
Setting up...
In serialEvent1...
Char in...
WTF
WTF2
inChar typically prints as nothing, but during one test it was printing as an '#' character. The string sent is "s,1\n" from the Android device.
Based on the print out, the serial event is triggered by availability of serial data, but Serial1.available() remains true for only the first iteration, 's' is not read in (nor any of the other characters that do when Serial is used), and a termination character (newline char) is never read in so that I can begin parsing.
I also tried various baud rates with no difference in behavior. Based on reading Arduino documentation, serial port 1 should work just like serial port 0, and I did not miss substituting Serial for Serial1 in any part of the code.
What could be causing errors in communicating over Serial1 in the same way that has worked flawlessly on Serial0?
I also found a related Stack Overflow question, which was solved with something similar to my code (which works perfectly with Serial0 and is based on the Arduino documentation) using an expected termination character (the difference being that his code implements serial reading in the main loop, whereas mine is in a serialEvent). For some reason, it seems that both of us were having issues with Serial1 data not showing as available at the start of the next iteration. For some reason, serialEvent1 is not being called again for me. And I still don't understand why the first/only character read is not 's.' At first I was thinking that the stream was getting flushed before getting to the serial event again, but that still doesn't account for reading in an incorrect first character.
Also, I added the following Serial1 print statement to run multiple times in the Arduino setup and the Android device receives it each time with no errors, so sending data is working just fine:
Serial1.print("b,1\n");
Or even
Serial1.print("A long test message. A long test message.\n");
I'm fairly close to answering my own question now with further testing/debugging. I actually think the answer may end up being hardware-related rather than software. I wanted to find out if the problem was with the data sent from the HC-06 to port 1, or with the reading function of port 1. I basically had serial port 0 read in data, then send it serially to port 1, which would read that data, and send feedback over Bluetooth to the Android device. Serial port 1 read the data fine coming from port 0, so the issue is reading in data specifically from the HC-06. It may simply be a voltage level issue, so the answer may not belong with Stack Overflow. I will leave the question unanswered though until I definitively have found the root cause (allowing for the possibility that I might need some define statement for the HC-06 or serial port 1 for data to be read correctly, though I'm guessing a voltage level conversion may do the trick. I'm not sure why there would be such a difference between Serial0 and Serial1 though).
I solved the problem enabling the pull-up resistor of the RX1 pin:
Serial1.begin(9600);
pinMode(19, INPUT);
digitalWrite(19, HIGH);
Therefore the 3 V is "overridden" by Arduino's 5 V for logical HIGH and zero is pulled down by Bluetooth's TX for logical LOW.
I did it slightly differently by using the INPUT_PULLUP feature to pull the hardware Serial3 pin HIGH:
Serial3.begin(19200);
pinMode(15, INPUT_PULLUP); // Serial3 receive pin
It works a treat. Previously my serial communications between two Arduino Mega 2560s had been mainly corruption with the occasional correct transmission. Now it is mainly the correct transmission. Previously, the time taken to receive a valid serial value was up to 2.5 seconds (due to having to repeatedly retry to get a valid transmit). Now the time taken to get a valid transmit is 20 ms. (I use a twisted pair of single core wires about 35 cm length.)
After checking the serial data lines on my oscilloscope, I was able to come up with a solution to my issue. With the setup described about the related Stack Overflow question (Bluetooth TX → RX0, TX0 → RX1, TX1 → Bluetooth RX), I checked the signals sent by the Bluetooth device and by the Arduino's serial port 0.
The Bluetooth device's signal was low at 400 mV and high at 3.68 V, while the Arduino's port 0 sent low at 0V and high at 5 V. I knew the Bluetooth device was a 3.3V level device, but the Arduino should read anything above about 3V as high, so this should have not been an issue (and it obviously wasn't on Serial 0).
Anyway, I replaced the HC-06 Bluetooth device with a backup one I had purchased and everything works fine with the code using Serial1 that I posted in my question. This Bluetooth device was transmitting low at about 160 mV and high at 3.3 V.
It seems that my problem was rooted in the hardware (voltage levels) as expected, and that for some reason Serial1 is more sensitive to changes in digital levels than is Serial0.

How to record sound using bluetooth headset

I am writing an android app for storing and managing voice memos with some basic metadata and tagging. When recording sound I use:
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(currentRecordingFileName);
// and so on
This works well when using the phone in a normal fashion. However, it does not detect the presence of a bluetooth headset and still uses the phone's own microphone even when the headset is plugged in.
I also tried using MediaRecorder.AudioSource.DEFAULT, hoping it would automatically choose the correct source, but then no sound was recorded at all.
How can I a) detect if a bluetooth headset is plugged in and/or b) use a bluetooth headset as audio source for the media recorder?
olivierg is basically right (AudioSource can still be MIC), some basic code would look like this:
am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
Log.d(TAG, "Audio SCO state: " + state);
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
/*
* Now the connection has been established to the bluetooth device.
* Record audio or whatever (on another thread).With AudioRecord you can record with an object created like this:
* new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
* AudioFormat.ENCODING_PCM_16BIT, audioBufferSize);
*
* After finishing, don't forget to unregister this receiver and
* to stop the bluetooth connection with am.stopBluetoothSco();
*/
unregisterReceiver(this);
}
}
}, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
Log.d(TAG, "starting bluetooth");
am.startBluetoothSco();
This I stumbled upon this myself just again, I want to point out the importance of slott's comment to include the right permissions, most importantly to set
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
in your manifest file. Without it you will not get any error message but the state will simply not change to connected.
According to the documentation you need to start a SCO audio connection with AudioManager.startBluetoothSco(), and then it seems like you need to use MediaRecorder.AudioSource.VOICE_CALL.
As far as I can see, you can't select a particular device and such. This is performed at system level, ie after the user pairs the headset with the phone.
EDIT:
As mentioned by Stefan, the AudioSource needs to be MIC.
VOICE_CALL doesn't seem to work.
You can detect connected bluetooth devices like this:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
However, I'm not sure how you make it record from the headset and not the regular MIC

Categories

Resources