diff --git a/packages/build-tools/src/steps/functions/startServeSimRemoteSession.ts b/packages/build-tools/src/steps/functions/startServeSimRemoteSession.ts index 8daccbced5..bbc9f97acb 100644 --- a/packages/build-tools/src/steps/functions/startServeSimRemoteSession.ts +++ b/packages/build-tools/src/steps/functions/startServeSimRemoteSession.ts @@ -28,19 +28,18 @@ export function createStartServeSimRemoteSessionBuildFunction( await selectXcodeDeveloperDirectoryAsync({ env, logger }); - const { previewUrl, streamUrl } = await startServeSimWithTunnelAsync(ctx, { + const { previewUrl } = await startServeSimWithTunnelAsync(ctx, { baseDomain: ngrokTunnelDomain, env, logger, timeoutMs: STARTUP_TIMEOUT_MS, }); logger.info(`Preview URL: ${previewUrl}`); - logger.info(`Stream URL: ${streamUrl}`); await uploadRemoteSessionConfigAsync({ ctx, deviceRunSessionId, - remoteConfig: { previewUrl, streamUrl }, + remoteConfig: { previewUrl }, logger, }); diff --git a/packages/build-tools/src/steps/utils/__tests__/remoteDeviceRunSession.test.ts b/packages/build-tools/src/steps/utils/__tests__/remoteDeviceRunSession.test.ts index 4f90de3b03..23aa6cf4a6 100644 --- a/packages/build-tools/src/steps/utils/__tests__/remoteDeviceRunSession.test.ts +++ b/packages/build-tools/src/steps/utils/__tests__/remoteDeviceRunSession.test.ts @@ -5,6 +5,7 @@ import { CustomBuildContext } from '../../../customBuildContext'; import { Sentry } from '../../../sentry'; import { turtleFetch } from '../../../utils/turtleFetch'; import { + createServeSimTunnelArgs, fetchServeSimTurnArgsAsync, turnIceServersToServeSimArgs, } from '../remoteDeviceRunSession'; @@ -36,6 +37,29 @@ function createEnvMock(): BuildStepEnv { return { DEVICE_RUN_SESSION_ID: 'drs-id' } as unknown as BuildStepEnv; } +describe(createServeSimTunnelArgs, () => { + it('builds ngrok H264 serve-sim args without forcing WebRTC', () => { + expect(createServeSimTunnelArgs({ baseDomain: 'expo-simulator.ngrok.dev' })).toEqual([ + 'serve-sim-sjchmiela@latest', + '--tunnel', + '--tunnel-provider', + 'ngrok', + '--tunnel-domain', + 'expo-simulator.ngrok.dev', + '--stream-max-dimension', + '1280', + '--stream-quality', + '0.55', + '--stream-fps', + '10', + '--h264-bitrate', + '3000000', + '--h264-max-fps', + '30', + ]); + }); +}); + describe(turnIceServersToServeSimArgs, () => { it('returns no args for an empty ICE server list', () => { expect(turnIceServersToServeSimArgs([])).toEqual([]); diff --git a/packages/build-tools/src/steps/utils/remoteDeviceRunSession.ts b/packages/build-tools/src/steps/utils/remoteDeviceRunSession.ts index 5e084a1aa6..342d492798 100644 --- a/packages/build-tools/src/steps/utils/remoteDeviceRunSession.ts +++ b/packages/build-tools/src/steps/utils/remoteDeviceRunSession.ts @@ -16,6 +16,13 @@ import { turtleFetch } from '../../utils/turtleFetch'; const XCODE_DEVELOPER_DIR = '/Applications/Xcode.app/Contents/Developer'; +const SERVE_SIM_PACKAGE_SPEC = 'serve-sim-sjchmiela@latest'; +const SERVE_SIM_MJPEG_FALLBACK_MAX_DIMENSION = '1280'; +const SERVE_SIM_MJPEG_FALLBACK_QUALITY = '0.55'; +const SERVE_SIM_MJPEG_FALLBACK_FPS = '10'; +const SERVE_SIM_H264_BITRATE = '3000000'; +const SERVE_SIM_H264_MAX_FPS = '30'; + const START_DEVICE_RUN_SESSION_MUTATION = graphql(` mutation StartDeviceRunSession($deviceRunSessionId: ID!, $remoteConfig: JSONObject!) { deviceRunSession { @@ -246,7 +253,7 @@ export function spawnDetached({ } export async function startServeSimWithTunnelAsync( - ctx: CustomBuildContext, + _ctx: CustomBuildContext, { baseDomain, env, @@ -258,45 +265,52 @@ export async function startServeSimWithTunnelAsync( logger: bunyan; timeoutMs: number; } -): Promise<{ previewUrl: string; streamUrl: string }> { +): Promise<{ previewUrl: string }> { logger.info('Launching serve-sim with tunnel.'); - const turnArgs = await fetchServeSimTurnArgsAsync(ctx, { env, logger }); const serveSim = spawnDetached({ command: 'npx', - args: [ - 'serve-sim-szdziedzic@latest', - '--tunnel', - '--tunnel-provider', - 'ngrok', - '--tunnel-domain', - baseDomain, - '--stream-max-dimension', - '1280', - '--stream-quality', - '0.55', - '--codec', - 'webrtc', - ...turnArgs, - ], + args: createServeSimTunnelArgs({ baseDomain }), env, }); - logger.info('Waiting for serve-sim to report tunnel and stream URLs.'); + logger.info('Waiting for serve-sim to report tunnel URL.'); const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { const output = serveSim.getOutput(); const previewUrl = matchLabeledUrl({ output, label: 'Tunnel', baseDomain }); - const streamUrl = matchLabeledUrl({ output, label: 'Stream', baseDomain }); - if (previewUrl && streamUrl) { - return { previewUrl, streamUrl }; + if (previewUrl) { + return { previewUrl }; } await sleepAsync(1_000); } throw new SystemError( - `Timed out waiting for serve-sim to report Tunnel and Stream URLs. Last output:\n${serveSim.getOutput() || ''}` + `Timed out waiting for serve-sim to report Tunnel URL. Last output:\n${serveSim.getOutput() || ''}` ); } +export function createServeSimTunnelArgs({ baseDomain }: { baseDomain: string }): string[] { + return [ + SERVE_SIM_PACKAGE_SPEC, + '--tunnel', + '--tunnel-provider', + 'ngrok', + '--tunnel-domain', + baseDomain, + // MJPEG remains the browser fallback when AVCC/H.264 is unavailable. + '--stream-max-dimension', + SERVE_SIM_MJPEG_FALLBACK_MAX_DIMENSION, + '--stream-quality', + SERVE_SIM_MJPEG_FALLBACK_QUALITY, + '--stream-fps', + SERVE_SIM_MJPEG_FALLBACK_FPS, + // The tunneled helper advertises /stream.avcc, so keep H.264 network usage bounded. + '--h264-bitrate', + SERVE_SIM_H264_BITRATE, + '--h264-max-fps', + SERVE_SIM_H264_MAX_FPS, + ]; +} + function matchLabeledUrl({ output, label,