Summary
Battery Tapo cameras on newer firmware (tested: C660 firmware 1.1.7 Build 251226) send video as AES-encrypted MPEG-TS on port 8800. go2rtc connects and authenticates correctly, audio streams fine, but video bytes stay at 0 because the decryption step is not implemented.
Behaviour
tapo:// protocol connects successfully
- Audio (PCMA/8000) streams correctly — bytes accumulate on the audio receiver
- Video receiver bytes stay at 0
- Camera sends
X-If-Encrypt: 1 header in the HTTP stream response
Encryption algorithm
The camera signals encryption via the HTTP response header:
X-If-Encrypt: 1
X-Session-Id: 2
The AES-128-CBC key and IV are derived from a session nonce:
- Key:
MD5(username + ":" + nonce)
- IV:
MD5(nonce + ":" + password)
- The nonce comes from the
Key-Exchange header in the HTTP auth response
Reference / prior art: https://drmnsamoliu.github.io/video.html
Workaround
The substream (?subtype=1) uses a different mechanism and streams correctly as 720p H264 — this is the current workaround:
streams:
c660:
- tapo://admin:MD5HASH@192.168.1.x?subtype=1
For full-resolution decryption, pytapo's getMediaSession() implements the complete auth + AES decryption correctly and can be used as a reference implementation.
Affected cameras
Any Tapo battery camera that lacks the "camera account" option in firmware — the cloud credential auth path is used instead, which triggers the encrypted stream. Known affected models: C660, C410, C420, C425 and likely others in the battery/solar range.
Environment
- go2rtc version: 1.9.14
- Camera: Tapo C660, firmware 1.1.7 Build 251226 Rel.53177n
- Camera IP on port 8800 (Tapo proprietary protocol)
Summary
Battery Tapo cameras on newer firmware (tested: C660 firmware 1.1.7 Build 251226) send video as AES-encrypted MPEG-TS on port 8800. go2rtc connects and authenticates correctly, audio streams fine, but video bytes stay at 0 because the decryption step is not implemented.
Behaviour
tapo://protocol connects successfullyX-If-Encrypt: 1header in the HTTP stream responseEncryption algorithm
The camera signals encryption via the HTTP response header:
The AES-128-CBC key and IV are derived from a session nonce:
MD5(username + ":" + nonce)MD5(nonce + ":" + password)Key-Exchangeheader in the HTTP auth responseReference / prior art: https://drmnsamoliu.github.io/video.html
Workaround
The substream (
?subtype=1) uses a different mechanism and streams correctly as 720p H264 — this is the current workaround:For full-resolution decryption, pytapo's
getMediaSession()implements the complete auth + AES decryption correctly and can be used as a reference implementation.Affected cameras
Any Tapo battery camera that lacks the "camera account" option in firmware — the cloud credential auth path is used instead, which triggers the encrypted stream. Known affected models: C660, C410, C420, C425 and likely others in the battery/solar range.
Environment