AI Recording (TSAudioRecordInterface)
The recording contract includes normal device recording and AI recording. AI recording may be app-initiated or device-initiated and returns transcripts, events, runtime errors, and a final report through one provider-neutral model.
Interface and feature query
TSAIContext *context = [TSAIKit sharedInstance].activeContext;
id<TSAudioRecordInterface> audioRecord = context.audioRecord;
| Scenario | Feature |
|---|---|
| Normal recording | TSAIFeatureNormalAudioRecording |
| On-site AI recording | TSAIFeatureAIAudioRecording |
| Call AI recording | TSAIFeatureCallAudioRecording |
Data models
TSAIAudioRecordConfig
| Property | Type | Description |
|---|---|---|
audioRouteConfiguration | TSAIAudioRouteConfiguration * | Input route; output must be None; nil requests automatic routing |
recordingScene | TSAIAudioRecordScene | On-site or call recording |
language | TSAILanguage | Input language; Unknown uses the current app language |
allowRecordingWhileOffline | BOOL | Allow supported providers to record offline and sync later |
enableSpeakerDiarization | BOOL | Enable speaker diarization |
defaultConfig uses on-site recording and disables offline recording and diarization.
TSAIAudioRecordSessionResult
type | Valid fields | Description |
|---|---|---|
Transcript | text, sentenceIndex, isSentenceFinal, speakerSegments | Streaming transcript |
Event | eventType, timestamp, evidence, details | Session event |
Error | error | Runtime error |
Finish | transcripts, sessionEvents, rawAudioFilePath | Final session report |
The final report also exposes isStoppedByInterruption, isOfflineRecording, and hadNetworkDisconnection.
Transcript results also expose languageCode, sequence, and requestId; event results expose timeSinceSessionStart. A TSAIAudioRecordSpeakerSegment contains speakerId, startTimeMilliseconds, endTimeMilliseconds, associatedTranscriptSequence, and text.
Normal recording
- (void)setNormalAudioRecordingMaximumDuration:(NSUInteger)maximumDuration
completion:(TSAICompletionBlock)completion;
- (void)getNormalAudioRecordingMaximumDuration:(nullable TSAudioRecordMaximumDurationResultBlock)completion;
- (void)startNormalAudioRecording:(TSAICompletionBlock)startCompletion
finishHandler:(nullable TSAudioRecordFinishHandler)finishHandler;
- (void)stopNormalAudioRecording:(TSAICompletionBlock)completion;
Maximum duration is in minutes and must be from 1 through 240.
[audioRecord startNormalAudioRecording:^(BOOL success, NSError *error) {
if (!success) {
TSLog(@"Normal recording failed to start: %@", error.localizedDescription);
}
} finishHandler:^(TSAudioRecordStopReason reason, NSError *error) {
TSLog(@"Normal recording ended: %lu", (unsigned long)reason);
}];
AI recording
- (void)startAIAudioRecordingWithConfig:(nullable TSAIAudioRecordConfig *)config
startCompletion:(TSAICompletionBlock)startCompletion
didReceiveAudioData:(nullable TSAudioRecordDataReceivedBlock)didReceiveAudioData
didReceiveSessionResult:(nullable TSAIAudioRecordSessionResultHandler)didReceiveSessionResult
finishHandler:(nullable TSAudioRecordFinishHandler)finishHandler;
- (void)stopAIAudioRecording:(TSAICompletionBlock)completion;
TSAIAudioRecordConfig *config = [TSAIAudioRecordConfig defaultConfig];
config.language = TSAILanguageEnglishUS;
config.enableSpeakerDiarization = YES;
[audioRecord startAIAudioRecordingWithConfig:config
startCompletion:^(BOOL success, NSError *error) {
if (!success) {
TSLog(@"AI recording failed to start: %@", error.localizedDescription);
}
}
didReceiveAudioData:^(NSData *audioData) {
// Avoid blocking I/O in this high-frequency callback.
}
didReceiveSessionResult:^(TSAIAudioRecordSessionResult *result) {
if (result.type == TSAIAudioRecordSessionResultTypeTranscript) {
TSLog(@"Transcript: %@", result.text);
} else if (result.type == TSAIAudioRecordSessionResultTypeFinish) {
TSLog(@"Session complete: %@", result.transcripts);
}
}
finishHandler:^(TSAudioRecordStopReason reason, NSError *error) {
TSLog(@"Audio stream ended: %lu", (unsigned long)reason);
}];
finishHandler means only that the underlying audio stream ended. The semantic AI session ends when didReceiveSessionResult receives a Finish result.
Device-initiated recording
- (void)registerOnRequestStartAIAudioRecording:(nullable TSAIAudioRecordRequestStartBlock)block;
- (void)registerOnRequestStopAIAudioRecording:(nullable dispatch_block_t)block;
- (void)registerAIAudioRecordingDidInterrupt:(nullable TSAIAudioRecordInterruptBlock)block;
- (void)registerOnAIAudioRecordingVoiceDataReceived:(nullable TSAudioRecordVoiceDataReceivedBlock)block;
- (void)registerAIAudioRecordingStateDidChanged:(nullable TSAIAudioRecordStateBlock)block;
[audioRecord registerOnRequestStartAIAudioRecording:^(TSAIAudioRecordScene scene) {
TSAIAudioRecordConfig *config = [TSAIAudioRecordConfig defaultConfig];
config.recordingScene = scene;
// Eligibility already passed. Prepare locally but do not open UI yet.
}];
[audioRecord registerOnRequestStopAIAudioRecording:^{
[audioRecord stopAIAudioRecording:^(BOOL success, NSError *error) {
TSLog(@"Device stop request: %@", success ? @"handled" : error.localizedDescription);
}];
}];
The start callback runs only after exact eligibility passes. Prepare locally with startAIAudioRecordingWithConfig:... and open the recording UI only after startCompletion succeeds, when both app and device are active.
Report a real state transition to the device with:
- (void)reportAIAudioRecordingStartSuccessWithScene:(TSAIAudioRecordScene)scene
completion:(nullable TSAICompletionBlock)completion;
- (void)reportAIAudioRecordingStoppedWithCompletion:(nullable TSAICompletionBlock)completion;
Do not report success before the recording has actually started or stopped.
Key enums
TSAIAudioRecordScene | Description |
|---|---|
Unknown | Unknown scene |
OnSite | On-site recording |
Call | Call recording |
TSAIAudioRecordState | Description |
|---|---|
Unknown | Unknown state |
Idle | Idle |
Starting | Starting |
Recording | Recording |
Stopping | Stopping |
Interrupted | Interrupted |
TSAIAudioRecordInterruptReason | Description |
|---|---|
Unknown | Unknown reason |
LowBattery | Device battery is low |
IncomingCall | Incoming call interruption |
Other | Other interruption |
Stop reasons and session-result types
| Enum | Values and raw values |
|---|---|
TSAudioRecordStopReason | Unknown = 0, UserInitiated = 1, MaxDurationReached = 2, DeviceError = 3, StorageFull = 4, Disconnected = 5, Interrupted = 6 |
TSAIAudioRecordSessionResultType | Transcript = 0, Event = 1, Error = 2, Finish = 3 |
Add the corresponding enum prefix to shortened values, for example TSAudioRecordStopReasonUserInitiated.
Important notes
- Obtain explicit user consent and show a clear recording indicator.
- Recording input language does not accept
TSAILanguageAuto. - Avoid expensive work in audio, transcript, and event callbacks.
- Unregister all device-request, data, interruption, and state listeners when leaving the feature.
- Offline recording works only when both the provider and the configuration allow it.