2011年11月14日 星期一

[Android] Bluetooth - (2) Connection

Connecting as a server
  • Server is holding an open BluetoothServerSocket.
  • The purpose of the server socket is to listen for incoming connection requests and when one is accepted, provide a connected BluetoothSocket.
  • When the BluetoothSocket is acquired from the BluetoothServerSocket, the BluetoothServerSocket can (and should) be discarded, unless you want to accept more connections.


Here's the basic procedure to set up a server socket and accept a connection:

1. Get a BluetoothServerSocket by calling thelistenUsingRfcommWithServiceRecord(String, UUID).
  • The string is an identifiable name of your service.
  • The system will automatically write to a new Service Discovery Protocol (SDP) database entry on the device (the name is arbitrary and can simply be your application name).
  • The UUID is also included in the SDP entry and will be the basis for the connection agreement with the client device.
    • When the client attempts to connect with this device, it will carry a UUID that uniquely identifies the service with which it wants to connect
    • These UUIDs must match in order for the connection to be accepted (in the next step).

2. Start listening for connection requests by calling accept().
  • This is a blocking call. 
    • The accept() call should not be executed in the main Activity UI thread because it is a blocking call and will prevent any other interaction with the application.
    • To abort a blocked call such as accept(), call close() on the BluetoothServerSocket (or BluetoothSocket) from another thread and the blocked call will immediately return. 
  • It will return when either a connection has been accepted or an exception has occurred. 
  • A connection is accepted only when a remote device has sent a connection request with a UUID matching the one registered with this listening server socket.
  • When successful, accept() will return a connected BluetoothSocket.

3. Unless you want to accept additional connections, call close().
  • This releases the server socket and all its resources, but does not close the connected BluetoothSocket that's been returned by accept()
  • Unlike TCP/IP, RFCOMM only allows one connected client per channel at a time, so in most cases it makes sense to call close() on the BluetoothServerSocket immediately after accepting a connected socket.
Note:
  • All methods on a BluetoothServerSocket or BluetoothSocket are thread-safe.
    • It usually makes sense to do all work with a BluetoothServerSocket or BluetoothSocket in a new thread managed by your application.
  • When accept() returns the BluetoothSocket, the socket is already connected, so you should not call connect() (as you do from the client-side).



Connecting as a client
  • In order to initiate a connection with a remote device, you must first obtain a BluetoothDevice object that represents the remote device.
  • You must then use the BluetoothDevice to acquire a BluetoothSocket and initiate the connection.

Here's the basic procedure:

1. Using the BluetoothDevice, get a BluetoothSocket by calling createRfcommSocketToServiceRecord(UUID).
  • This initializes a BluetoothSocket that will connect to the BluetoothDevice
  • The UUID passed here must match the UUID used by the server device when it opened its BluetoothServerSocket (with listenUsingRfcommWithServiceRecord(String, UUID)).
  • Using the same UUID is simply a matter of hard-coding the UUID string into your application and then referencing it from both the server and client code.


2. Initiate the connection by calling connect().
  • This method is a blocking call. 
    • If, for any reason, the connection fails or the connect() method times out (after about 12 seconds), then it will throw an exception.
    • This connection procedure should always be performed in a thread separate from the main Activity thread.
  • Upon this call, the system will perform an SDP lookup on the remote device in order to match the UUID
    • If the lookup is successful and the remote device accepts the connection, it will share the RFCOMM channel to use during the connection and connect() will return. 
Note: 
  • Ensure that the device is not performing device discovery when you call connect().
    • If discovery is in progress, then the connection attempt will be significantly slowed and is more likely to fail.
  • cancelDiscovery() is called before the connection is made.
    • You should always do this before connecting and it is safe to call without actually checking whether it is running or not (but if you do want to check, call isDiscovering()).


Managing a Connection

Using the BluetoothSocket, the general procedure to transfer arbitrary data is simple:
  1. Get the InputStream and OutputStream that handle transmissions through the socket, via getInputStream() and getOutputStream(), respectively.
  2. Read and write data to the streams with read(byte[]) and write(byte[]).
Note
  • Should use a dedicated thread for all stream reading and writing.
    • This is important because both read(byte[]) and write(byte[]) methods are blocking calls.



Working with Profiles
Starting in Android 3.0, the Bluetooth API includes support for working with Bluetooth profiles.

A Bluetooth profile
  • Is a wireless interface specification for Bluetooth-based communication between devices. 
  • An example is the Hands-Free profile. For a mobile phone to connect to a wireless headset, both devices must support the Hands-Free profile.

Support Profiles
  • Headset
    • The Headset profile provides support for Bluetooth headsets to be used with mobile phones.
    • BluetoothHeadset class
      • A proxy for controlling the Bluetooth Headset Service via interprocess communication (IPC). 
      • Includes both Bluetooth Headset and Hands-Free (v1.5) profiles.
      • Support for AT commands. For more discussion of this topic, see Vendor-specific AT commands
  • A2DP
    • The Advanced Audio Distribution Profile (A2DP).
    • Defines how high quality audio can be streamed from one device to another over a Bluetooth connection.
    • BluetoothA2dp class
      • A proxy for controlling the Bluetooth A2DP Service via IPC.


Here are the basic steps for working with a profile:
  1. Get the default adapter, as described in Setting Up Bluetooth.
  2. Use getProfileProxy() to establish a connection to the profile proxy object associated with the profile. In the example below, the profile proxy object is an instance of BluetoothHeadset.
  3. Set up a BluetoothProfile.ServiceListener. This listener notifies BluetoothProfile IPC clients when they have been connected to or disconnected from the service.
  4. In onServiceConnected(), get a handle to the profile proxy object.
  5. Once you have the profile proxy object, you can use it to monitor the state of the connection and perform other operations that are relevant to that profile.



By the way

UUID
  • Universally Unique Identifier (UUID) 
  • A standardized 128-bit format for a string ID used to uniquely identify information. 
  • Big enough that you can select any random and it won't clash.
  • Used to uniquely identify your application's Bluetooth service.
  • To get a UUID to use with your application, you can use one of the many random UUID generators on the web, then initialize a UUID with fromString(String).



* Reference
Bluetooth | Android Developers **
package android.bluetooth
Android應用程式學習筆記 - Bluetooth
藍牙規範 - 维基百科,自由的百科全书
Bluetooth profile - Wikipedia, the free encyclopedia
Android 上的 Bluetooth | 憑虛御風
Bluetooth Health Devices

沒有留言:

張貼留言