(
state: AppState,
udid: String,
payload: WebRtcOfferPayload,
_peer_is_loopback: bool,
)
| 138 | } |
| 139 | |
| 140 | pub async fn create_answer( |
| 141 | state: AppState, |
| 142 | udid: String, |
| 143 | payload: WebRtcOfferPayload, |
| 144 | _peer_is_loopback: bool, |
| 145 | ) -> Result<WebRtcAnswerPayload, AppError> { |
| 146 | if payload.kind != "offer" { |
| 147 | return Err(AppError::bad_request( |
| 148 | "WebRTC payload must include type `offer`.", |
| 149 | )); |
| 150 | } |
| 151 | let is_android = android::is_android_id(&udid); |
| 152 | if payload.transport.is_some() { |
| 153 | return Err(AppError::bad_request( |
| 154 | "Unsupported WebRTC transport. SimDeck streams WebRTC video over media tracks.", |
| 155 | )); |
| 156 | } |
| 157 | if !is_android { |
| 158 | if let Some(stream_config) = payload.stream_config.as_ref() { |
| 159 | apply_stream_quality_payload(&state, stream_config)?; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | let source = if is_android { |
| 164 | WebRtcVideoSource::Android( |
| 165 | AndroidWebRtcSource::start( |
| 166 | state.android.clone(), |
| 167 | state.metrics.clone(), |
| 168 | udid.clone(), |
| 169 | android_h264_quality_from_payload(payload.stream_config.as_ref())?, |
| 170 | ) |
| 171 | .await?, |
| 172 | ) |
| 173 | } else { |
| 174 | let session = state.registry.get_or_create_async(&udid).await?; |
| 175 | if let Err(error) = session.ensure_started_async().await { |
| 176 | state.registry.remove(&udid); |
| 177 | return Err(error); |
| 178 | } |
| 179 | apply_stream_client_foreground(&state, &session, &payload.client_id, Some(true)); |
| 180 | WebRtcVideoSource::Simulator(session) |
| 181 | }; |
| 182 | |
| 183 | info!( |
| 184 | "WebRTC offer for {udid}: remote_candidates={} remote_candidate_types={} ice_servers={} ice_transport_policy={}", |
| 185 | count_sdp_candidates(&payload.sdp), |
| 186 | summarize_sdp_candidate_types(&payload.sdp), |
| 187 | std::env::var("SIMDECK_WEBRTC_ICE_SERVERS") |
| 188 | .ok() |
| 189 | .filter(|value| !value.trim().is_empty()) |
| 190 | .unwrap_or_else(|| DEFAULT_STUN_URL.to_owned()), |
| 191 | ice_transport_policy_label() |
| 192 | ); |
| 193 | |
| 194 | let first_frame = wait_for_h264_sync_keyframe(&source, WEBRTC_INITIAL_KEYFRAME_TIMEOUT) |
| 195 | .await |
| 196 | .ok_or_else(|| AppError::native("Timed out waiting for a device H.264 keyframe."))?; |
| 197 | let codec = first_frame |
no test coverage detected