API Reference
Events
Event types — BioEvent, lifecycle events, session events, connection states, and stream states.
The SDK communicates state changes through a Combine-based event system. Subscribe to sdk.events to receive all events.
sdk.events.sink { event in
switch event {
case .lifecycle(let e): handleLifecycle(e)
case .sample(let deviceId, let sample): handleSample(deviceId, sample)
case .deviceState(let device, let conn, let stream): handleState(device, conn, stream)
case .session(let e): handleSession(e)
case .notification(let e): handleNotification(e)
}
}BioEvent
Top-level event enum emitted by BioSDKClient.events.
public enum BioEvent: Equatable {
case lifecycle(BioLifecycleEvent)
case sample(deviceId: String, BioSample)
case deviceState(device: BioDevice, connection: BioConnectionState, stream: BioStreamState)
case session(BioSessionEvent)
case notification(BioNotificationEvent)
}| Case | Description |
|---|---|
.lifecycle(...) | Device discovered, connected, or disconnected |
.sample(deviceId:, ...) | Biosignal sample received from a device |
.deviceState(...) | Connection or streaming state changed |
.session(...) | Backend session lifecycle event |
.notification(...) | Push notification event |
BioLifecycleEvent
Device discovery and connection lifecycle events.
public enum BioLifecycleEvent: Equatable {
case discovered(BioDevice)
case connected(BioDevice)
case disconnected(BioDevice, errorMessage: String?, errorCode: Int?, errorDomain: String?)
}| Case | Description |
|---|---|
.discovered(device) | A new device was found during scanning |
.connected(device) | Device successfully connected |
.disconnected(device, ...) | Device disconnected (with optional error details) |
Example:
sdk.events
.compactMap { event -> BioDevice? in
guard case .lifecycle(.connected(let device)) = event else { return nil }
return device
}
.sink { device in
print("Connected to \(device.name)")
}BioSessionEvent
Backend session lifecycle events.
public enum BioSessionEvent: Equatable {
case started(id: String, devices: [SessionDevice])
case resumed(id: String, devices: [SessionDevice])
case conflict(activeId: String, startedAt: Date?)
case ended(id: String, ok: Bool)
case endFailed(id: String, status: Int?)
case recoveryAvailable(info: OrphanedSessionInfo)
case forbidden
case serverError(status: Int)
case error(message: String)
}| Case | Description |
|---|---|
.started(id:, devices:) | New session created on the backend |
.resumed(id:, devices:) | Existing session resumed |
.conflict(activeId:, startedAt:) | HTTP 409 — another session is active |
.ended(id:, ok:) | Session ended (ok indicates clean shutdown) |
.endFailed(id:, status:) | Session end request failed |
.recoveryAvailable(info:) | An orphaned session from a previous launch was detected |
.forbidden | Authentication/authorization failure (HTTP 403) |
.serverError(status:) | Backend returned a server error |
.error(message:) | General session error |
SessionDevice
Device info returned when a session starts or resumes.
public struct SessionDevice: Equatable, Codable {
public let ingest_device_id: String
public let device_id: String
public let device_profile_id: String?
public let make: String?
public let model: String?
}OrphanedSessionInfo
Information about a session that was left active from a previous app launch.
public struct OrphanedSessionInfo: Equatable, Sendable {
public let sessionId: String
public let startedAt: Date
public let deviceCount: Int
public let totalChunks: Int
}BioNotificationEvent
Events from the notification system.
public enum BioNotificationEvent: Equatable {
case received(BioNotification)
case acknowledged(notificationId: String)
case dismissed(notificationId: String)
case connectionStateChanged(NotificationConnectionState)
}See the Notifications API reference for BioNotification and NotificationConnectionState.
BioConnectionState
Connection state for a device.
public enum BioConnectionState: String, Equatable, Codable {
case discovered
case connecting
case discoveringServices
case ready
case disconnected
case failed
}State Flow
discovered → connecting → discoveringServices → ready
→ failed
→ disconnected| State | Description |
|---|---|
.discovered | Device found during scan, not yet connected |
.connecting | Connection in progress |
.discoveringServices | Connected, discovering GATT services |
.ready | Fully connected with services discovered |
.disconnected | Device disconnected |
.failed | Connection attempt failed |
BioStreamState
Streaming state for a device.
public enum BioStreamState: String, Equatable, Codable {
case idle
case starting
case streaming
case stopping
case stalled
case unsupported
}State Flow
idle → starting → streaming → stopping → idle
→ stalled
→ unsupported| State | Description |
|---|---|
.idle | Not streaming |
.starting | Stream start command sent, waiting for data |
.streaming | Actively receiving biosignal data |
.stopping | Stream stop command sent |
.stalled | Stream started but no data received (timeout) |
.unsupported | Device does not support streaming |
Subscribing to Events
Filter by Event Type
// Only session events
let sessionEvents = sdk.events
.compactMap { event -> BioSessionEvent? in
guard case .session(let e) = event else { return nil }
return e
}
// Only samples from a specific device
let deviceSamples = sdk.events
.compactMap { event -> BioSample? in
guard case .sample(let id, let sample) = event,
id == myDeviceId else { return nil }
return sample
}Observe Device State Changes
sdk.events
.compactMap { event -> (BioDevice, BioConnectionState, BioStreamState)? in
guard case .deviceState(let device, let conn, let stream) = event
else { return nil }
return (device, conn, stream)
}
.sink { device, connection, stream in
print("\(device.name): \(connection) / \(stream)")
}