Skip to content

feat(app): stream Android emulators over the emulator's gRPC API - #77

Merged
dungngminh merged 1 commit into
mainfrom
feat/emulator-grpc-stream
Oct 21, 2026
Merged

dungngminh merged 1 commit into
mainfrom
feat/emulator-grpc-stream

Conversation

@dungngminh

Copy link
Copy Markdown
Owner

Description

Android emulators on macOS now stream the way Android Studio's embedded emulator does: through the emulator's own gRPC API instead of scrcpy, so the guest never encodes H.264.

  • EmulatorGrpcSession (simutil_adb): finds the endpoint from the emulator's discovery file (~/Library/Caches/TemporaryItems/avd/running/pid_<pid>.ini, matched by port.serial; token sent as authorization: Bearer, never logged). Video is streamScreenshot with RGB888 and the MMAP transport into a file the view owns; input is streamInputEvent (touch with rotation undone, W3C keys GoBack/GoHome/AppSwitch…, text via KeyboardEvent.text). Recording uses adb emu screenrecord (webm) converted to mp4 with ffmpeg.
  • SharedFrameTexture (simutil_h264 0.2.0, macOS): maps the shared file and converts each frame (vImage RGB888 → BGRA) into a pooled CVPixelBuffer texture.
  • App: EmulatorVideoView requests the view's physical pixel size (capped at the display), re-requesting on resize/rotation. Falls back to ScrcpySession when no gRPC endpoint shows up (old emulators, -no-grpc); physical devices and Linux/Windows keep scrcpy.
  • gRPC stubs generated from a trimmed copy of emulator_controller.proto, checked in; melos run protoc regenerates them.

Measured on a Pixel 7 Pro AVD (1440x3120, -gpu host) while scrolling continuously, profile build, same load:

gRPC (this PR) scrcpy
Shown fps 60.0 steady 51–59 (~54)
Emulator CPU ~10% ~15%

Verified: tap / swipe / back / typing / Backspace, all four rotations (pointer_location), recording to H.264 mp4.

Known: stream device settings (max fps, bit rate, show touches, stay awake, screen off) don't apply to gRPC emulator streams. Emulator 37.2.12 aborted once inside its gRPC server around a force-kill of the app mid-stream; not reproducible in 5+ tries.

SimUtil streaming an emulator over gRPC at 60 fps

Type of Change

  • 🔥 New feature (non-breaking change which adds functionality)
  • ✨ Enhancement (non-breaking change which improves existing functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • 🧹 Code refactor
  • 📝 Documentation
  • 🗑️ Chore
  • 📦 Build configuration change
  • ✅ Test

Emulators on macOS now stream like Android Studio's embedded emulator:
EmulatorController.streamScreenshot with the MMAP transport writes raw
RGB888 frames into a file the new SharedFrameTexture (simutil_h264) maps
and converts to a BGRA texture, sized to the view and re-requested on
resize/rotation. Input goes through streamInputEvent (touch with
rotation undone, W3C keys, text); recording uses adb emu screenrecord
and ffmpeg. The endpoint comes from the emulator's discovery file
(avd/running/pid_<pid>.ini, matched by port.serial). Emulators without
gRPC, physical devices and Linux/Windows keep scrcpy.

Measured on a Pixel 7 Pro AVD (-gpu host) while scrolling: 60.0 fps
steady vs 51-59 fps with scrcpy, emulator CPU ~10% vs ~15%.

Stubs are generated from a trimmed copy of emulator_controller.proto
(melos run protoc).
@dungngminh dungngminh added feature Features ✨ macos app Desktop app only: shows in app-v* release notes labels Oct 21, 2026
@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 416f0c74-ee2f-45bb-a8d6-b96129128613
📥 Commits

Reviewing files that changed from the base of the PR and between ec1dfc2 and 560d10e.

⛔ Files ignored due to path filters: 4
  • packages/simutil_adb/lib/src/emulator/generated/emulator_controller.pb.dart is excluded by !**/generated/**
  • packages/simutil_adb/lib/src/emulator/generated/emulator_controller.pbenum.dart is excluded by !**/generated/**
  • packages/simutil_adb/lib/src/emulator/generated/emulator_controller.pbgrpc.dart is excluded by !**/generated/**
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing: 27
  • AGENTS.md
  • app/CHANGELOG.md
  • app/lib/src/stream/android/emulator_video_view.dart
  • app/lib/src/stream/device_keyboard.dart
  • app/lib/src/stream/streams_cubit.dart
  • app/lib/src/ui/shared/session_view.dart
  • app/pubspec.yaml
  • app/test/device_keyboard_test.dart
  • docs/ai/architecture.md
  • packages/simutil_adb/CHANGELOG.md
  • packages/simutil_adb/analysis_options.yaml
  • packages/simutil_adb/lib/simutil_adb.dart
  • packages/simutil_adb/lib/src/emulator/emulator_endpoint.dart
  • packages/simutil_adb/lib/src/emulator/emulator_grpc_session.dart
  • packages/simutil_adb/lib/src/emulator/emulator_input.dart
  • packages/simutil_adb/lib/src/ffmpeg.dart
  • packages/simutil_adb/lib/src/scrcpy/scrcpy_session.dart
  • packages/simutil_adb/protos/emulator_controller.proto
  • packages/simutil_adb/pubspec.yaml
  • packages/simutil_adb/test/emulator/emulator_endpoint_test.dart
  • packages/simutil_adb/test/emulator/emulator_input_test.dart
  • packages/simutil_h264/CHANGELOG.md
  • packages/simutil_h264/lib/simutil_h264.dart
  • packages/simutil_h264/macos/simutil_h264/Sources/simutil_h264/SharedFrames.swift
  • packages/simutil_h264/macos/simutil_h264/Sources/simutil_h264/SimutilH264Plugin.swift
  • packages/simutil_h264/pubspec.yaml
  • pubspec.yaml
+---------------------------------------------------------------------+
| You added a feature flag. Great-now we can ship bugs *selectively*. |
+---------------------------------------------------------------------+
  \
   \     /)/)
        ( '')
        /  |
      o(___)
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dungngminh
dungngminh merged commit d9eeedf into main Oct 21, 2026
5 of 7 checks passed
@dungngminh
dungngminh deleted the feat/emulator-grpc-stream branch October 21, 2026 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Desktop app only: shows in app-v* release notes feature Features ✨ macos

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant