so i'm currently developing an android service which implements the HFP profile for later use with a gui , i was able to successfully and easily implement the RFCOMM part where the AT commands like ATA(accep call) are sent , but i am stuck with accepting the audio SCO Connection on the app . so basically im testing with an Iphone AG Role and an android tablet HF Role which runs my app , to open the SCO connection i have tried calling AudioMAnager.startBluetoothSco(); without any luck , and even made a bluetooth SCO socket server in C using the ndk , which listens for a connection. but the actual problem is that the Iphone doesnt seem to try to connect with the sco socket , so i dumped the trafic from the android tablet and saw that when the Iphone requests the SCO connection the android hci automatically responds with Reject of reason: Connection Rejected due to Limited Resources (0x0d) , no matter what i do, maybe im missing something? any ideas? thanks. forgot to mention that both devices are paired using the os settings app and the connection is established by connecting to the android tablet from the native settings app of ios.
AudioHandler.java
public class AudioHandler implements Runnable{
static
{
System.loadLibrary("libsco");
}
#Override
public void run()
{
AudioManager amanager = (AudioManager) Common.APPCONTEXT.getSystemService(Context.AUDIO_SERVICE);
amanager.setMode(AudioManager.MODE_IN_COMMUNICATION);
amanager.startBluetoothSco();
amanager.setBluetoothScoOn(true);
if(amanager.isBluetoothScoOn())
{
int status= this.SCOINIT();
Log.d("SCO","SCOFinished");
}
/*while(Common.isCallActive)
{
play(stream.readbytes());
}
this.SCOCLOSE();
amanager.stopBSCO();
*/
}
private native int SCOINIT();}
libsco.c
void init() {
struct sockaddr_sco addr = {0}, remoteadress = {0};
int SCOServer, SCOClient;
SCOServer = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
if (SCOServer < 0) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "SCO socket create failed.");
print("SCO socket create failed.");
}
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, BDADDR_ANY);
if (bind(SCOServer, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
print("failed to bind sco.");
}
if (listen(SCOServer, 1)) {
print("Listening Failed!!");
} else {
print("Listening for SCO connection.");
}
socklen_t addrlength = sizeof(remoteadress);
SCOClient = accept(SCOServer, (struct sockaddr *) &remoteadress, &addrlength);
if (SCOClient < 0) {
print("Accept Failed!!");
close(SCOClient);
} else {
print("Conected.\n");
close(SCOClient);
}
close(SCOServer);
}
everything runs without errors and i can see the "LIstening for SCO Connection " line, but it never accepts because the android hci rejects the connection before anything can be done...
screenshot from wireshark
Related
Overview: I'm currently working on an Android app which connects to a Linux system via WiFi Direct, with the final intent of streaming video over this established connection.
The raspi will be acting as a server in this scenario, with the Android being the client. I will be streaming from a camera attached to the pi, and receiving this video on the Android side to display in my app using ExoPlayer. The pi cannot start sending this video over a datagram socket without having the client's ip address. The Android device will also need to send out miscellaneous packets to the Pi which would be telling it what to do, thus the need for both devices having each others ip addresses.
The current Linux system I am working on is a Raspberry Pi running Raspian, with development taking place in C++. The Android runtime environment being a Samsung Galaxy Tab A.
Problem: I'm able to successfully establish a connection between the two devices, which I have setup so that the Raspberry Pi is always the group owner. With the Pi being group owner, it doesn't have immediate access to the Android's IP address; thus a temporary TCP socket connection must be made between the two so the Raspberry Pi can take note of the Android's IP address.
After a WiFi connection is established, this C++ code is ran on the Pi to open & accept a TCP socket connection from the Android:
#include<cstddef>
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<unistd.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define BACKLOG 2 //Allowed connection count.
#define PORT 8988 //The port we will be listening on.
//The static IP of p2p-dev-wlan0
const std::string MY_IP = "192.168.4.1";
bool listen_for_ip() {
//Buffer for receiving messages.
char buffer[256];
//Create Server Socket:
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
return false;
else
std::cout << "Created Server" << std::endl;
struct sockaddr_in my_addr, peer_addr;
//Recieve messages from IPv4 addresses.
my_addr.sin_family = AF_INET;
//Set our IP address of the socket to the value in "MY_IP"
my_addr.sin_addr.s_addr = inet_addr(MY_IP.c_str());
//my_addr.sin_addr.s_addr = INADDR_ANY; // Also tested with this, no luck.
//Set our in port to the value in "PORT"
my_addr.sin_port = htons(PORT);
//Attempt to bind to IP and port.
if (bind(sock_fd, (struct sockaddr*) &my_addr, sizeof(my_addr)) == 0)
std::cout << "Binded successfully" << std::endl;
else
return false;
//Listen on the socket
if (listen(sock_fd, BACKLOG) < 0)
return false;
//Accept a connection.
socklen_t peer_addr_size = sizeof(peer_addr);
std::cout << "Accepting connection ..." << std::endl;
int new_fd = accept(sock_fd, (struct sockaddr*) &peer_addr, &peer_addr_size);
if (new_fd == -1) {
std::cout << "Error accepting connect" << std::endl;
close(sock_fd);
return false;
}
else
std::cout << "Connection accept completed status = " << new_fd << std::endl;
//
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(peer_addr.sin_addr), ip, INET_ADDRSTRLEN);
if (recv(new_fd, buffer, 256, 0) < 0) {
close(new_fd);
close(sock_fd);
return false;
}
std::cout << "Client says " << buffer << std::endl;
//Do other stuff with connection ...
close(new_fd);
close(sock_fd);
return true;
}
This code runs successfully, and as should blocks on the accept() call to wait for the Android connect to the socket.
On the Android side this code is ran to connect to the Pi (Group owner) over a basic socket:
public static final int PORT = 8988;
private static final int TIMEOUT_MS = 10000;
private final String myIp;
private WifiP2pInfo mGroupInfo;
private final WifiDirectService mWifiDirectService;
public P2pClientSocket(WifiDirectService wifiDirectService, WifiP2pInfo groupInfo, String ourDeviceIP) {
mGroupInfo = groupInfo;
myIp = ourDeviceIP;
mWifiDirectService = wifiDirectService;
exchangeIP();
}
/**
* Utilizes a basic socket & TCP to ensure that the IP address of this machine is sent to the group owner of established P2P group.
* If there is an error with sending or writing this message, or the message times out,
* {#link WifiDirectService} will be notified to immediately dispose of its current connection.
*/
private void exchangeIP() {
Socket initSocket = new Socket();
Runnable r = () -> {
try {
String host = mGroupInfo.groupOwnerAddress.getHostAddress();
Log.d(TAG, "Opening socket to : " + host + ", " + PORT);
initSocket.connect(new InetSocketAddress(host, PORT), TIMEOUT_MS);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(initSocket.getOutputStream(), StandardCharsets.UTF_8);
outputStreamWriter.write(myIp, 0, myIp.length());
outputStreamWriter.close();
Log.d(TAG, "Successfully wrote IP.");
} catch (SocketTimeoutException e) {
String message = "Connection Timeout - Disconnecting.";
Log.e(TAG, message, e);
mWifiDirectService.socketError(message);
} catch (IOException e) {
String message = "IP Exchange Error - Disconnecting.";
Log.e(TAG, message, e);
mWifiDirectService.socketError(message);
} finally {
try {
initSocket.close();
} catch (IOException e) {
Log.e(TAG,"Error Closing Init Socket.");
}
}
};
new Thread(r).start();
}
The value of
String host = mGroupInfo.groupOwnerAddress.getHostAddress()
will always be the IP address of the raspberry pi. I have configured it so it runs as a DHCP server with a static IP using:
cat > /etc/systemd/network/12-p2p-wlan0.network <<EOF
[Match]
Name=p2p-wlan0-*
[Network]
Address=192.168.4.1/24
DHCPServer=yes
EOF
However, on the .connect() call, the timeout threshold is always reached. I'm a bit of a networking noob so I'm not entirely sure on what I'm doing wrong. Included is the timeout stack trace:
java.net.SocketTimeoutException: failed to connect to /192.168.4.1 (port 8988) from /192.168.4.163 (port 33122) after 10000ms
at libcore.io.IoBridge.connectErrno(IoBridge.java:191)
at libcore.io.IoBridge.connect(IoBridge.java:135)
at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
at java.net.Socket.connect(Socket.java:621)
at com.nlos.networking.P2pClientSocket.lambda$exchangeIP$0$P2pClientSocket(P2pClientSocket.java:54)
at com.nlos.networking.-$$Lambda$P2pClientSocket$fxU2Z0Zg0gRF1Fyl1fNnqgO2m8I.run(Unknown Source:4)
at java.lang.Thread.run(Thread.java:919)
I've tried multiple different sockets, ensured that the pi is actually up and listening, and am honestly stumped at this point. Any help would be greatly appreciated!
I currently purchased the 3DR bluetooth module for pixhawk to transfer telemetry data to an android phone. I am able to connect to the device, i.e. the bluetooth module turns solid red. However, the android program says that the phone and pixhawk are not connected. Here is my current connection setup.
protected void updateConnectedButton(Boolean isConnected) {
Button connectButton = (Button)findViewById(R.id.btnConnect);
connectButton.setText(isConnected ? "Disconnect" : "Connect");
}
public void onBtnConnectTap(View view) {
if(drone.isConnected()) {
drone.disconnect();
} else {
Bundle extraParams = new Bundle();
extraParams.putInt(ConnectionType.EXTRA_USB_BAUD_RATE, DEFAULT_USB_BAUD_RATE); // Set default baud rate to 57600
//connect with usb
//ConnectionParameter connectionParams = new ConnectionParameter(ConnectionType.TYPE_USB, extraParams, null);
ConnectionParameter connectionParams = new ConnectionParameter(ConnectionType.TYPE_BLUETOOTH,extraParams,null);
drone.connect(connectionParams);
}
try {
Thread.sleep(8000);
} catch(InterruptedException e) {
}
updateConnectedButton(drone.isConnected());
}
If I remove the USB Baud rate setting, the red light on the device keeps blinking when I attempt to connect. I added a sleep because the bluetooth module takes a while to connect. The documentation and examples don't talk much about bluetooth connections. Any ideas what I am doing wrong?
I'm trying to use arduino with Bluetooth module (HC-06).
And also im trying to send/receive data from android with the app (ArduDroid which is in playstore).
But i have the problem while sending program to Arduino uno after successful compilation.
The error Code is when vcc connected to 3.3V
avrdude: stk500_getsync(): not in sync: resp=0x00
When i connected to 5V sometimes error code changes to but usually same as 3.3v
avrdude: stk500_getsync(): not in sync: resp=0x45.
When i unplug the bt device sending program is successful but i cant receive or send anything.
I checked com port and board. Everything is OK.
Please help me to continue my licence project.
Best regards..
The code is as below:
int ledPin = 13;
int state = 0;
int flag = 0;
void setup() {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
Serial.begin(9600); // Default connection rate for my BT module
}
void loop() {
if(Serial.available() > 0){
state = Serial.read();
flag=0;
}
if (state == '0') {
digitalWrite(ledPin, LOW);
if(flag == 0){
Serial.println("LED: off");
flag = 1;
}
}
else if (state == '1') {
digitalWrite(ledPin, HIGH);
if(flag == 0){
Serial.println("LED: on");
flag = 1;
}
}
}
You need to unplug the module before uploading the code via USB.
the module uses the same serial pins than the ones used for USB serial, that's where your issue comes from.
uploading code via bt is tricky. it can be done but I've never succeeded myself... :(
I've solved the problem as the same way. Just unplug the bt device and upload. After this step, plug again and connect to dc. Thats OK. working.
The source of the problem is serial ports as i understand. BT module using 9600 port and disconnecting the connection between computer and arduino.
I'm trying to send UDP packets from an emulated device (Nexus S 4.0", 480 x 800: hdpi) to my host PC for development and testing. The sending side seems correct and doesn't encounter any errors, but Wireshark indicates they are not arriving at the host PC. I've researched this problem and all the fixes that worked for others are not working for me:
I added "uses-permission android:name="android.permission.INTERNET" to the maifest XML file. (I also have ACCESS_NETWORK_STATE but I don't think that's necessary for this.)
I am sending the packets to the host loopback address 10.0.2.2. The port is 5006, so it's not one that I should need special privileges for.
I am calling DatagramSocket.send() in a dedicated thread, not in the main thread. (I think this would throw NetworkOnMainThreadException anyway, and I'm not getting any exceptions.)
I have Telnet-ed into "localhost 5444" and issued the "redir add udp:5006:5006" command to setup UDP port forwarding on the emulator's virtual router. The command returns "OK" without error, and "redir list" returns "udp:5006 => 5006".
I've also setup UDP port forwarding (port 5006) on my host PC's router (between PC and open internet). But I don't think that should be necessary, this router is not between the emulator and the host PC.
I have disabled Windows firewall and anti-virus on the host PC.
Here is the relevant code in my MainActivity.java. The start() and stop() methods are called from button clicks (omitted because they are not part of the problem):
private static String TAG = "MainActivity";
private volatile boolean running = false;
private String ip = "10.0.2.2";
private int port = 5006;
public void start(View view) {
new Thread() {
public void run() {
byte[] bytes = "Hi from UDPSender!".getBytes();
try {
InetAddress inetAddr = InetAddress.getByName(ip);
running = true;
while (running == true) {
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, inetAddr, port);
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(false);
socket.send(packet);
socket.close();
Log.d(TAG, "Send packet to "+packet.getAddress().getHostAddress()+":"+packet.getPort());
Thread.sleep(1000);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}.start();
}
public void stop(View view) {
running = false;
}
I have a device which supports the OBEX Object Push Profile, this profile is based upon the Serial Port Profile. My guess is that I can use the Android Bluetooth Chat example for connecting this device to my Android Phone. But I ran into a problem, regarding the socket.accept() functionality in the android SDK. I try to accomplish to connect my phone with this device like this:
adapter = BluetoothAdapter.getDefaultAdapter();
device = adapter.getRemoteDevice("00:1B:DC:0F:EC:7E");
AcceptThread = new AcceptThread(true, adapter, device);
AcceptThread.start();
The constructor in AcceptThread is coded like this:
public AcceptThread(boolean secure, BluetoothAdapter adapter, BluetoothDevice device) {
BluetoothServerSocket tmp = null;
this.adapter = adapter;
this.device = device;
// Create a new listening server socket
try {
tmp = adapter.listenUsingInsecureRfcommWithServiceRecord(device.getName(), UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (Exception e) {
Log.e(TAG, ".AcceptThread # listen() failed", e);
}
mmServerSocket = tmp;
}
The problem is when I try to do a connect() as I said before
public void run() {
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
Log.d(TAG, "AcceptThread.run: accepting server socket connection");
socket = mmServerSocket.accept(20000);
Log.d(TAG, ".AcceptThread.run # server socket connection accepted");
} catch (Exception e) {
Log.e(TAG, ".run # accept() failed: "+e);
break;
}
}
}
As you can see the ServerSocket accept every incomming connection for 20 seconds or 20000 ms. When the time is up, the app will throw an IOException like this
07-11 10:30:08.355: E/SIMPLECONNECT(1301): .run # accept() failed: java.io.IOException: Connection timed out
which tells me that my device couldnt connect to my android phone. The device doesnt have a connect button on the display, just a send functionalitywhich will send a file to my phone. I believe that this send functionality also do a connect in the background, but I am not sure.
Can anybody pinpoint any solutions for me? I am running my app on a Samsung Galaxy SIII with Android 4.0.4
I finally solved it, the problem is that different Android Versions and different devices seemes to need different sockets. I tryed it with Samsung Galaxy XCOVER, Tab1, Tab2, Nexus, Note, Motorola Defy and HTC Flyer.
The Sockets I used are:
A:
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
mSocket = (BluetoothSocket) m.invoke(mmDevice, Integer.valueOf(1));
B:
Method m = mmDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[]{int.class});
mSocket=(BluetoothSocket)m.invoke(mmDevice,Integer.valueOf(1));
C:
mSocket=BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mmDevice.getAddress()).createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Android 4.0.x works for Nexus, Flyer,Tab1 with A,B
Android 4.0.3 works for Tab2 with B
Android 3,6,x works for DEFY with A,B
Android 2.3.6 works for XCOVER with C
I can't find a solution witch works for all devices and I;m not able to find out witch socket will work before I create and use the Socket, especially the XCOVER perform the connect() for all Sockets without throwing an exception, but catch if i try tro write(). So if you want to setup a bloothoh connection wich works for all devices you have to create the sockets, connect an write and then remeber the socket wich works (e.g. in preferences)