Skip to content

Commit

Permalink
'DUMPSYS_AUDIO_*' -> 'STREAM_MUSIC_*' (#87)
Browse files Browse the repository at this point in the history
* 'DUMPSYS_AUDIO_*' -> 'STREAM_MUSIC_*'

* Add 'CMD_STREAM_MUSIC'

* Fix comments

* Update/fix tests; fix wake_lock_size bug

* Add newline at end of file
  • Loading branch information
JeffLIrion committed Sep 6, 2019
1 parent b50f034 commit 06b06f7
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 139 deletions.
45 changes: 24 additions & 21 deletions androidtv/androidtv.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def update(self):
"""
# Get the properties needed for the update
screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume = self.get_properties(lazy=True)
screen_on, awake, audio_state, wake_lock_size, current_app, media_session_state, device, is_volume_muted, volume = self.get_properties(lazy=True)

# Get the volume (between 0 and 1)
volume_level = self._volume_level(volume)
Expand Down Expand Up @@ -192,14 +192,14 @@ def get_properties(self, lazy=False):
Whether or not the device is on, or ``None`` if it was not determined
awake : bool, None
Whether or not the device is awake (screensaver is not running), or ``None`` if it was not determined
audio_state : str, None
The audio state, as determined from "dumpsys audio", or ``None`` if it was not determined
wake_lock_size : int, None
The size of the current wake lock, or ``None`` if it was not determined
current_app : str, None
The current app property, or ``None`` if it was not determined
media_session_state : int, None
The state from the output of ``dumpsys media_session``, or ``None`` if it was not determined
audio_state : str, None
The audio state, as determined from "dumpsys audio", or ``None`` if it was not determined
device : str, None
The current playback device, or ``None`` if it was not determined
is_volume_muted : bool, None
Expand All @@ -209,11 +209,12 @@ def get_properties(self, lazy=False):
"""
output = self.adb.shell(constants.CMD_SCREEN_ON + (constants.CMD_SUCCESS1 if lazy else constants.CMD_SUCCESS1_FAILURE0) + " && " +
constants.CMD_AUDIO_STATE + " && " +
constants.CMD_AWAKE + (constants.CMD_SUCCESS1 if lazy else constants.CMD_SUCCESS1_FAILURE0) + " && " +
constants.CMD_WAKE_LOCK_SIZE + " && " +
constants.CMD_CURRENT_APP + " && (" +
constants.CMD_MEDIA_SESSION_STATE + " || echo) && " +
"dumpsys audio")
constants.CMD_STREAM_MUSIC)
_LOGGER.debug("Android TV %s update response: %s", self.host, output)

# ADB command was unsuccessful
Expand All @@ -222,43 +223,45 @@ def get_properties(self, lazy=False):

# `screen_on` property
if not output:
return False, False, -1, None, None, None, None, None, None
return False, False, None, -1, None, None, None, None, None
screen_on = output[0] == '1'

# `awake` property
if len(output) < 2:
return screen_on, False, -1, None, None, None, None, None, None
return screen_on, False, None, -1, None, None, None, None, None
awake = output[1] == '1'

# `audio_state` property
if len(output) < 3:
return screen_on, awake, None, -1, None, None, None, None, None
audio_state = self._audio_state(output[2])

lines = output.strip().splitlines()

# `wake_lock_size` property
if len(lines[0]) < 3:
return screen_on, awake, -1, None, None, None, None, None, None
if len(lines[0]) < 4:
return screen_on, awake, audio_state, -1, None, None, None, None, None
wake_lock_size = self._wake_lock_size(lines[0])

# `current_app` property
if len(lines) < 2:
return screen_on, awake, wake_lock_size, None, None, None, None, None, None
return screen_on, awake, audio_state, wake_lock_size, None, None, None, None, None
current_app = self._current_app(lines[1])

# `media_session_state` property
if len(lines) < 3:
return screen_on, awake, wake_lock_size, current_app, None, None, None, None, None
return screen_on, awake, audio_state, wake_lock_size, current_app, None, None, None, None
media_session_state = self._media_session_state(lines[2], current_app)

# "dumpsys audio" output
# "STREAM_MUSIC" block
if len(lines) < 4:
return screen_on, awake, wake_lock_size, current_app, media_session_state, None, None, None, None

# reconstruct the output of `adb shell dumpsys audio`
dumpsys_audio = "\n".join(lines[3:])
return screen_on, awake, audio_state, wake_lock_size, current_app, media_session_state, None, None, None

# `audio_state` property
audio_state = self._audio_state(dumpsys_audio)
# reconstruct the output of `constants.CMD_STREAM_MUSIC`
stream_music_raw = "\n".join(lines[3:])

# the "STREAM_MUSIC" block from `adb shell dumpsys audio`
stream_music = self._get_stream_music(dumpsys_audio)
stream_music = self._get_stream_music(stream_music_raw)

# `device` property
device = self._device(stream_music)
Expand All @@ -269,7 +272,7 @@ def get_properties(self, lazy=False):
# `is_volume_muted` property
is_volume_muted = self._is_volume_muted(stream_music)

return screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume
return screen_on, awake, audio_state, wake_lock_size, current_app, media_session_state, device, is_volume_muted, volume

def get_properties_dict(self, lazy=True):
"""Get the properties needed for Home Assistant updates and return them as a dictionary.
Expand All @@ -286,14 +289,14 @@ def get_properties_dict(self, lazy=True):
``'media_session_state'``, ``'audio_state'``, ``'device'``, ``'is_volume_muted'``, and ``'volume'``
"""
screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume = self.get_properties(lazy=lazy)
screen_on, awake, audio_state, wake_lock_size, current_app, media_session_state, device, is_volume_muted, volume = self.get_properties(lazy=lazy)

return {'screen_on': screen_on,
'awake': awake,
'audio_state': audio_state,
'wake_lock_size': wake_lock_size,
'current_app': current_app,
'media_session_state': media_session_state,
'audio_state': audio_state,
'device': device,
'is_volume_muted': is_volume_muted,
'volume': volume}
Expand Down
56 changes: 23 additions & 33 deletions androidtv/basetv.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,17 +308,11 @@ def audio_state(self):
Returns
-------
str, None
The audio state, as determined from the ADB shell command ``dumpsys audio``, or ``None`` if it could not be determined
The audio state, as determined from the ADB shell command :py:const:`androidtv.constants.CMD_AUDIO_STATE`, or ``None`` if it could not be determined
"""
audio_state_response = self.adb.shell(constants.CMD_AUDIO_STATE)
if audio_state_response is None:
return None
if audio_state_response == '1':
return constants.STATE_PAUSED
if audio_state_response == '2':
return constants.STATE_PLAYING
return constants.STATE_IDLE
return self._audio_state(audio_state_response)

@property
def available(self):
Expand Down Expand Up @@ -477,32 +471,26 @@ def wake_lock_size(self):
# #
# ======================================================================= #
@staticmethod
def _audio_state(dumpsys_audio_response):
"""Parse the :attr:`audio_state` property from the output of ``adb shell dumpsys audio``.
def _audio_state(audio_state_response):
"""Parse the :attr:`audio_state` property from the output of the command :py:const:`androidtv.constants.CMD_AUDIO_STATE`.
Parameters
----------
dumpsys_audio_response : str, None
The output of ``adb shell dumpsys audio``
audio_state_response : str, None
The output of the command :py:const:`androidtv.constants.CMD_AUDIO_STATE`
Returns
-------
str, None
The audio state, or ``None`` if it could not be determined
"""
if not dumpsys_audio_response:
if not audio_state_response:
return None

for line in dumpsys_audio_response.splitlines():
if 'OpenSL ES AudioPlayer (Buffer Queue)' in line:
# ignore this line which can cause false positives for some apps (e.g. VRV)
continue
if 'started' in line:
return constants.STATE_PLAYING
if 'paused' in line:
return constants.STATE_PAUSED

if audio_state_response == '1':
return constants.STATE_PAUSED
if audio_state_response == '2':
return constants.STATE_PLAYING
return constants.STATE_IDLE

@staticmethod
Expand Down Expand Up @@ -579,27 +567,27 @@ def _device(stream_music):

return None

def _get_stream_music(self, dumpsys_audio_response=None):
"""Get the ``STREAM_MUSIC`` block from ``adb shell dumpsys audio``.
def _get_stream_music(self, stream_music_raw=None):
"""Get the ``STREAM_MUSIC`` block from the output of the command :py:const:`androidtv.constants.CMD_STREAM_MUSIC`.
Parameters
----------
dumpsys_audio_response : str, None
The output of ``adb shell dumpsys audio``
stream_music_raw : str, None
The output of the command :py:const:`androidtv.constants.CMD_STREAM_MUSIC`
Returns
-------
str, None
The ``STREAM_MUSIC`` block from ``adb shell dumpsys audio``, or ``None`` if it could not be determined
The ``STREAM_MUSIC`` block from the output of :py:const:`androidtv.constants.CMD_STREAM_MUSIC`, or ``None`` if it could not be determined
"""
if not dumpsys_audio_response:
dumpsys_audio_response = self.adb.shell("dumpsys audio")
if not stream_music_raw:
stream_music_raw = self.adb.shell(constants.CMD_STREAM_MUSIC)

if not dumpsys_audio_response:
if not stream_music_raw:
return None

matches = re.findall(constants.STREAM_MUSIC_REGEX_PATTERN, dumpsys_audio_response, re.DOTALL | re.MULTILINE)
matches = re.findall(constants.STREAM_MUSIC_REGEX_PATTERN, stream_music_raw, re.DOTALL | re.MULTILINE)
if matches:
return matches[0]

Expand Down Expand Up @@ -747,7 +735,9 @@ def _wake_lock_size(wake_lock_size_response):
"""
if wake_lock_size_response:
return int(wake_lock_size_response.split("=")[1].strip())
wake_lock_size_matches = constants.REGEX_WAKE_LOCK_SIZE.search(wake_lock_size_response)
if wake_lock_size_matches:
return int(wake_lock_size_matches.group('size'))

return None

Expand Down
4 changes: 4 additions & 0 deletions androidtv/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#: Determine if the device is on
CMD_SCREEN_ON = "dumpsys power | grep 'Display Power' | grep -q 'state=ON'"

#: Get the "STREAM MUSIC" block from ``dumpsys audio``
CMD_STREAM_MUSIC = r"dumpsys audio | grep '\- STREAM_MUSIC:' -A 12"

#: Get the wake lock size
CMD_WAKE_LOCK_SIZE = "dumpsys power | grep Locks | grep 'size='"

Expand Down Expand Up @@ -259,6 +262,7 @@

# Regular expressions
REGEX_MEDIA_SESSION_STATE = re.compile(r"state=(?P<state>[0-9]+)", re.MULTILINE)
REGEX_WAKE_LOCK_SIZE = re.compile(r"size=(?P<size>[0-9]+)")

# Regular expression patterns
DEVICE_REGEX_PATTERN = r"Devices: (.*?)\W"
Expand Down
Loading

0 comments on commit 06b06f7

Please sign in to comment.