惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
K
Kaspersky official blog
A
Arctic Wolf
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
Lohrmann on Cybersecurity
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Last Watchdog
The Last Watchdog
B
Blog RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
博客园 - Franky
T
Tenable Blog
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Help Net Security
Help Net Security
WordPress大学
WordPress大学
T
The Exploit Database - CXSecurity.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
S
Security Affairs
J
Java Code Geeks
小众软件
小众软件
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
NISL@THU
NISL@THU
O
OpenAI News
The Cloudflare Blog
月光博客
月光博客
Google Online Security Blog
Google Online Security Blog
V
V2EX
罗磊的独立博客
美团技术团队
博客园 - 三生石上(FineUI控件)
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏

Dropbox Tech Blog

How we used DSPy to turn AI evaluations into better responses in Dash chat How Dropbox uses MCP and Dash to close the design-to-code security gap Beyond code generation: rethinking engineering productivity in the age of AI agents Introducing Nova, our internal platform for coding agents Improving storage efficiency in Magic Pocket, our immutable blob store Reducing our monorepo size to improve developer velocity How we optimized Dash's relevance judge with DSPy Using LLMs to amplify human labeling and improve Dash search relevance How low-bit inference enables efficient AI Insights from our executive roundtable on AI and engineering productivity Engineering VP Josh Clemm on how we use knowledge graphs, MCP, and DSPy in Dash Inside the feature store powering real-time AI in Dropbox Dash Building the future: highlights from Dropbox’s 2025 summer intern class Fighting the forces of clock skew when syncing password payloads Introducing Focus, a new open source Gradle plugin Making camera uploads for Android faster and more reliable Why we built a custom Rust library for Capture Detecting memory leaks in Android applications How we sped up Dropbox Android app startup by 30% Why we chose Apache Superset as our data exploration platform Revamping the Android testing pipeline at Dropbox Our counterintuitive fix for Android path normalization JQuery to React: How we rewrote the HelloSign Editor How we ensure credible analytics on Dropbox mobile apps Engineering Dropbox Transfer: Making simple even simpler Speeding up a Git monorepo at Dropbox with <200 lines of code Building for reliability at HelloSign Store grand re-opening: loading Android data with coroutines Modernizing our Android build system: Part I, the planning Modernizing our Android build system: Part II, the execution Our journey to type checking 4 million lines of Python The (not so) hidden cost of sharing code between iOS and Android Redux with Code-Splitting and Type Checking The Programmer Mindset: Main Debug Loop On working with designers Incrementally migrating over one million lines of code from Python 2 to Python 3 Crash reporting in desktop Python applications What we learned at our first JS Guild Summit How we rolled out one of the largest Python 3 migrations ever Dropbox Paper: Emojis and Exformation Creating a culture of accessibility Adding IPv6 connectivity support to the Dropbox desktop client Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 2 Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 1 DropboxMacUpdate: Making automatic updates on macOS safer and more reliable Annotations on Document Previews Open Sourcing Pytest Tools Open Sourcing Zulip – a Dropbox Hack Week Project Building Carousel, Part III: Drawing Images on Screen The Tech Behind Dropbox’s New User Experience on Mobile (Part 2) Building Dropbox’s New User Experience for Mobile, Part 1 Building Carousel, Part II: Speeding Up the Data Model Building Carousel, Part I: How we made our networked mobile app feel fast and local Scaling MongoDB at Mailbox Welcome Guido! Dropbox dives into CoffeeScript Some love for JavaScript applications Plop: Low-overhead profiling for Python Using the Dropbox API from Haskell A Python Optimization Anecdote Translating Dropbox
How Dropbox Replay keeps everyone in sync
Alan Rogers, Daniel Wagner, and Siya Yang · 2021-11-23 · via Dropbox Tech Blog

How do you recreate the experience of an in-person screening room with a remote, distributed team? This is one of the reasons we built Dropbox Replay, our new video collaboration tool. Dropbox customers told us the shift to virtual work had turned their once-straightforward review sessions into lengthy, inefficient video calls. It was clear their previous in-person workflows hadn’t made an elegant transition online.

When we looked at the market for virtual screening tools, we mostly found expensive Hollywood-scale solutions or clunky DIY experiences run over video conferencing tools. Nothing quite offered the kind of collaborative, live, and synchronous playback experience we envisioned—something that would approximate the feeling of being together in a screening room, with shared feedback, cursors, and playback controls. We knew there was an opportunity for an accessible yet high-quality online screening experience where people could collaborate in realtime as they would in person, but virtually—and where everyone could see the same thing and seamlessly annotate what they were seeing in real time. We created Dropbox Replay’s Live Review feature in response.

But keeping a virtual screening room with multiple collaborators in sync is a harder problem to solve than you might think. Anyone in a Live Review session can pause, adjust the playback speed, or scrub to a different frame at anytime. This is great for keeping screenings open and collaborative, but it also means that everyone might be sending conflicting commands at once. What if two people try to change the position of the video at the same time? 

For Live Review to work, we need to make sure that everyone converges on the same playback state in a timely manner. When a person is ready to discuss a frame, they must be able to trust that everyone is seeing the same frame too.

Changing states

In a Live Review session, we care about two types of state—single client state and shared client state. The position of someone’s mouse cursor or the drawings they make on a video frame are examples of single client state. These can’t conflict with other clients, so they’re relatively easy to handle: changes in single client state are sent to the server, which echoes them to the other clients, and that’s that. 

The shared client state, on the other hand, is what keeps local playback synchronized between all of the clients in a Live Review session. When someone joins a Live Review session, their client opens a WebSocket connection with a Dropbox Replay server (we use an open source Go library called Gorilla, which is already used elsewhere within Dropbox). Anytime someone presses play, pause, or changes the position of the video, the client sends a message conveying this change to the server, which updates the shared client state and then sends it to everyone else in the session.

The playback state is encoded using Protocol Buffers, which offer an extensible, schematized, and space-efficient way to package the data. We like the combination of Protocol Buffers and WebSockets; Protocol Buffers don’t concern themselves with message framing and leave the format on the wire up to the developer. WebSockets, meanwhile, are largely content-agnostic and offer text or binary messages that are framed, delivered reliably and in order, and even take care of ping/pong heartbeats, which can keep sessions alive through proxies or firewalls that might otherwise terminate an idle connection.

In a perfect world, only one person would interact with the video at a time. But that’s not how most screenings work. Everyone has something to say, or something they want the group to see—often at the same time! It’s precisely because anyone can influence playback at any time that our protocol must be resilient enough to handle multiple concurrent interactions and still produce a consistent outcome for all participants.

Establishing an order of events

One approach might be to simply send all state changes—“video paused at frame” or “cursor is now at position”—to all other clients. However, when the state is shared between clients you can quickly see how this approach will lead to inconsistent states if more than one client changes the state at the same time—for example, if Patty makes a change, sends it to Steven, but Steven makes and sends a change before Patty’s change has arrived.

As you can see in the previous diagram, this approach could quite easily result in Patty and Steven adopting each other’s state and losing their own. The clients will end up out of sync. As far as Patty is concerned, she skipped to frame 120, and then Steven skipped her to frame 240. But as far as Steven is concerned, he skipped to frame 240 and then Patty skipped him to frame 120. How can we stay in sync when this happens?

We could try to add timestamps to messages so that each client can determine if they received an old message—and therefore know the message can be ignored—but this would rely on every client’s clock being synchronized. Since we probably don’t need to know the exact time when a particular event was sent, what if we simply delegated this job to the server instead?

We found we could leverage our server-side sync service to establish a logical clock—and more precisely, a happened-before relationship with the messages it receives from each client in a Live Review session. Individually (i.e. without a server), clients would have to have very precise clocks or engage in a more complicated negotiation to establish that same happened-before relationship. But by simply sending messages to the server and letting the server establish local event precedence—which it then broadcasts to all clients—the result is a simpler approach that achieves the same outcome.

Good, but not great

While WebSockets already guarantee in-order message delivery, what’s left is to ensure that the server processes the incoming messages in the right order. How did we achieve that in our server? 

Our sync service guarantees a response to each playback message will be sent to all clients before it starts processing the next message, therefore establishing a canonical happened-before relationship. But it also echoes messages back to the client that sent them so that we can communicate the timeline to them, too. Let’s look at why this matters:

As you can see, by echoing their messages back to them, Patty and Steven now both end up at the same place. This is good! However, while we now have our clients converging on the same state, they still take different paths. This isn’t necessarily bad, but let’s look at the experience from both sides. 

For Steven:

  • He starts paused on frame 120
  • He then presses play 
  • The video plays
  • Then he sees that Patty paused the video on frame 0—and his video matches

For Patty:

  • She starts paused on frame 120
  • She skips her video to frame 0 and remains paused
  • Because of Steven’s message, her video then starts playing from frame 120
  • But then a short time later her video skips back to frame 0 and remains paused

A decent experience for Steven, but a surprising and clunky experience for Patty. We can do better!

A smooth experience for all

We mentioned before that our server-side sync service acts as a logical clock for these playback messages. It ensures that the order in which it receives a message is reflected in the order it sends that message back out to each and every client—including the client that sent the message in the first place. Can we make use of this to improve the experience for Patty? It turns out we can.

For every state change message Patty receives between the moment she skips to frame 0 and when she receives her own message back from the server, we know something very important: They all must have happened before Patty changed the frame.

How do we know this? The sync service processes and responds to each message one at a time—and in order. This means that, by design, any message that Patty receives before her own message is echoed back must have happened before her initial message, and thus her client can safely ignore it.

What does this look like?

Now let’s look at the experience from both sides again:

For Steven:

  • He starts paused on frame 120
  • He then presses play 
  • The video plays
  • Then he sees that Patty paused the video on frame 0—and his video matches

For Patty:

  • She starts paused on frame 120
  • She skips her video to frame 0 and remains paused

Finally, a smooth experience for both Steven and Patty.

Try it out for yourself

There were, of course, other approaches we could have used to keep everyone in sync. We could have built a system to record, forward and replay events across multiple clients, or used an existing synchronization algorithm—such as operational transformation—to achieve the same result. But while these approaches would have technically been able to keep all clients in sync, it was just as important that, whatever the solution, the Live Review experience feel good for our users, too. By prioritizing how the user would experience a Live Review session, we ended up with a simpler algorithm than if we’d focussed on the engineering problem alone.

We think the resulting experience is smooth and seamless—exactly what you want while receiving feedback on your latest creation. But don’t take our word for it. Dropbox Replay is now available in beta for you to try for for free! Be sure to start your own Live Review session and tell us what you think.

Also: We’re hiring!

Do you love to build new things? Are you a curious engineer with a passion to see where a new idea takes you? Dropbox is hiring

The Replay team is a small, nimble and creative force. We are focused on pushing boundaries and obsessed with building products that make our users’ lives easier and more productive. We're always on the lookout for clever, curious engineers who want to learn new things, take on bigger challenges, and build products our customers love. If you're an engineer with talent, passion, and enthusiasm, we'd love to have you at Dropbox. Visit our careers page to apply.

Special thanks to the Dropbox Replay team.