Skip to content

Instantly share code, notes, and snippets.

View samsonjs's full-sized avatar

Sami Samhuri samsonjs

View GitHub Profile
@samsonjs
samsonjs / SampleWriter.swift
Created July 11, 2024 06:27
Task cancellation in a dispatch queue world of AVAssetWriterInputs
actor SampleWriter {
// ...
var isCancelled = false
// ...
func cancel() async {
isCancelled = true
}
private func encodeAudioTracks() async {
@samsonjs
samsonjs / ExportSession.swift
Created July 8, 2024 15:54
Attempting to send non-Sendable AVFoundation types in a safe way
public import AVFoundation
struct UniqueRef<Value>: ~Copyable, @unchecked Sendable {
private let lock = NSLock()
private var unsafeValue: Value?
init(value: sending Value) {
self.unsafeValue = value
}
@samsonjs
samsonjs / ContentView.swift
Created July 2, 2024 21:22
How to fix a Swift 6 warning: "Sending main actor-isolated value of type 'WebAuthenticationSession' with later accesses to nonisolated context risks causing data races; this is an error in the Swift 6 language mode"
// https://iosdev.space/@andy/112714337582288785
import AuthenticationServices
import SwiftUI
struct ContentView: View {
@State var url = URL(string: "https://example.net")!
@Environment(\.webAuthenticationSession) var webAuthenticationSession
@samsonjs
samsonjs / VFAExportSession.swift
Last active June 29, 2024 05:10
Exploring possible modern APIs for something like AVAssetExportSession
// Old way
let session = VFAExportSession(asset: asset)
session.timeRange = CMTimeRange(start: .seconds(1), duration: .seconds(3))
session.audioMix = audioMix
session.audioOutputConfiguration = [
AVFormatIDKey: kAudioFormatMPEG4AAC,
AVNumberOfChannelsKey: NSNumber(value: 2),
AVSampleRateKey: NSNumber(value: 44_100.0),
]
session.videoComposition = videoComposition
@samsonjs
samsonjs / SendableWrapper.swift
Last active July 9, 2024 03:23
Exporting videos with AVFoundation in the strict concurrency world of Swift 6
//
// Created by Sami Samhuri on 2024-06-26.
//
import Foundation
final class SendableWrapper<T>: @unchecked Sendable {
private var unsafeValue: T
private let lock = NSLock()
@samsonjs
samsonjs / Tracks.swift
Last active June 24, 2024 15:20
FB14035001: Tracks loaded from an AVAsset should be marked `sending` to be used from actor-isolated contexts
import AVFoundation
/*
* In Swift 6 it’s not currently possible to directly load tracks from an AVAsset using a method like
* AVAsset.loadTracks(withMediaType:) from an actor-isolated context, because AVAssetTrack isn’t Sendable. Given
* that many AVFoundation types are not sendable / thread-safe it’s tempting to use an actor to work with
* compositions and that currently requires some work-arounds that shouldn’t be necessary and may not be obvious
* to everyone.
*/
@samsonjs
samsonjs / SendableWrapper.swift
Last active June 22, 2024 16:46
SyncState isolation example
final class SendableWrapper<T>: @unchecked Sendable {
private var unsafeValue: T
private let lock = NSLock()
var value: T {
get {
lock.withLock { unsafeValue }
}
set {
@samsonjs
samsonjs / MovieExporter.swift
Created June 21, 2024 15:15
AVAssetExportSession safety when using structured concurrency in Swift 5 and 6
import AVFoundation
/**
* AVAssetExportSession is initialized with an AVComposition, and that composition and all of its constituent
* components are not sendable. Because `composition` is isolated to the main actor here, the call to the
* non-isolated method `export(to:as:)` sends it across an isolation region and that is unsafe.
*/
@MainActor
class UnsafeMovieExporter {
let composition = AVMutableComposition()
@samsonjs
samsonjs / MovieExportSession.swift
Created June 21, 2024 05:39
Weird AVAssetExportSession sendable error in Swift 6
import AVFoundation
import Combine
import OSLog
private let log = Logger.forType(MovieExportSession.self)
actor MovieExportSession {
let composition: AVComposition
let audioMix: AVAudioMix?
@samsonjs
samsonjs / honeybadger_logger.rb
Last active June 11, 2024 16:45
Honeybadger logger for Ruby on Rails
require 'json'
require 'logger'
require 'net/http'
require 'stringio'
require 'zlib'
module Pronto
# Logs messages to Honeybadger's events API (Insights). The logger buffers messages and sends
# them to the API in batches. The logs are currently not structured and are sent as plain text,
# but if/when we actually move off of Papertrail then we can consider sending structured logs as