RFCOMM Scenario: Send File as a Client (HTML)

The basic App scenario is to connect to a paired device based on a desired service. In this scenario, the developer can use the provided RfcommDeviceService.GetDeviceSelector* functions to help generate an AQS query that can be used to enumerated paired device instances of the desired service. From there, the App developer picks an enumerated device, creates an RfcommDeviceService, and reads the SDP attributes as needed (using established data helpers to parse the attribute’s Data). The App developer can then create a socket and use the RfcommDeviceService’s ConnectionHostName and ConnectionServiceName property to ConnectAsync to the remote device service with the appropriate parameters. When it’s time to send a file, the App developer can follow established data stream patterns to read chunks of data from the file and send it on the socket’s OutputStream to the device.

var _service;    // Windows.Devices.Bluetooth.RfcommDeviceService
var _socket;     // Windows.Networking.Sockets.StreamSocket

function Initialize() {
    // Enumerate devices with the object push service
    Windows.Devices.Enumeration.DeviceInformation.findAllAsync(
        RfcommDeviceService.getDeviceSelector(
            RfcommServiceId.obexObjectPush))
    .done(function(services) {
        if (services.length > 0) {
            // Initialize the target Bluetooth BR device
            RfcommDeviceService.fromIdAsync(services[0].id)
            .done(function(service) {
                // Check that the service meets this App’s minimum
                // requirement
                if (SupportsProtection(service)
                    && IsCompatibleVersion(service))
                {
                    _service = service;

                    // Create a socket and connect to the target
                    _socket = new StreamSocket();
                    _socket.connectAsync(
                        _service.connectionHostName,
                        _service.connectionServiceName,
                        SocketProtectionLevel
                            .bluetoothEncryptionAllowNullAuthentication)
                    .done(function () {
                        // The socket is connected. At this point the App can
                        // wait for the user to take some action, e.g. click
                        // a button to send a file to the device, which could
                        // invoke the Picker and then send the picked file.
                        // The transfer itself would use the Sockets API and
                        // not the Rfcomm API, and so is omitted here for
                        // brevity.
                    });
                }
            });
        }
    });
}

// This App requires a connection that is encrypted but does not care about
// whether its authenticated.
function SupportsProtection(service)
{
    switch (service.protectionLevel)
    {
    case SocketProtectionLevel.plainSocket:
        if ((service.maximumProtectionLevel == SocketProtectionLevel
                .bluetoothEncryptionWithAuthentication)
            || (service.maximumProtectionLevel == SocketProtectionLevel
                .bluetoothEncryptionAllowNullAuthentication)
        {
            // The connection can be upgraded when opening the socket so the
            // App may offer UI here to notify the user that Windows may
            // prompt for a PIN exchange.
            return true;
        }
        else
        {
            // The connection cannot be upgraded so an App may offer UI here
            // to explain why a connection won’t be made.
            return false;
        }
    case SocketProtectionLevel.bluetoothEncryptionWithAuthentication:
        return true;
    case SocketProtectionLevel.bluetoothEncryptionAllowNullAuthentication:
        return true;
    }
    return false;
}

// This App relies on CRC32 checking available in version 2.0 of the service.
var SERVICE_VERSION_ATTRIBUTE_ID = 0x0300;
var byte SERVICE_VERSION_ATTRIBUTE_TYPE = 0x0A;   // UINT32
var MINIMUM_SERVICE_VERSION = 200;
function IsCompatibleVersion(service)
{
    service.getSdpRawAttributesAsync(BluetoothCacheMode.Uncached)
    .done(function(attributes) {
        var attribute = attributes[SERVICE_VERSION_ATTRIBUTE_ID];
        var reader = DataReader.fromBuffer(attribute);

        // The first byte contains the attribute's type
        var attributeType = reader.readByte();
        if (attributeType == SERVICE_VERSION_ATTRIBUTE_TYPE)
        {
            // The remainder is the data
            var version = reader.uint32();
            return version >= MINIMUM_SERVICE_VERSION;
        }
    });
}