PyAgoraRTC 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/PKG-INFO +1 -1
  2. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/architecture.md +4 -1
  3. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/backlog.md +20 -6
  4. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/decisions.md +11 -0
  5. pyagorartc-0.2.1/docs/migration.md +996 -0
  6. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/open_questions.md +14 -4
  7. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/models.py +4 -2
  8. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/session/session.py +7 -1
  9. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyproject.toml +1 -1
  10. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_session_streams.py +45 -1
  11. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_session_streams.py +70 -0
  12. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/test_models.py +1 -0
  13. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/uv.lock +1 -1
  14. pyagorartc-0.2.0/docs/migration.md +0 -683
  15. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.claude/agents/code-reviewer.md +0 -0
  16. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.claude/agents/test-reviewer.md +0 -0
  17. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.github/workflows/ci.yml +0 -0
  18. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.github/workflows/release.yml +0 -0
  19. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.gitignore +0 -0
  20. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.pre-commit-config.yaml +0 -0
  21. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/.python-version +0 -0
  22. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/CLAUDE.md +0 -0
  23. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/CONSTITUTION.md +0 -0
  24. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/CONTRIBUTING.md +0 -0
  25. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/LICENSE +0 -0
  26. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/README.md +0 -0
  27. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/analysis/divergence.md +0 -0
  28. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/analysis/legacy/README.md +0 -0
  29. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/analysis/legacy/agora_api.py +0 -0
  30. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/analysis/legacy/agora_sdp.py +0 -0
  31. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/analysis/legacy/agora_websockets.py +0 -0
  32. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/code_style.md +0 -0
  33. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/protocol.md +0 -0
  34. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/docs/testing.md +0 -0
  35. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/__init__.py +0 -0
  36. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/ap/__init__.py +0 -0
  37. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/ap/client.py +0 -0
  38. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/ap/password.py +0 -0
  39. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/ap/response.py +0 -0
  40. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/const.py +0 -0
  41. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/exceptions.py +0 -0
  42. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/py.typed +0 -0
  43. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/rtm/__init__.py +0 -0
  44. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/rtm/client.py +0 -0
  45. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/sdp/__init__.py +0 -0
  46. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/sdp/answer.py +0 -0
  47. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/sdp/candidates.py +0 -0
  48. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/sdp/offer.py +0 -0
  49. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/session/__init__.py +0 -0
  50. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/session/messages.py +0 -0
  51. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/session/recovery.py +0 -0
  52. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/pyagorartc/session/transport.py +0 -0
  53. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/__init__.py +0 -0
  54. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/_helpers.py +0 -0
  55. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/conftest.py +0 -0
  56. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/__init__.py +0 -0
  57. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/__main__.py +0 -0
  58. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/_common.py +0 -0
  59. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/ap.py +0 -0
  60. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/gateway.py +0 -0
  61. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/rtm.py +0 -0
  62. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/scheduler.py +0 -0
  63. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/server.py +0 -0
  64. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fakegateway/state.py +0 -0
  65. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/README.md +0 -0
  66. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_all_failed.json +0 -0
  67. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_gateway_failed.json +0 -0
  68. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_irregular.json +0 -0
  69. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_one_failed.json +0 -0
  70. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_request_expected.json +0 -0
  71. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/choose_server_response.json +0 -0
  72. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/ap/update_ticket_response.json +0 -0
  73. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/error.json +0 -0
  74. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_failed.json +0 -0
  75. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_failed_code_only.json +0 -0
  76. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_ok.json +0 -0
  77. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_ok_no_ortc.json +0 -0
  78. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_ok_rtx.json +0 -0
  79. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_v3_expected.json +0 -0
  80. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/join_v3_inputs.json +0 -0
  81. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/leave_expected.json +0 -0
  82. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/non_object_message.json +0 -0
  83. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_add_video_stream.json +0 -0
  84. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_add_video_stream_h265_pt0.json +0 -0
  85. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_add_video_stream_minimal.json +0 -0
  86. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_add_video_stream_no_ssrc.json +0 -0
  87. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_notification_quit.json +0 -0
  88. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_notification_warn.json +0 -0
  89. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_p2p_lost.json +0 -0
  90. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_p2p_lost_top_level.json +0 -0
  91. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_p2p_lost_top_level_only.json +0 -0
  92. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_p2p_ok.json +0 -0
  93. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_rtp_capability_change.json +0 -0
  94. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_rtp_capability_change_irregular.json +0 -0
  95. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_token_privilege_did_expire.json +0 -0
  96. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_token_privilege_will_expire.json +0 -0
  97. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_user_offline.json +0 -0
  98. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_user_offline_no_uid.json +0 -0
  99. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/on_user_online.json +0 -0
  100. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/ping_back.json +0 -0
  101. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/ping_expected.json +0 -0
  102. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/renew_token_expected.json +0 -0
  103. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/set_client_role_expected.json +0 -0
  104. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/subscribe_expected.json +0 -0
  105. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/unknown_event.json +0 -0
  106. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/gateway/unsubscribe_expected.json +0 -0
  107. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_delivered.json +0 -0
  108. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_failed.json +0 -0
  109. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_failed_sent.json +0 -0
  110. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_mixed_case.json +0 -0
  111. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_offline.json +0 -0
  112. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/ack_sent.json +0 -0
  113. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/rtm/peer_message_request_expected.json +0 -0
  114. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/chrome_answer_shipped.sdp +0 -0
  115. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/chrome_offer_ortc_shipped.json +0 -0
  116. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/chrome_recvonly_offer.sdp +0 -0
  117. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/gateway_join_ortc.json +0 -0
  118. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/gateway_ortc_vp8.json +0 -0
  119. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/go2rtc_offer.sdp +0 -0
  120. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/fixtures/sdp/whep_trickle_fragment.sdpfrag +0 -0
  121. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/__init__.py +0 -0
  122. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/_helpers.py +0 -0
  123. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/conftest.py +0 -0
  124. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_ap_client.py +0 -0
  125. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_fakegateway_contract_ap.py +0 -0
  126. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_fakegateway_contract_control.py +0 -0
  127. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_fakegateway_contract_gateway_events.py +0 -0
  128. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_fakegateway_contract_gateway_join.py +0 -0
  129. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_fakegateway_contract_rtm.py +0 -0
  130. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_rtm_client.py +0 -0
  131. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_session_endings.py +0 -0
  132. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_session_join.py +0 -0
  133. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_session_secrets.py +0 -0
  134. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_session_timers.py +0 -0
  135. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/integration/test_transport.py +0 -0
  136. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/meta/__init__.py +0 -0
  137. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/meta/_helpers.py +0 -0
  138. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/meta/test_conventions.py +0 -0
  139. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/meta/test_guards.py +0 -0
  140. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/regression/__init__.py +0 -0
  141. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/__init__.py +0 -0
  142. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/_fakes.py +0 -0
  143. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/ap/__init__.py +0 -0
  144. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/ap/test_client.py +0 -0
  145. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/ap/test_password.py +0 -0
  146. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/ap/test_response.py +0 -0
  147. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/conftest.py +0 -0
  148. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/rtm/__init__.py +0 -0
  149. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/rtm/test_client.py +0 -0
  150. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/sdp/__init__.py +0 -0
  151. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/sdp/_helpers.py +0 -0
  152. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/sdp/test_answer.py +0 -0
  153. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/sdp/test_candidates.py +0 -0
  154. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/sdp/test_offer.py +0 -0
  155. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/__init__.py +0 -0
  156. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/_helpers.py +0 -0
  157. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_messages.py +0 -0
  158. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_recovery.py +0 -0
  159. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_session.py +0 -0
  160. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_session_recovery.py +0 -0
  161. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_session_teardown.py +0 -0
  162. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_session_timers.py +0 -0
  163. {pyagorartc-0.2.0 → pyagorartc-0.2.1}/tests/unit/session/test_transport.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: PyAgoraRTC
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Async Python client for Agora RTC signalling: edge discovery, SDP/ORTC negotiation and the WebSocket gateway session
5
5
  Project-URL: Homepage, https://github.com/mikey0000/PyAgoraRTC
6
6
  Project-URL: Documentation, https://github.com/mikey0000/PyAgoraRTC/tree/main/docs
@@ -77,7 +77,9 @@ host: s = AgoraSession(creds, ap, options, callbacks…)
77
77
  (JoinRejectedError / JoinTimeoutError; never a fabricated SDP)
78
78
  4. subscribe to streams already in the join payload, and to each
79
79
  announced stream once both on_add_video_stream and
80
- on_user_online for its publisher have been seen (any order),
80
+ on_user_online for its publisher have been seen (any order;
81
+ a held stream logs its uid at DEBUG, Q18) — or on the
82
+ announcement alone with subscribe_requires_online=False (D28),
81
83
  filtered by target_uid and never our own uid; each subscribe
82
84
  task calls on_stream(stream) once, after its first subscribe
83
85
  5. start owned tasks: ping, keepalive (if given); every timer
@@ -145,6 +147,7 @@ new `AgoraSession`. That is what keeps state simple enough to reason about.
145
147
  | `set_client_role` after join | `SessionOptions.send_set_client_role` (default off) | knowing the device tolerates it |
146
148
  | Join codec and flags | `client_codec` (default `vp8`, D7), `prealloc_pc` (default on, Q10), `extra_join_attributes` (merged into `userAttributes` last; stored read-only) | the codec its device publishes; any flag it needs |
147
149
  | DTLS role in the client ORTC | `ortc_dtls_role` (default `server`; `None` sends none, D4/Q2) | a parity experiment |
150
+ | Subscribing before presence | `subscribe_requires_online` (default on, D28/Q18) | whether its gateway sends `on_user_online` for a publisher |
148
151
  | Ending on `on_p2p_lost` | `end_on_p2p_lost` (default off, D22) | whether its device treats it as fatal |
149
152
  | Renewal cadence | `renew_debounce_s` (default 30 s, D8/Q11) | nothing, unless the gateway penalises repeats |
150
153
  | Timeouts | `join_timeout_s` (15 s), `connect_timeout_s` (10 s) | a slower network |
@@ -19,6 +19,15 @@ Open work only; finished items are deleted.
19
19
  coverage.
20
20
  - A fake gateway knob that omits `dtlsParameters.fingerprints` from the join
21
21
  response, so D26's fill-in gets integration coverage (Q19).
22
+ - A way for a host to filter the join's inline candidates. PetKit dropped
23
+ host candidates before the join (`whep_proxy.py:170-173`); `join()` now
24
+ sends every `a=candidate:` in the offer. The workaround (strip the lines,
25
+ `add_ice_candidate` the filtered ones, migration §3.6) works; decide after
26
+ the PetKit run whether an option is worth it.
27
+ - Send AP detail `6` without putting `string_uid` into the join. PetKit's AP
28
+ request always carried `6 = str(uid)` (`agora_api.py:320-321`) and its join
29
+ none (`agora_websocket.py:686`); `ChannelCredentials.string_uid` couples
30
+ the two (Q9).
22
31
  - Post-join trickle candidates once Q4 is answered.
23
32
  - ICE restart / rejoin with `rejoin_token` (the field is stored today and
24
33
  never used).
@@ -31,12 +40,17 @@ Open work only; finished items are deleted.
31
40
 
32
41
  ## Hosts
33
42
 
34
- - HA-Luba: replace `custom_components/mammotion/agora_*.py` with `pyagorartc`
35
- per `docs/migration.md`; keep its six Agora tests as library tests (done
36
- here) and delete the local copies.
37
- - PetKit: migration per `docs/migration.md`; the `set_client_role` question
38
- (Q3) must be answered on real hardware before the default changes for
39
- them.
43
+ - HA-Luba: merge the `pyagorartc-migration` branch (`docs/migration.md` §2)
44
+ once the hardware run below passes.
45
+ - HA-Luba: run one WiFi and one 4G session on a Luba 2 and a Yuka across all
46
+ camera uids to validate the migration (Q2, Q5, Q6, Q10, Q11; migration §4).
47
+ - pymammotion drops its unused `sdp-transform`, `websockets`, `webrtc-models`
48
+ requirements.
49
+ - PetKit: migration per `docs/migration.md` §3. One go2rtc session per
50
+ camera model at DEBUG answers Q18 first (it decides the default of
51
+ `subscribe_requires_online`, D28), then Q3, Q7 and
52
+ Q13 (migration §4). `send_set_client_role` and `end_on_p2p_lost` stay on
53
+ for PetKit until those runs say otherwise.
40
54
 
41
55
  ## Documentation
42
56
 
@@ -239,3 +239,14 @@ dozen characters, so a `renew_token` frame is logged whole, token included
239
239
  `pyagorartc.session.wire`, set to INFO. A host that needs the frames can set
240
240
  that logger to DEBUG on purpose; the session's own frame lines go through
241
241
  `describe_frame` and carry no values.
242
+
243
+ ## D28. The presence gate on subscribe is an option
244
+
245
+ HA-Luba subscribed to an announced stream only once its publisher's
246
+ `on_user_online` had been seen; PetKit subscribed on `on_add_video_stream`
247
+ alone, and its camera likely starts publishing after the join, so the gate
248
+ could hold its stream forever. `SessionOptions.subscribe_requires_online`
249
+ defaults to `True`, preserving the Mammotion rule; PetKit passes `False`,
250
+ which counts the announced uid as present so `on_user_offline` still tears
251
+ the subscription down. A held stream logs its uid at DEBUG. Q18 decides the
252
+ eventual default.