### Development Setup Script Source: https://github.com/harflabs/swiftvlc/blob/main/README.md Clone the repository, navigate to the project directory, and run the setup script to prepare the development environment. This script downloads necessary binaries and configures local package references for development. ```bash git clone https://github.com/harflabs/SwiftVLC.git cd SwiftVLC ./scripts/setup-dev.sh ``` -------------------------------- ### Install Build Dependencies and Build libVLC Source: https://github.com/harflabs/swiftvlc/blob/main/README.md Installs required build tools using Homebrew and then executes the script to build all libVLC components for all supported platforms. This process can take a significant amount of time. ```bash brew install autoconf automake libtool cmake pkg-config gettext ./scripts/build-libvlc.sh --all ``` -------------------------------- ### Integration Test Example Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md An example of an integration test using SwiftVLC's Player API. This test requires a `VLCInstance` and uses bundled fixture files. ```swift @Test(.tags(.integration, .media, .async)) func playAndWaitForState() async throws { let player = Player() try player.play(url: TestMedia.videoURL) // Wait for state change... } ``` -------------------------------- ### Configure Media Playback Options Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md Add playback options to a media object using colon-prefixed strings. These options affect media that has not yet started playing. Examples include network caching and start time. ```swift media.addOption(":network-caching=1500") ``` ```swift media.addOption(":start-time=30") ``` -------------------------------- ### Instantiate and Use PiPController Directly Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md Demonstrates how to manually instantiate PiPController, add its layer to a container, and start the PiP session. Use this when custom view hierarchies or layout control is needed. ```swift let controller = PiPController(player: player) container.layer.addSublayer(controller.layer) controller.start() ``` -------------------------------- ### Prewarm libVLC Instance at App Launch Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md Prewarm the shared libVLC instance during app initialization to perform one-time setup, avoiding delays during the first playback. ```swift import SwiftUI import SwiftVLC @main struct MyApp: App { init() { VLCInstance.prewarmShared() } var body: some Scene { WindowGroup { PlayerView() } } } ``` -------------------------------- ### SwiftVLC Quick Start Player View Source: https://github.com/harflabs/swiftvlc/blob/main/README.md A basic SwiftUI View that uses SwiftVLC to play a video from a URL. Ensure the URL is a direct media stream or file URL. ```swift import SwiftUI import SwiftVLC struct PlayerView: View { @State private var player = Player() var body: some View { VideoView(player) .onAppear { try? player.play(url: URL(string: "https://example.com/video.mp4")!) } } } ``` -------------------------------- ### VideoView Rendering with libVLC Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Illustrates the interaction between SwiftUI, VideoView, VideoSurface, and libVLC for video rendering. libVLC handles all rendering internally without requiring CALayer or AVPlayerLayer setup. ```mermaid sequenceDiagram participant SwiftUI participant VideoView participant VideoSurface as VideoSurface
(UIView / NSView) participant libVLC SwiftUI->>VideoView: makeUIView / makeNSView VideoView->>VideoSurface: create VideoSurface->>libVLC: set_nsobject(view pointer) libVLC->>VideoSurface: adds rendering sublayer loop On resize VideoSurface->>VideoSurface: layoutSubviews() — sync sublayer frames end SwiftUI->>VideoView: dismantleUIView VideoSurface->>libVLC: set_nsobject(nil) ``` -------------------------------- ### Cast Media to a Renderer Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md Discover renderer devices on the network and cast media to them. This involves starting a RendererDiscoverer and reacting to events for when renderers are added or removed. A new Player instance is recommended for casting. ```swift let services = RendererDiscoverer.availableServices() guard let service = services.first else { return } var player = Player() let discoverer = try RendererDiscoverer(name: service.name) try discoverer.start() for await event in discoverer.events { switch event { case .itemAdded(let renderer): print("Found", renderer.name, renderer.type) let castPlayer = Player() do { try castPlayer.setRenderer(renderer) try castPlayer.play(url: mediaURL) player.stop() player = castPlayer } catch { print("Cast failed:", error) } case .itemDeleted(let renderer): print("Lost", renderer.name) } } ``` -------------------------------- ### Multiple Consumers for Log Streams Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/Logging.md Demonstrates how multiple tasks can independently subscribe to the log stream with different minimum severity levels. The underlying libVLC callback is installed lazily and removed when all consumers terminate. ```swift Task { for await e in instance.logStream(minimumLevel: .error) { diagnostics.record(e) }} ``` ```swift Task { for await e in instance.logStream(minimumLevel: .debug) { devConsole.append(e) }} ``` -------------------------------- ### Discover Local Media Sources Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md Use MediaDiscoverer to find available media services on the local network, such as UPnP or SMB. Start a discoverer for a specific service and retrieve a list of media items. ```swift let services = MediaDiscoverer.availableServices(category: .lan) guard let upnp = services.first(where: { $0.name == "upnp" }) else { return } let discoverer = try MediaDiscoverer(name: upnp.name) try discoverer.start() try? await Task.sleep(for: .seconds(2)) if let list = discoverer.mediaList { for i in 0.. XCF["Vendor/libvlc.xcframework
(unstripped)"] XCF --> RELEASE["release.sh vX.Y.Z"] RELEASE --> VERIFY["Verify all required slices present"] VERIFY --> STRIP["strip -S"] STRIP --> ZIP["ditto -c -k"] ZIP --> SUM["swift package compute-checksum"] SUM --> COMMIT["Commit on main:
Package.swift → url+checksum
Showcase → exactVersion X.Y.Z"] COMMIT --> TAG["git tag vX.Y.Z"] TAG --> PUSH_TAG["git push origin vX.Y.Z"] PUSH_TAG --> GH["gh release create
+ attached .zip"] GH --> PUSH_MAIN["git push origin HEAD:main"] PUSH_MAIN --> SPM["main and consumers resolve the same release"] ``` -------------------------------- ### Build a Media List Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md Create a MediaList and append or insert Media items. MediaList is thread-safe. ```swift let list = MediaList() try list.append(Media(url: url1)) try list.append(Media(url: url2)) try list.insert(Media(url: url3), at: 1) ``` -------------------------------- ### SwiftVLC Test Directory Structure Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Illustrates the organization of test files and fixtures within the SwiftVLC project. ```tree Tests/SwiftVLCTests/ ├── Support/ │ ├── TestMedia.swift # Fixture URLs (bundled resources) │ └── Tag.swift # Test tag definitions ├── Fixtures/ │ ├── test.mp4 # 1s, 64x64, with metadata │ ├── twosec.mp4 # 2s, for seeking tests │ ├── silence.wav # Audio-only │ └── test.srt # Subtitle file └── … # One test suite per domain area ``` -------------------------------- ### Perform a dry run of the release script Source: https://github.com/harflabs/swiftvlc/blob/main/README.md Simulates the release process by stripping debug symbols, zipping the framework, and computing checksums, without actually pushing any changes. ```bash ./scripts/release.sh X.Y.Z --dry-run # strip + zip + checksum, no push ``` -------------------------------- ### Verification Script for Dynamic Host Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/IntegrationTopology.md This script builds and audits the dynamic host fixture to verify the single-copy libVLC runtime. It checks the 'nm' output for '_libvlc_new' symbol definition count and optionally launches the iOS app in a simulator. ```sh Fixtures/DynamicHost/verify.sh # build + single-copy audit ``` ```sh Fixtures/DynamicHost/verify.sh --launch # additionally run the iOS app # in a simulator (local only) ``` -------------------------------- ### Basic Video Playback in SwiftUI Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/SwiftVLC.md This snippet demonstrates how to initialize a Player and play a video URL within a SwiftUI View. It utilizes the @State property wrapper for player management and the .task modifier for asynchronous playback initiation. ```swift import SwiftUI import SwiftVLC struct ContentView: View { @State private var player = Player() var body: some View { VideoView(player) .task { try? player.play(url: videoURL) } } } ``` -------------------------------- ### Initialize Player Instance Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md Declare a Player instance using @State for use within SwiftUI views. This initializes the underlying libVLC resources. ```swift @State private var player = Player() ``` -------------------------------- ### Package.swift Local Binary Target Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Defines the libvlc binary target for local development, pointing to an on-disk xcframework. ```swift .binaryTarget(name: "libvlc", path: "Vendor/libvlc.xcframework") ``` -------------------------------- ### Configure HTTP Request Options Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md Set HTTP-specific request options for streams, such as user-agent and referrer, using the addOption method. These options are applied to HTTP and HTTPS streams. ```swift media.addOption(":http-user-agent=CustomApp/1.0") ``` ```swift media.addOption(":http-referrer=https://example.com") ``` -------------------------------- ### Best-Effort Seeks Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md For live, timeshift, or unknown-duration media, use these best-effort seek methods that do not throw errors. ```swift player.seek(toPosition: 0.95, fast: true) // raw fractional seek player.jump(by: .seconds(-10)) // native relative jump ``` -------------------------------- ### Exhaustive Error Handling with Pattern Matching Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/HandlingErrors.md Demonstrates how to use a do-catch block with pattern matching to handle all possible VLCError cases. This ensures that no error goes unhandled. ```swift do { try player.play(url: url) } catch .instanceCreationFailed { print("libVLC could not be initialized") } catch .mediaCreationFailed(let source) { print("Couldn't build media for: \(source)") } catch .playbackFailed(let reason) { print("Playback refused: \(reason)") } catch .parseFailed(let reason) { print("Parsing failed: \(reason)") } catch .parseTimeout { print("Parsing timed out") } catch .trackNotFound(let id) { print("No track matched: \(id)") } catch .invalidState(let message) { print("Player wasn't ready: \(message)") } catch .invalidInput(let message) { print("Bad argument: \(message)") } catch .operationFailed(let op) { print("libVLC call failed: \(op)") } ``` -------------------------------- ### Media Parsing Flow Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Illustrates the asynchronous parsing flow for media, including cancellation, timeout, and success scenarios. This sequence diagram outlines the interaction between the App, Media, and libVLC components. ```mermaid sequenceDiagram participant App participant Media participant libVLC App->>Media: parse(timeout:) async throws Media->>libVLC: libvlc_media_parse_request() libVLC-->>Media: MediaParsedChanged event alt Task cancelled Media->>libVLC: libvlc_media_parse_stop() else Timeout exceeded Media-->>App: throws .parseTimeout else Success Media-->>App: returns Metadata end ``` -------------------------------- ### Audio Volume Scale Conversion Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Demonstrates the conversion between VLCKit's 0-200 integer volume scale and SwiftVLC's 0.0-2.0 float scale. ```swift // VLCKit player.audio.volume = 150 ``` ```swift // SwiftVLC try player.setAudioVolume(Volume(1.5)) ``` -------------------------------- ### Stop and Wait for Player Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Use `stopAndWait()` to ensure the native stop operation completes before proceeding. This prevents common porting bugs related to deactivating audio sessions too early. ```swift await player.stopAndWait() try AVAudioSession.sharedInstance() .setActive(false, options: .notifyOthersOnDeactivation) ``` -------------------------------- ### Configure Audio Session for PiP Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md Sets the audio session category to .playback and mode to .moviePlayback, then activates the session. This is required for PiP functionality on iOS. ```swift try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback) try? AVAudioSession.sharedInstance().setActive(true) ``` -------------------------------- ### Parse Media Metadata Up Front Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Parse media metadata and track information once before playback begins. This operation is asynchronous and honors task cancellation. ```swift let media = try Media(url: url) let metadata = try await media.parse() try player.play(media) ``` -------------------------------- ### Playing Media on the Main Actor Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md Construct a Media object on any actor and then play it on the main actor. Ownership of the Media object is transferred to the player upon calling play. ```swift let media = try Media(url: url) // any actor await MainActor.run { try? player.play(media) // main actor; ownership transfers } ``` -------------------------------- ### SwiftVLC @Observable and SwiftUI Integration Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ComparisonWithVLCKit.md Demonstrates SwiftVLC's integration with SwiftUI using the @Observable macro for state management and a direct Swift API for playback. This approach avoids Objective-C bridging. ```swift // SwiftVLC: @Observable plus SwiftUI struct PlayerView: View { @State var player = Player() var body: some View { VideoView(player) .task { try? player.play(url: url) } } } ``` -------------------------------- ### Play a Media List Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md Attach a MediaListPlayer to an existing Player and set the MediaList. Playback can be looped or default. ```swift let listPlayer = MediaListPlayer() listPlayer.mediaPlayer = player listPlayer.mediaList = list listPlayer.playbackMode = .loop listPlayer.play() ``` -------------------------------- ### Set Audio Role Hint Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md Provide a hint to libVLC about the intended role of the audio playback, such as music or communication calls. The actual effect of this hint depends on the platform and the active audio output module. ```swift player.role = .music // long-form listening player.role = .communication // voice/video calls ``` -------------------------------- ### Configure Video Adjustments Overlay Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md Enables and adjusts video properties such as contrast, brightness, and saturation in real time. These adjustments are applied to the video feed. ```swift player.withAdjustments { $0.isEnabled = true $0.contrast = 1.1 $0.brightness = 1.05 $0.saturation = 1.2 } ``` -------------------------------- ### Project Structure Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Hierarchical view of the SwiftVLC project directory, detailing the organization of source code, tests, showcase applications, vendor libraries, scripts, and configuration files. ```tree SwiftVLC/ ├── Sources/ │ ├── CLibVLC/ # C bridging layer │ │ ├── include/vlc/ # libVLC 4.0 C headers │ │ └── shim.c # va_list formatting shim │ │ │ └── SwiftVLC/ # Main library │ ├── Core/ # VLCInstance, VLCError, Logging, Duration │ ├── Player/ # Player, EventBridge, PlayerState, Events, ABLoop, etc. │ ├── Media/ # Media, Metadata, Track, Thumbnails, Statistics │ ├── Audio/ # AudioOutput, Equalizer, ChannelModes │ ├── Video/ # VideoView, AspectRatio, Adjustments, Marquee, Logo, Viewpoint │ ├── Playlist/ # MediaList, MediaListPlayer, PlaybackMode │ ├── Discovery/ # MediaDiscoverer, RendererDiscoverer │ └── PiP/ # PiPController, PiPVideoView, PixelBufferRenderer │ ├── Tests/SwiftVLCTests/ # Swift Testing suite, one file per domain │ ├── Support/ # TestMedia fixtures, Tag definitions │ └── Fixtures/ # Bundled media files (~50 KB) │ ├── Showcase/ # Platform showcase apps │ ├── Shared/ # Launch-arg/accessibility contracts, app icon, and shared showcase resources │ ├── iOS/ # Full-featured iOS target/scheme, also enabled for Mac Catalyst │ ├── macOS/ # Native macOS target/scheme with Mac-tailored showcases │ ├── tvOS/ # Native tvOS target/scheme with TV-tailored showcases │ ├── visionOS/ # Native visionOS target/scheme with focused playback coverage │ └── UITests/ │ ├── iOS/ # UI tests for the iOS/Catalyst showcase │ ├── macOS/ # Native macOS UI tests │ └── tvOS/ # Empty tvOS UI-test target shell │ ├── Vendor/ # libvlc.xcframework (multi-GB unstripped; release zip a few hundred MB) │ ├── scripts/ │ ├── build-libvlc.sh # Compile libvlc from source │ ├── setup-dev.sh # Download xcframework for local dev │ ├── release.sh # Cut a versioned release and advance main │ ├── fix-duplicate-symbols.sh # Localize duplicate json symbols │ ├── ci-use-released-xcframework.sh # CI: point Package.swift at latest release │ └── ci-run-with-timeouts.py # CI: wall-clock + idle test timeouts │ ├── .github/workflows/ │ ├── test.yml # CI test runner │ ├── sanitize.yml # Sanitizer test runner │ └── claude.yml # Claude Code bot integration │ ├── Package.swift # SPM manifest (Swift 6.3+) ├── .swiftlint.yml # Lint configuration ├── .swiftformat # Format: 2-space indent └── README.md # User guide ``` -------------------------------- ### Seeking Media Position in SwiftVLC Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Use `Player/seek(to:)` for precise seeking or `Player/seek(toPosition:fast:)` for a more lenient approach when migrating from VLCKit's `player.position = x`. ```swift Player/seek(to:)-(PlaybackPosition) ``` ```swift Player/seek(toPosition:fast:) ``` -------------------------------- ### Logo (image overlay) Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md Adds an image logo overlay to the video. Supports static PNGs or animated sequences. Allows configuration of opacity and screen position. ```APIDOC ## Logo (image overlay) ``Logo`` layers a PNG (or a sequence of PNGs for animation) on top of the video: ```swift player.withLogo { logo in logo.isEnabled = true logo.setFile("/tmp/logo.png") logo.opacity = 200 // 0–255 logo.screenPosition = .topRight } ``` For an animated sequence, pass "file,delay,transparency;…" to ``Logo/setFile(_:)``. ``` -------------------------------- ### Set Stereo Mode and Mix Mode Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md Configure the stereo transformation mode (e.g., mono, reversed) and the channel count of the final audio mix, including options like stereo, 5.1, 7.1, and binaural rendering for headphones. ```swift player.stereoMode = .mono // collapse to mono player.mixMode = .binaural // spatialize for headphones ``` -------------------------------- ### Marquee (text overlay) Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md Configures a text marquee overlay on the video. Supports strftime-style placeholders and allows customization of refresh interval, font size, color, and screen position. ```APIDOC ## Marquee (text overlay) ``Marquee`` displays a text string on top of the video. It supports strftime-style placeholders refreshed at the interval configured by ``Marquee/refresh``: ```swift player.withMarquee { m in m.isEnabled = true m.setText("%H:%M:%S") m.refresh = 1000 // refresh every second m.fontSize = 24 m.color = 0xFFFFFF m.screenPosition = .bottomLeft } ``` Anchoring uses ``OverlayPosition``, an `OptionSet` whose flags compose into corners (`.topLeft`, `.bottomRight`, …) or an empty set for the center. The raw ``Marquee/position`` `Int` bitmask remains available for libVLC-flavored code. ``` -------------------------------- ### Multiplexing Player Events with `AsyncStream` Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ConcurrencyModel.md Shows how to subscribe to player events using `AsyncStream`. Multiple independent streams can be created from the same event source, with each stream receiving all events broadcast after its creation. Slow consumers will drop the oldest events due to `bufferingNewest`. ```swift Task { for await e in player.events { handleA(e) } } Task { for await e in player.events { handleB(e) } } ``` -------------------------------- ### Delegate Thread-Marshaling Comparison Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Compares the old VLCKit delegate pattern requiring manual main-queue hops with SwiftVLC's direct consumption of events on the main actor via AsyncStreams. ```swift // VLCKit: delegate + manual main-queue hop func mediaPlayerStateChanged(_ notification: Notification!) { DispatchQueue.main.async { self.updateUI() } } ``` ```swift // SwiftVLC: consume on the main actor, no marshaling for await state in player.stateTransitions { updateUI(for: state) } ``` -------------------------------- ### Fetching Media Metadata in SwiftVLC Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Replace the `mediaMetaDataDidChange` delegate in VLCKit with an `await` call to `Media/parse(timeout:instance:)` in SwiftVLC for metadata retrieval. ```swift await Media/parse(timeout:instance:) ``` -------------------------------- ### Transferring Media Ownership with `sending` Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ConcurrencyModel.md Demonstrates how to use the `sending` keyword to transfer ownership of a `Media` object from a background task to the main actor for playback. This prevents the background task from modifying the `Media` object after it has been passed to the player. ```swift public func load(_ media: sending Media) ``` ```swift Task.detached { let media = try Media(url: url) // built off-actor await MainActor.run { try? player.play(media) // ownership transfers in } } ``` -------------------------------- ### SwiftUI Player Screen with PiPVideoView Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md This SwiftUI view demonstrates how to integrate PiPVideoView for Picture-in-Picture playback. It manages the player and a PiPController, allowing users to toggle PiP mode. ```swift struct PlayerScreen: View { @State private var player = Player() @State private var pip: PiPController? var body: some View { VStack { PiPVideoView(player, controller: $pip) .aspectRatio(16/9, contentMode: .fit) Button("Picture in Picture") { pip?.toggle() } .disabled(pip?.isPossible != true) } } } ``` -------------------------------- ### Apply a Built-in Equalizer Preset Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md Load and apply a predefined equalizer preset by its name, such as 'Rock'. If the preset is not found, the default equalizer is used. Set the player's equalizer to nil to disable equalization. ```swift if let rock = Equalizer(preset: Equalizer.presetNames.firstIndex(of: "Rock") ?? 0) { player.equalizer = rock } player.equalizer = nil ``` -------------------------------- ### Adding a Marquee Overlay Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md Use `withMarquee` to add text overlays to the video. Configure the marquee's enabled state, text content, and font size. ```swift player.withMarquee { m in m.isEnabled = true m.setText("LIVE") m.fontSize = 32 } ``` -------------------------------- ### Configure Marquee Text Overlay Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md Configures a text marquee overlay with custom text, refresh interval, font size, color, and screen position. Supports strftime-style placeholders. ```swift player.withMarquee { $0.isEnabled = true $0.setText("%H:%M:%S") $0.refresh = 1000 // refresh every second $0.fontSize = 24 $0.color = 0xFFFFFF $0.screenPosition = .bottomLeft } ``` -------------------------------- ### Set Equalizer Band Gains Using Typed Values Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md Set multiple equalizer band gains at once using typed values, including predefined constants like .flat. Individual band gains and preamp gain are clamped within libVLC's -20.0 to +20.0 dB range. ```swift eq.preampGain = .flat try eq.setBandGains([+3.0, +2.0, .flat, -1.0, -2.0, -2.0, -1.0, .flat, +1.0, +2.0]) try eq.setGain(+6.0, forBand: 3) ``` -------------------------------- ### Enumerate Media Tracks Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md Retrieve and print information about the audio tracks of a media object after parsing or loading. This includes track name, language, and channel count. ```swift let audio = media.tracks().filter { $0.type == .audio } audio.forEach { print($0.name, $0.language ?? "—", $0.channels ?? 0) } ``` -------------------------------- ### Taking a Snapshot of the Video Frame Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md Capture the current video frame and save it as a PNG image to a specified file path. You can optionally specify the width and height for the snapshot. ```swift try player.takeSnapshot( to: "/tmp/frame.png", width: 1920, // pass 0 to derive from aspect ratio height: 0 ) ``` -------------------------------- ### Access Media Statistics Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md Retrieve real-time statistics for input, demux, decoders, and output while a media is loaded. These values are snapshots and can be captured on a timer to display rates over time. ```swift if let stats = player.statistics { print("Input bitrate: \(stats.inputBitrate) kbps") print("Dropped frames: \(stats.lostPictures)") } ``` -------------------------------- ### Controlling Aspect Ratio Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md Set the `aspectRatio` property on the player to control how the video is displayed. Options include default fitting, forcing a specific ratio, or filling the available space. ```swift player.aspectRatio = .default // letterbox/pillarbox to fit ``` ```swift player.aspectRatio = .ratio(16, 9) // force 16:9 ``` ```swift player.aspectRatio = .fill // cover the display; may crop ``` -------------------------------- ### Package.swift Remote Binary Target Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md Defines the libvlc binary target for published states, pointing to a remote URL for the xcframework. ```swift .binaryTarget( name: "libvlc", url: "https://github.com/harflabs/SwiftVLC/releases/download/vX.Y.Z/libvlc.xcframework.zip", checksum: "" ) ``` -------------------------------- ### Check Renderer Capabilities Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md Inspect a discovered renderer item to check its capabilities, such as whether it supports video playback and its specific type. ```swift if renderer.canVideo && renderer.type == "chromecast" { // OK to cast video } ``` -------------------------------- ### Control Playback UI from State Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md Drive UI elements like text descriptions, progress views, and play/pause buttons by directly reading observable properties from the Player instance. ```swift Text(player.state.description) ProgressView(value: player.position) Button(player.isPlaying ? "Pause" : "Play") { player.togglePlayPause() } ``` -------------------------------- ### Player/shutdown() Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md Performs a full asynchronous teardown of the player. After this method returns, no libVLC threads owned by the player are active, and the player becomes an inert no-op. ```APIDOC ## Player/shutdown() ### Description An awaitable full teardown. After it returns, no libVLC thread owned by the player is draining, its streams are finished, and the player is an inert no-op. Reach for it when the player's end-of-life must complete *before* something else, rather than on `deinit`'s background schedule. ### Method `await` (asynchronous function) ### Endpoint N/A (method call) ### Parameters None ### Request Example ```swift await player.shutdown() // Player is now fully shut down and inert. ``` ### Response #### Success Response Completes when the player has been fully torn down. #### Response Example None (asynchronous completion) ``` -------------------------------- ### Optional Result with try? Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/HandlingErrors.md Use try? to simplify error handling when the specific failure reason is not important. This converts any thrown VLCError into a nil result. ```swift try? player.play(url: url) ``` -------------------------------- ### Add SwiftVLC Package to Project Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md Add the SwiftVLC package to your Xcode project by pasting the repository URL. For Package.swift manifests, pin to the latest release version. ```text https://github.com/harflabs/SwiftVLC.git ``` ```swift dependencies: [ .package(url: "https://github.com/harflabs/SwiftVLC.git", from: "x.y.z") ], targets: [ .target(name: "MyApp", dependencies: ["SwiftVLC"]) ] ``` -------------------------------- ### Access Media List Safely Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md For consistent reads, use withLocked to acquire the underlying libVLC lock. The view passed to the closure is not storable. ```swift let mrls = list.withLocked { view in (0..