Selected work

ENGINEERING CASE STUDY / Framewright

Making playback failures easier to investigate.

How debugging Android playback at Storyteller motivated me to build an independent, open-source diagnostics toolkit.

  • Kotlin
  • Swift
  • Media3 / ExoPlayer
  • AVPlayer
  • Jetpack Compose
  • SwiftUI
  • Coroutines / Flow
My role
Creator & engineer
Context
Independent · Open source
Focus
Android / iOS playback diagnostics

THE CATALYST

A question that followed me beyond the fix.

At Storyteller, I worked on reusable Android SDK features for media experiences on mobile and TV. Part of that work was diagnosing device-specific lifecycle, rendering, and Surface-attachment failures.

Those investigations are the catalyst for Framewright. I wanted to build a tool around a question I kept returning to: what is happening inside this playback session?

Framewright is my independent, open-source project. My experience at Storyteller supplies the motivation; the toolkit is a separate piece of work.

THE PROBLEM

A visible symptom is the beginning of an investigation.

A playback investigation can cross several boundaries: application lifecycle, rendering, device capability, and the player itself. My Storyteller work brought me into those boundaries directly, alongside product, QA, iOS, backend, and client teams.

That experience shaped the problem I chose to work on independently: give engineers useful playback evidence while allowing their application to keep its existing player integration.

ENGINEERING DECISIONS

Observe the player. Keep ownership explicit.

Framewright attaches to a host-owned Media3 ExoPlayer. The application still creates, controls, and releases that player. This boundary lets an integration add diagnostics without handing over its playback lifecycle.

The toolkit produces structured events and separates analytics from the Media3 adapter. Bandwidth, codec, DRM, Compose UI, and persistence diagnostics are optional modules. Teams can select the pieces relevant to their investigation.

The integration still has responsibilities: attach on the player’s application thread, track preparation, and close diagnostics in the lifecycle that owns the player. Keeping those steps visible makes the ownership contract clear.

Integration boundary Conceptual architecture
  1. HOST APPLICATIONOwns the player

    Create · Configure · Play · Release

  2. MEDIA3 ADAPTERObserves playback

    Host player callbacks → Structured events

  3. DIAGNOSTIC MODULESBuilds the evidence

    Analytics · Bandwidth · Codec · DRM · UI · Storage

Minimal attachment & cleanupKotlin
val player = ExoPlayer.Builder(context).build()
val diagnostics = FramewrightMedia3.attach(context, player)

player.setMediaItem(MediaItem.fromUri(mediaUri))
diagnostics.trackPrepare(MediaSessionInfo(mediaUri.toString())) {
    player.prepare()
}
player.play()

// When the owning lifecycle ends:
diagnostics.close()
player.release()

Lifecycle excerpt from the public documentation. Event collection and optional modules are covered in the integration guide. Integration guide ↗

THE RESULT

A toolkit engineers can inspect and integrate.

Framewright captures startup timing, buffering, track changes, dropped frames, decoder details, and playback errors. A minimal integration can collect live events; optional modules add diagnostic UI and session persistence with JSON export.

The public repository includes a demonstration app and integration documentation. The result I can point to is the toolkit and its integration surface. Its effect on debugging time and production reliability remains to be measured.

REFLECTION

Turning production experience into developer tooling.

For me, Framewright connects two parts of engineering: investigating an immediate product issue and building something reusable from the experience. The Storyteller work gave me the motivation; the independent project gives me room to explore the tooling.

A useful next step is to document a reproducible playback investigation from symptom to evidence. That would make the toolkit’s practical value easier to evaluate alongside its API and architecture.

CONTINUE EXPLORING

See the work behind the story.

Back to selected work