Skip to content

Implementation

This guide uses iOS SDK 5.1.0. See installation and update instructions.

Configure the recognizer

Import the SORI framework and configure the shared recognizer with your SORI application credentials.

swift
import SORI

let recognizer = SORIAudioRecognizer.shared()
let configuration = SORIAudioRecognizer.Configuration(
    applicationID: "YOUR_SORI_APP_ID",
    secretKey: "YOUR_SORI_SECRET_KEY"
)

recognizer.configure(configuration)

Start recognition

Call startRecognition(repeat:handler:) after configuration. The handler receives the campaign payload returned by SORI API when a registered material is recognized.

swift
recognizer.startRecognition(repeat: true) { media, error in
    if let error {
        print("SORI recognition error: \(error)")
        return
    }

    guard let campaign = media as? [String: Any] else {
        return
    }

    handleRecognizedCampaign(campaign)
}

Enable Audio Marker recognition

Audio Marker recognition is disabled by default. In the default mode, iOS recognition remains fingerprint-only. Enable it only when your SORI Console setup uses Audio Markers.

swift
let configuration = SORIAudioRecognizer.Configuration(
    applicationID: "YOUR_SORI_APP_ID",
    secretKey: "YOUR_SORI_SECRET_KEY"
)
configuration.audiomarker = true

recognizer.configure(configuration)

For current-marker UI and later activity enrichment, use the SDK-managed state and activity result APIs. The SDK manages expiry, marker traits and updates to the same activity. Existing campaign and discovery callbacks remain compatible.

Render an ordered continuous-activity timeline

The following guidance is for existing campaign callbacks. For the new SDK-accepted activity results, use the exact-ID update rules in Audio Marker state and activity results; these results can update the matching historical activity.

The recognition handler can first return a campaign for a material and later return a marker-refined campaign for that same activity. Show the first result immediately, but keep an explicit current segment in application state. The public payload dictionary may provide activity_id, material_id, and trait.marker.

  • A non-empty activity_id may refine only the current row with that exact ID. Do not search the complete timeline by activity, campaign, or material ID.
  • Older payloads may omit activity_id. In that case, a material_id fallback is safe only for the current row and must not become a global identity.
  • Retain the time, position, and other first-observation metadata stored for the row. The later callback updates marker and campaign presentation fields, not the original observation.
  • Merge marker and refined campaign values so later marker misses or less complete duplicate payloads cannot downgrade the current row.
  • A different material_id seals the previous segment. Ignore delayed refinements for an older activity after that boundary.

Therefore A(activity-1) -> A'(activity-1, marker) -> A(activity-1, marker miss) is one row, while A(activity-1) -> B(activity-2) -> delayed A'(activity-1) keeps B current and does not rewrite the historical A.

Stop recognition

Stop recognition when your app no longer needs microphone capture.

swift
recognizer.stopRecognition()

Background recognition

If your app needs background recognition, add audio to UIBackgroundModes in Info.plist. Background recognition works while the app is running. If the app is terminated, recognition also stops.

Error handling

Recognition errors are delivered through the recognition handler and SORI error notifications. To observe error notifications, register for SORIError.errorNotificationName():

swift
NotificationCenter.default.addObserver(forName: SORIError.errorNotificationName(), object: nil, queue: OperationQueue.main) { notification in
    guard let error = notification.object as? NSError,
          let code = SORIErrorCode(rawValue: error.code) else {
        print("Unknown error notification: \(notification)")
        return
    }

    if code == .authenticationFailure {
        print("Failed to authenticate")
    }
}