Skip to content

Not recording when session readyState is closed (i.e. disconnected from server) #1820

@mkrn

Description

@mkrn

Observed behavior

When server drops connection (or disconnected for whatever reason) recording stops with following errors:
StreamRecorder error: Failed to append sample buffer - The operation could not be completed
StreamRecorder error: Failed to append sample buffer - The operation could not be completed
repeated
(infinite)

code to start recording and catches this error:

    func startRecording() {

 
        Task {

            let recorder = StreamRecorder()

            // Enable movie fragment interval for crash-safe recording
            // This ensures the file will be recoverable even if the app crashes
            await recorder.setMovieFragmentInterval(10.0)

            // Monitor recorder errors in a separate task
            Task {
                for await error in await recorder.error {
                    await MainActor.run {
                        // Log all error types comprehensively
                        switch error {
                        case .invalidState:
                            self.error = error
                            self.delegate?.recordingErrorOccured(error: error)

                        case .fileAlreadyExists(let outputURL):
                            self.error = error
                            self.delegate?.recordingErrorOccured(error: error)

                        case .notSupportedFileType(let pathExtension):
                            self.error = error
                            self.delegate?.recordingErrorOccured(error: error)

                        case .failedToCreateAssetWriter(let underlyingError):
                            self.error = underlyingError
                            self.delegate?.recordingErrorOccured(error: underlyingError)

                        case .failedToCreateAssetWriterInput(let underlyingError):
                            self.error = underlyingError
                            self.delegate?.recordingErrorOccured(error: underlyingError)

                        case .failedToAppend(let underlyingError):
                            if let underlyingError {
                                self.error = underlyingError
                                self.delegate?.recordingErrorOccured(error: underlyingError)
                            } else {
                                self.error = error
                                self.delegate?.recordingErrorOccured(error: error)
                            }

                        case .failedToFinishWriting(let underlyingError):
                            if let underlyingError {
                                self.error = underlyingError
                                self.delegate?.recordingErrorOccured(error: underlyingError)
                            } else {
                                self.error = error
                                self.delegate?.recordingErrorOccured(error: error)
                            }
                        }
                    }
                }
            }

            await mixer.addOutput(recorder)

            do {
                // When starting a recording while connected to Xcode, it freezes for about 30 seconds. iOS26 + Xcode26.
                try await recorder.startRecording()

                await MainActor.run {
                    self.recorder = recorder
                    recording = true
                }
            } catch {
                await MainActor.run {
                    self.error = error
                    self.delegate?.recordingErrorOccured(error: error)
                }
            }

        }

    }

Code that builds session:

func makeSession() async {

do {
            let builder = try await SessionBuilderFactory.shared.make(url) 
 
            let builderWithMode = builder.setMode(.publish) 

            LogManager.info("Building session...")
            session = try await builderWithMode.build() 
 

            await mixer.addOutput(session.stream)

            tasks.append(Task {
                for await readyState in await session.readyState {
                    await MainActor.run {
                        self.readyState = readyState

                        // Update status based on readyState
                        switch readyState {
                        case .closed:
                            LogManager.info("Session state: CLOSED")
                            self.status = .ready
                            UIApplication.shared.isIdleTimerDisabled = false

Code to start publishing:

    func startPublishing() {
        Task {

            do {

                await MainActor.run {
                    self.published = true
                }
                self.startRecording()
               try await session.connect {
                    Task { @MainActor in
                        LogManager.info("Start Publishing Connected")
                        self.isShowError = true
                    }
                }

Code to start recording:

Expected behavior

Recording to continue normally even if the stream disconnected

To Reproduce

Try to build a session,
start publish and start record at the same time
disconnect RTMP

Version

2.2 main branch

Smartphone info.

iPhone 13 pro

Additional context

No response

Screenshots

No response

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions