1#!/usr/bin/env python3
2#
3#   Copyright 2016 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17#   Utilities that can be used for testing media related usecases.
18
19# Events dispatched from the RPC Server
20EVENT_PLAY_RECEIVED = "playReceived"
21EVENT_PAUSE_RECEIVED = "pauseReceived"
22EVENT_SKIP_NEXT_RECEIVED = "skipNextReceived"
23EVENT_SKIP_PREV_RECEIVED = "skipPrevReceived"
24
25# Passthrough Commands sent to the RPC Server
26CMD_MEDIA_PLAY = "play"
27CMD_MEDIA_PAUSE = "pause"
28CMD_MEDIA_SKIP_NEXT = "skipNext"
29CMD_MEDIA_SKIP_PREV = "skipPrev"
30
31# MediaMetaData keys. Keep them the same as in BluetoothMediaFacade.
32MEDIA_KEY_TITLE = "keyTitle"
33MEDIA_KEY_ALBUM = "keyAlbum"
34MEDIA_KEY_ARTIST = "keyArtist"
35MEDIA_KEY_DURATION = "keyDuration"
36MEDIA_KEY_NUM_TRACKS = "keyNumTracks"
37
38class PlaybackState:
39    PAUSE = 2
40    PLAY = 3
41
42def verifyEventReceived(log, device, event, timeout):
43    """
44    Verify if the event was received from the given device.
45    When a fromDevice talks to a toDevice and expects an event back,
46    this util function can be used to see if the toDevice posted it.
47    Args:
48        log:        The logging object
49        device:     The device to pop the event from
50        event:      The event we are interested in.
51        timeout:    The time in seconds before we timeout
52    Returns:
53        True        if the event was received
54        False       if we timed out waiting for the event
55    """
56    try:
57        device.ed.pop_event(event, timeout)
58    except Exception:
59        log.info(" {} Event Not received".format(event))
60        return False
61    log.info("Event Received : {}".format(event))
62    return True
63
64
65def send_media_passthrough_cmd(log,
66                               fromDevice,
67                               toDevice,
68                               cmd,
69                               expctEvent,
70                               timeout=1.0):
71    """
72    Send a media passthrough command from one device to another
73    via bluetooth.
74    Args:
75        log:        The logging object
76        fromDevice: The device to send the command from
77        toDevice:   The device the command is sent to
78        cmd:        The passthrough command to send
79        expctEvent: The expected event
80        timeout:    The time in seconds before we timeout, deafult = 1sec
81    Returns:
82        True        if the event was received
83        False       if we timed out waiting for the event
84    """
85    log.info("Sending passthru : {}".format(cmd))
86    fromDevice.droid.bluetoothMediaPassthrough(cmd)
87    return verifyEventReceived(log, toDevice, expctEvent, timeout)
88
89
90def log_metadata(log, metadata):
91    """
92    Log the Metadata to the console.
93    Args:
94        log:        The logging object
95        metadata:   Dictionary of the song's metadata
96    """
97    title = metadata[MEDIA_KEY_TITLE]
98    album = metadata[MEDIA_KEY_ALBUM]
99    artist = metadata[MEDIA_KEY_ARTIST]
100    duration = metadata[MEDIA_KEY_DURATION]
101    numTracks = metadata[MEDIA_KEY_NUM_TRACKS]
102    log.info("Playing Artist: {}, Album: {}, Title: {}".format(artist, album,
103                                                               title))
104    log.info("Duration: {}, NumTracks: {}".format(duration, numTracks))
105
106
107def compare_metadata(log, metadata1, metadata2):
108    """
109    Compares the Metadata between the two devices
110    Args:
111        log:        The logging object
112        metadata1    Media Metadata of device1
113        metadata2    Media Metadata of device2
114    Returns:
115        True        if the Metadata matches
116        False       if the Metadata do not match
117    """
118    log.info("Device1 metadata:")
119    log_metadata(log, metadata1)
120    log.info("Device2 metadata:")
121    log_metadata(log, metadata2)
122
123    if not (metadata1[MEDIA_KEY_TITLE] == metadata2[MEDIA_KEY_TITLE]):
124        log.info("Song Titles do not match")
125        return False
126
127    if not (metadata1[MEDIA_KEY_ALBUM] == metadata2[MEDIA_KEY_ALBUM]):
128        log.info("Song Albums do not match")
129        return False
130
131    if not (metadata1[MEDIA_KEY_ARTIST] == metadata2[MEDIA_KEY_ARTIST]):
132        log.info("Song Artists do not match")
133        return False
134
135    if not (metadata1[MEDIA_KEY_DURATION] == metadata2[MEDIA_KEY_DURATION]):
136        log.info("Song Duration do not match")
137        return False
138
139    if not (metadata1[MEDIA_KEY_NUM_TRACKS] == metadata2[MEDIA_KEY_NUM_TRACKS]
140    ):
141        log.info("Song Num Tracks do not match")
142        return False
143
144    return True
145
146
147def check_metadata(log, device1, device2):
148    """
149    Gets the now playing metadata from 2 devices and checks if they are the same
150    Args:
151        log:        The logging object
152        device1     Device 1
153        device2     Device 2
154    Returns:
155        True        if the Metadata matches
156        False       if the Metadata do not match
157    """
158    metadata1 = device1.droid.bluetoothMediaGetCurrentMediaMetaData()
159    if metadata1 is None:
160        return False
161
162    metadata2 = device2.droid.bluetoothMediaGetCurrentMediaMetaData()
163    if metadata2 is None:
164        return False
165    return compare_metadata(log, metadata1, metadata2)
166
167
168def isMediaSessionActive(log, device, mediaSession):
169    """
170    Checks if the passed mediaSession is active.
171    Used to see if the device is playing music.
172    Args:
173        log:            The logging object
174        device          Device to check
175        mediaSession    MediaSession to check if it is active
176    Returns:
177        True            if the given mediaSession is active
178        False           if the given mediaSession is not active
179    """
180    # Get a list of MediaSession tags (String) that is currently active
181    activeSessions = device.droid.bluetoothMediaGetActiveMediaSessions()
182    if len(activeSessions) > 0:
183        for session in activeSessions:
184            log.info(session)
185            if (session == mediaSession):
186                return True
187    log.info("No Media Sessions")
188    return False
189