twrecked / pyaarlo

Asynchronous Arlo Component for Python
GNU Lesser General Public License v3.0
50 stars 30 forks source link

Unable to get stream url during a user active stream #151

Open YpNo opened 2 months ago

YpNo commented 2 months ago

HI,

I've created a simple python script to try getting the stream url when a Live stream is running. But it seems that the stream url cannot be get during a "manual" running stream.

How to handle that ? It should be in the _start_stream function but I didn't know what I should change or not.

Here my script:

import pyaarlo
from decouple import config
from time import sleep
import sys
import logging

# Read config from ENV
ARLO_USER = config('ARLO_USER')
ARLO_PASS = config('ARLO_PASS')
IMAP_HOST = config('IMAP_HOST')
IMAP_USER = config('IMAP_USER')
IMAP_PASS = config('IMAP_PASS')
DEBUG = config('DEBUG', default=False, cast=bool)
PYAARLO_BACKEND = config('PYAARLO_BACKEND', default=None)
PYAARLO_REFRESH_DEVICES = config('PYAARLO_REFRESH_DEVICES', default=0, cast=int)
PYAARLO_STREAM_TIMEOUT = config('PYAARLO_STREAM_TIMEOUT', default=0, cast=int)
PYAARLO_STORAGE_DIR = config('PYAARLO_STORAGE_DIR', default=None)
PYAARLO_ECDH_CURVE = config('PYAARLO_ECDH_CURVE', default=None)

# Initialize logging
logging.basicConfig(
  level=logging.DEBUG if DEBUG else logging.INFO,
  format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
  )

def check_camera_stream(camera):
  """
  Checks if the given camera has an active stream.
  Returns True if the stream is active, False otherwise.
  """
  # Get thestream_url = camera.get_stream()
  # return bool(stream_url)
  return camera.is_streaming

def main():
  """
  Main function to check camera streams every 30 seconds.
  """

  arlo_args = {
      'username': ARLO_USER,
      'password': ARLO_PASS,
      'tfa_source': 'imap',
      'tfa_type': 'email',
      'tfa_host': IMAP_HOST,
      'tfa_username': IMAP_USER,
      'tfa_password': IMAP_PASS,
      'save_session': True,
      # 'verbose_debug': DEBUG
  }

  if PYAARLO_REFRESH_DEVICES:
      arlo_args['refresh_devices_every'] = PYAARLO_REFRESH_DEVICES

  if PYAARLO_STREAM_TIMEOUT:
      arlo_args['stream_timeout'] = PYAARLO_STREAM_TIMEOUT

  if PYAARLO_BACKEND:
      arlo_args['backend'] = PYAARLO_BACKEND

  if PYAARLO_STORAGE_DIR:
      arlo_args['storage_dir'] = PYAARLO_STORAGE_DIR

  if PYAARLO_ECDH_CURVE:
      arlo_args['ecdh_curve'] = PYAARLO_ECDH_CURVE

  try:
      arlo = pyaarlo.PyArlo(**arlo_args)
  except ValueError as e:
      print(f"Error: {e}")
      sys.exit(1)

  # Get the list of cameras
  cameras = arlo.cameras
  if not cameras:
    print("No Arlo cameras found.")
    exit(1)

  while True:
    try:
      for camera in cameras:
        if check_camera_stream(camera):
          print(f"Camera {camera.name} has an active stream")
          stream_url = camera.get_stream()
          print(f"{camera.name} -> Stream URL: {stream_url}")
        else:
            print(f"Camera {camera.name} does not have an active stream")
      sleep(10)
    except KeyboardInterrupt:
        print("Program interrupted by user")
        break
    except Exception as e:
        print(f"An error occurred: {e}")
        continue

if __name__ == "__main__":
  main()
twrecked commented 2 months ago

What are the debug logs showing you?

YpNo commented 2 months ago

What are the debug logs showing you?

Ah yes sorry:

# Running loop to check if there are an active streams
...
Camera outdoor-camera does not have an active stream
Camera livingroom-camera does not have an active stream
...

# Starting a live stream on the Arlo App

2024-04-27 18:35:52,326 [DEBUG] pyaarlo: backend: packet-in=
{ 'action': 'is',
  'from': 'AAAAAAAAAAAA',
  'properties': { 'activityState': 'userStreamActive',
                  'dateStarted': 111111111111000},
  'resource': 'cameras/AAAAAAAAAAAA',
  'transId': 'AAAAAAAAAAAA!e26b90c7!111111111111'}
2024-04-27 18:35:52,327 [DEBUG] pyaarlo: backend: packet: device update
2024-04-27 18:35:52,327 [DEBUG] pyaarlo: backend: sending cameras/AAAAAAAAAAAA to AAAAAAAAAAAA
2024-04-27 18:35:52,327 [DEBUG] pyaarlo: backend: cameras/AAAAAAAAAAAA:AAAAAAAAAAAA bounded device!
2024-04-27 18:35:52,327 [DEBUG] pyaarlo: backend: packet-in=
{ 'action': 'is',
  'from': 'AAAAAAAAAAAA',
  'properties': {},
  'resource': 'basestation',
  'to': 'UUUU-111-66666666',
  'transId': 'c7b337cfcced4cde8203472be04ca4d7'}
2024-04-27 18:35:52,327 [DEBUG] pyaarlo: backend: unhandled response basestation - {'to': 'UUUU-111-66666666', 'from': 'AAAAAAAAAAAA', 'transId': 'c7b337cfcced4cde8203472be04ca4d7', 'resource': 'basestation', 'action': 'is', 'properties': {}}
2024-04-27 18:35:52,328 [DEBUG] pyaarlo: backend: basestation:AAAAAAAAAAAA bounded device!
2024-04-27 18:35:52,328 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera BASE got cameras/AAAAAAAAAAAA
2024-04-27 18:35:52,328 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:35:52,328 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloBase/AAAAAAAAAAAA/activityState=userStreamActive
2024-04-27 18:35:52,328 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW userStreamActive
2024-04-27 18:35:52,329 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD userStreamActive
2024-04-27 18:35:52,329 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera CAMERA got one cameras/AAAAAAAAAAAA
2024-04-27 18:35:52,329 [DEBUG] pyaarlo: AAAAAAAAAAAA: _event::stream::reqs='set()',local='{'remote'}',remote='{'streaming'}'
2024-04-27 18:35:52,329 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: child got cameras/AAAAAAAAAAAA event **
2024-04-27 18:35:52,329 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:35:52,330 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/activityState=userStreamActive
2024-04-27 18:35:52,330 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW userStreamActive
2024-04-27 18:35:52,330 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD userStreamActive
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: backend: packet-in=
{ 'action': 'is',
  'from': 'AAAAAAAAAAAA',
  'properties': {'activityState': 'startUserStream'},
  'resource': 'cameras/AAAAAAAAAAAA',
  'to': 'UUUU-111-66666666',
  'transId': 'iOS!RG8AN9CX-2770-176-132407479!1714235748!10019'}
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: backend: packet: device update
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: backend: sending cameras/AAAAAAAAAAAA to AAAAAAAAAAAA
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: backend: cameras/AAAAAAAAAAAA:AAAAAAAAAAAA bounded device!
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera BASE got cameras/AAAAAAAAAAAA
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloBase/AAAAAAAAAAAA/activityState=startUserStream
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW startUserStream
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD startUserStream
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera CAMERA got one cameras/AAAAAAAAAAAA
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: child got cameras/AAAAAAAAAAAA event **
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/activityState=startUserStream
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW startUserStream
2024-04-27 18:35:52,373 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD startUserStream

...

Camera outdoor-camera does not have an active stream
Camera livingroom-camera has an active stream
2024-04-27 18:35:57,334 [DEBUG] pyaarlo: AAAAAAAAAAAA: _start_stream::reqs='set()',local='{'streaming', 'remote'}',remote='{'streaming'}'
livingroom-camera -> Stream URL: None

...

Camera outdoor-camera does not have an active stream
Camera livingroom-camera has an active stream
2024-04-27 18:36:07,338 [DEBUG] pyaarlo: AAAAAAAAAAAA: _start_stream::reqs='set()',local='{'streaming', 'remote'}',remote='{'streaming'}'
livingroom-camera -> Stream URL: None

...

Camera outdoor-camera does not have an active stream
Camera livingroom-camera has an active stream
2024-04-27 18:36:17,343 [DEBUG] pyaarlo: AAAAAAAAAAAA: _start_stream::reqs='set()',local='{'streaming', 'remote'}',remote='{'streaming'}'
livingroom-camera -> Stream URL: None

# Stopping the live stream on the Arlo App

2024-04-27 18:36:24,809 [DEBUG] pyaarlo: backend: packet-in=
{ 'createdDate': '20240427',
  'deviceId': 'AAAAAAAAAAAA',
  'mediaObjectCount': 1,
  'ownerId': 'UUUU-111-66666666',
  'presignedLastImageUrl': 'https://arlolastimage-z1.arlo.com/444444444444444444444444444/UUUU-111-66666666/AAAAAAAAAAAA/lastImage.jpg?AWSAccessKeyId=AKIA2BAHQO5QZGD7VOMI&Expires=1714322184&Signature=Tvi6pLtzvQbIfO2jCEBaE4crjyk%3D',
  'resource': 'mediaUploadNotification',
  'uniqueId': 'UUUU-111-66666666_AAAAAAAAAAAA'}
2024-04-27 18:36:24,810 [DEBUG] pyaarlo: backend: sending mediaUploadNotification to AAAAAAAAAAAA
2024-04-27 18:36:24,811 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera BASE got mediaUploadNotification
2024-04-27 18:36:24,811 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got mediaUploadNotification event
2024-04-27 18:36:24,811 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera CAMERA got one mediaUploadNotification
2024-04-27 18:36:24,811 [DEBUG] pyaarlo: AAAAAAAAAAAA: mediaObjectCount: OLD 1
2024-04-27 18:36:24,811 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/presignedLastImageUrl=https://arlolastimage-z1.arlo
2024-04-27 18:36:24,812 [DEBUG] pyaarlo: AAAAAAAAAAAA: presignedLastImageUrl: NEW https://arlolastimage-z1.arlo.com/444444444444444444444444444/UXGX-176-6080
2024-04-27 18:36:24,812 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera -> thumbnail changed
2024-04-27 18:36:24,812 [DEBUG] pyaarlo: AAAAAAAAAAAA: turning recent ON for livingroom-camera
2024-04-27 18:36:24,813 [DEBUG] pyaarlo: backend: packet-in=
{ 'action': 'is',
  'from': 'AAAAAAAAAAAA',
  'properties': {'activityState': 'idle', 'dateStarted': 1714235785000},
  'resource': 'cameras/AAAAAAAAAAAA',
  'transId': 'AAAAAAAAAAAA!a7916456!1714235785'}
2024-04-27 18:36:24,813 [DEBUG] pyaarlo: backend: packet: device update
2024-04-27 18:36:24,813 [DEBUG] pyaarlo: backend: sending cameras/AAAAAAAAAAAA to AAAAAAAAAAAA
2024-04-27 18:36:24,813 [DEBUG] pyaarlo: backend: cameras/AAAAAAAAAAAA:AAAAAAAAAAAA bounded device!
2024-04-27 18:36:24,954 [DEBUG] urllib3.connectionpool: Starting new HTTPS connection (1): arlolastimage-z1.arlo.com:443
2024-04-27 18:36:25,012 [DEBUG] pyaarlo: backend: packet-in=
{ 'action': 'is',
  'from': 'AAAAAAAAAAAA',
  'properties': {'activityState': 'idle'},
  'resource': 'cameras/AAAAAAAAAAAA',
  'to': 'mediaserver:UUUU-111-66666666',
  'transId': 'All clients disconnectedAAAAAAAAAAAA_1714235748602'}
2024-04-27 18:36:25,012 [DEBUG] pyaarlo: backend: packet: device update
2024-04-27 18:36:25,012 [DEBUG] pyaarlo: backend: sending cameras/AAAAAAAAAAAA to AAAAAAAAAAAA
2024-04-27 18:36:25,012 [DEBUG] pyaarlo: backend: cameras/AAAAAAAAAAAA:AAAAAAAAAAAA bounded device!
2024-04-27 18:36:25,160 [DEBUG] urllib3.connectionpool: https://arlolastimage-z1.arlo.com:443 "GET /444444444444444444444444444/UUUU-111-66666666/AAAAAAAAAAAA/lastImage.jpg?AWSAccessKeyId=AKIA2BAHQO5QZGD7VOMI&Expires=1714322184&Signature=Tvi6pLtzvQbIfO2jCEBaE4crjyk%3D HTTP/1.1" 200 29529
2024-04-27 18:36:25,164 [DEBUG] pyaarlo: AAAAAAAAAAAA: updating image for livingroom-camera (04-27 18:35)
2024-04-27 18:36:25,164 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/lastImageSource=capture/04-27 18:35
2024-04-27 18:36:25,164 [DEBUG] pyaarlo: AAAAAAAAAAAA: lastImageSource: NEW capture/04-27 18:35
2024-04-27 18:36:25,165 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/presignedLastImageData=b'\xff\xd8\xff\xfe\x00\x10La
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: presignedLastImageData: NEW b'\xff\xd8\xff\xfe\x00\x10Lavc58.35.100\x00\xff\xdb\x00C\x00\x08\n\n\x0b\n\x0b\r
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera BASE got cameras/AAAAAAAAAAAA
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloBase/AAAAAAAAAAAA/activityState=idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera CAMERA got one cameras/AAAAAAAAAAAA
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: got a stream/recording stop
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: turning recent ON for livingroom-camera
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: removing streaming activity state
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: _event::idle::reqs='set()',local='set()',remote='set()'
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: child got cameras/AAAAAAAAAAAA event **
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: set:ArloCamera/AAAAAAAAAAAA/activityState=idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: NEW idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera BASE got cameras/AAAAAAAAAAAA
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera CAMERA got one cameras/AAAAAAAAAAAA
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: removing streaming activity state
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: _event::idle::reqs='set()',local='set()',remote='set()'
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: child got cameras/AAAAAAAAAAAA event **
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: livingroom-camera: object got cameras/AAAAAAAAAAAA event
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle
2024-04-27 18:36:25,174 [DEBUG] pyaarlo: AAAAAAAAAAAA: activityState: OLD idle

...

Camera outdoor-camera does not have an active stream
Camera livingroom-camera does not have an active stream
YpNo commented 2 months ago

I am trying to update the get_stream function by checking first if there is an active stream, retrieve and return the stream url if yes, and call _start_stream if not. But first, we need to know what is the URL Path for retrieving current streaming URL.

YpNo commented 1 month ago

Any help ? I published a post on the Arlo community forum to try getting any response about API endpoint for getting live stream status and the stream URL. but I don't know if we will have a feedback.

I've found a sip call when I launch the stream on the interface but I don't how to use it or how to convert it on a rtsp feed

YpNo commented 1 month ago

I didn't overcome this topic. Help needed.

Thanks.

twrecked commented 1 month ago

Sorry, I think I found the issue looking at another issue - to do with the glance cards in Home Assistant.

Can you try this diff:

Index: pyaarlo/camera.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/pyaarlo/camera.py b/pyaarlo/camera.py
--- a/pyaarlo/camera.py (revision 5f57e8b9a6a5c79ee000a53d462d0d032d0aed43)
+++ b/pyaarlo/camera.py (date 1716638333326)
@@ -432,16 +432,16 @@
             with self._lock:
                 if not self.has_user_request("recording"):
                     self._remote_users.add("recording")
-                    if not self.has_any_local_users:
-                        self._local_users.add("remote")
+                    # if not self.has_any_local_users:
+                    #     self._local_users.add("remote")
                 self._lock.notify_all()
                 self._dump_activities("_event::record")
         if activity == "userStreamActive":
             with self._lock:
                 if not self.has_user_request("streaming"):
                     self._remote_users.add("streaming")
-                    if not self.has_any_local_users:
-                        self._local_users.add("remote")
+                    # if not self.has_any_local_users:
+                    #     self._local_users.add("remote")
                 self._lock.notify_all()
                 self._dump_activities("_event::stream")
YpNo commented 1 month ago

@twrecked much better, it gets the stream ! BUT, now, when I stop the stream no event has been received.

YpNo commented 1 month ago

ERRATUM: in my little script it works well, I received the event on stop, but it doesn't on the arlo-streamer project. I am trying to get why. I'll keep you inform

YpNo commented 1 month ago

@twrecked you can consider that your patch solve the issue. Could you explain why adding the remote to the "_local_users" generates the issue ?

twrecked commented 1 month ago

Because pyaarlo would wrongly assume there was a stream URL if _local_users had anything in it.

All I can think is that Arlo has changed their back end. When I wrote this - a long time ago - I'm guessing we were automatically sent a stream URL when a remote started playback. ("Guess" is the word here, I would have tested it when I wrote it but too many things have happened since.) Thinking about this, I bet this changed around the time rtsp was deprecated for HLS and mpeg-dash.

I'll try to get an updated release out this week. I'm also trying to make the login/cloudflare error messages more meaningful, hopefully I can roll it into one.

YpNo commented 3 weeks ago

Hi @twrecked,

I've found a new bug I think. Should the url stream be converted from rtsps to rtsp ? I've got rtsps url :

2024-06-10 23:27:29,347 [DEBUG] pyaarlo: XXXXXXXXXX: already streaming: rtsps://arlostreaming19885-z1-prod.wowza.arlo.com:443/vzmodulelive/XXXXX....

Regards.

twrecked commented 3 weeks ago

We manually convert it to rtsps in the code:

https://github.com/twrecked/pyaarlo/blame/5f57e8b9a6a5c79ee000a53d462d0d032d0aed43/pyaarlo/camera.py#L352

Arlo always used to return a secure stream with the missing s at the end. What is going wrong?

YpNo commented 3 weeks ago

We manually convert it to rtsps in the code:

https://github.com/twrecked/pyaarlo/blame/5f57e8b9a6a5c79ee000a53d462d0d032d0aed43/pyaarlo/camera.py#L352

Arlo always used to return a secure stream with the missing s at the end. What is going wrong?

Oh sorry, I red the opposite last night 😶‍🌫️ Nothing special, I am working on the arlo-streamer project with ffmpeg proxing. The stream was slow with a lot of delay and I got stuck myself on this point thinking it should be the opposite 😅