Skip to main content

Request Transfer (TSRequestTransfer)

The TSRequestTransfer module provides bidirectional data transfer between the device and the App based on a request-response model. The device can send requests (with parameters and file paths) to the App; the App processes them and sends a response back. The module also includes an audio conversion utility that turns MP3 files into PCM suitable for device playback.

Prerequisites

  1. TopStepComKit SDK has been successfully initialized
  2. A Bluetooth connection with the peripheral device has been established
  3. The peripheral device supports request transfer

Data Models

TSRequestModel

The request model sent from the device to the App.

PropertyTypeDescription
requestNameNSString *Request name identifying the type or purpose
requestIdNSString *Unique request identifier used to match requests with responses
requestUrlNSString *Target URL endpoint for the request
parametersNSDictionary *Request parameters as key-value pairs
appIdNSString *Identifier of the application issuing the request
deviceStoragePathNSString *Remote path on the device where response files are stored
remoteFilePathsNSArray<NSString *> *Remote file paths on the device that need to be downloaded
localFilePathsNSArray<NSString *> *Local file paths corresponding to remoteFilePaths

TSRespondModel

The response model sent from the App back to the device.

PropertyTypeDescription
requestIdNSString *Must match the requestId of the original TSRequestModel
requestNameNSString *Must match the requestName of the original request
appIdNSString *Identifier of the application that originated the request
responseContentNSDictionary *Response payload as key-value pairs
errorCodeNSIntegerError code; 0 indicates success, non-zero indicates failure
errorMessageNSString *Error description; nil on success
deviceStoragePathNSString *Remote path on the device where files are stored
localFilePathsNSArray<NSString *> *Local file paths included in the response

Callback Types

CallbackDescription
void (^)(TSRequestModel *_Nullable request, NSError *_Nullable error)Request listener callback, fired when a request from the device is received. A nil error means the request data is valid
TSCompletionBlockGeneric completion callback; nil error indicates success

Interface Methods

1. Request Listening

Register Request Listener

Registers a listener to receive requests from the device. Registering again overwrites the previous listener — only the most recently registered callback is active.

- (void)registerRequestListener:(TSRequestListenerBlock)completion;

Parameters

NameTypeDescription
completionTSRequestListenerBlockCallback invoked when a request is received, returning the request model or an error

Example

id<TSRequestTransferInterface> requestTransfer = [TopStepComKit sharedInstance].requestTransfer;

[requestTransfer registerRequestListener:^(TSRequestModel *_Nullable request, NSError *_Nullable error) {
if (error) {
TSLog(@"Failed to receive request: %@", error.localizedDescription);
return;
}
TSLog(@"Request received - name: %@, id: %@", request.requestName, request.requestId);
TSLog(@"Parameters: %@", request.parameters);

// Handle the request and respond immediately
[self handleRequest:request];
}];

2. Responding to Requests

Respond to a Device Request

Sends a response back to the device after processing an incoming request.

- (void)respondToRequest:(TSRespondModel *)respondModel
completion:(TSCompletionBlock)completion;

Parameters

NameTypeDescription
respondModelTSRespondModel *Response model; its requestId and requestName must match the original request
completionTSCompletionBlockCompletion callback for the send operation; a nil error means the response was sent successfully

Example

id<TSRequestTransferInterface> requestTransfer = [TopStepComKit sharedInstance].requestTransfer;

// Build the response from the received TSRequestModel.
TSRespondModel *respond = [[TSRespondModel alloc] init];
respond.requestId = request.requestId;
respond.requestName = request.requestName;
respond.appId = request.appId;
respond.errorCode = 0; // 0 means success
respond.responseContent = @{
@"status": @"ok",
@"data": @"processed payload"
};

[requestTransfer respondToRequest:respond completion:^(NSError *_Nullable error) {
if (!error) {
TSLog(@"Response sent");
} else {
TSLog(@"Failed to send response: %@", error.localizedDescription);
}
}];

3. Audio Format Conversion

MP3 to PCM

Converts an MP3 file to PCM for device playback. Sample rate and bit depth are configurable.

- (void)convertMP3ToPCM:(NSString *)mp3FilePath
pcmFilePath:(NSString *)pcmFilePath
sampleRate:(NSInteger)sampleRate
bitDepth:(NSInteger)bitDepth
completion:(TSCompletionBlock)completion;

Parameters

NameTypeDescription
mp3FilePathNSString *Local path of the source MP3 file
pcmFilePathNSString *Local path to write the output PCM file
sampleRateNSIntegerTarget sample rate in Hz (e.g. 8000, 16000, 44100); must match the device
bitDepthNSIntegerTarget bit depth (e.g. 8, 16, 24); must match the device
completionTSCompletionBlockCompletion callback; a nil error means conversion succeeded

Example

id<TSRequestTransferInterface> requestTransfer = [TopStepComKit sharedInstance].requestTransfer;

NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *mp3Path = [documentsPath stringByAppendingPathComponent:@"ringtone.mp3"];
NSString *pcmPath = [documentsPath stringByAppendingPathComponent:@"ringtone.pcm"];

[requestTransfer convertMP3ToPCM:mp3Path
pcmFilePath:pcmPath
sampleRate:16000
bitDepth:16
completion:^(NSError *_Nullable error) {
if (!error) {
TSLog(@"MP3 conversion done, PCM at: %@", pcmPath);
// On success you can put the PCM path into TSRespondModel.localFilePaths and send it back.
} else {
TSLog(@"Conversion failed: %@", error.localizedDescription);
}
}];

Full Example

The following sample shows the full request-response flow: receiving a request, converting audio, and sending a response.

id<TSRequestTransferInterface> requestTransfer = [TopStepComKit sharedInstance].requestTransfer;

// 1. Register the listener (call once after a successful connection).
[requestTransfer registerRequestListener:^(TSRequestModel *_Nullable request, NSError *_Nullable error) {
if (error || !request) {
TSLog(@"Request reception error: %@", error.localizedDescription);
return;
}

TSLog(@"Received request: %@", request.requestName);

// 2. If the request needs an audio file, convert it first.
if ([request.requestName isEqualToString:@"playRingtone"]) {
NSString *mp3Path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tone.mp3"];
NSString *pcmPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tone.pcm"];

[requestTransfer convertMP3ToPCM:mp3Path
pcmFilePath:pcmPath
sampleRate:16000
bitDepth:16
completion:^(NSError *convertError) {
// 3. Build and send the response.
TSRespondModel *respond = [[TSRespondModel alloc] init];
respond.requestId = request.requestId;
respond.requestName = request.requestName;
respond.appId = request.appId;
respond.errorCode = convertError ? -1 : 0;
respond.errorMessage = convertError.localizedDescription;
respond.localFilePaths = convertError ? nil : @[pcmPath];

[requestTransfer respondToRequest:respond completion:^(NSError *sendError) {
TSLog(@"Response send %@", sendError ? @"failed" : @"succeeded");
}];
}];
}
}];

Notes

  1. Single listener: Calling registerRequestListener: multiple times overwrites the previous listener; only the last registration is active. Register it once after the App starts.
  2. requestId must match: When calling respondToRequest:completion:, TSRespondModel.requestId must exactly match the incoming TSRequestModel.requestId; otherwise the device cannot correlate the response.
  3. Respond promptly: Some devices enforce a response timeout, so reply as quickly as possible.
  4. Sample rate and bit depth: The sampleRate and bitDepth passed to convertMP3ToPCM: must match the device's supported parameters; mismatches can cause playback issues.
  5. Completion callbacks: All callbacks are invoked on the main thread, so you can update the UI directly inside them.