use a dict instead of a series of ifs (+6 squashed commits)
Squashed commits:
[90f2024] fix import order
[0edd321] add a few docstrings
[77a0ac0] wip
[adcf159] wip
[96cbd67] wip
[d8bfbab] wip (+1 squashed commit)
Squashed commits:
[43b4d66] wip (+2 squashed commits)
Squashed commits:
[3dafaa8] wip
[5844026] wip (+1 squashed commit)
Squashed commits:
[4cbb35a] wip (+1 squashed commit)
Squashed commits:
[4d2b6d3] wip (+4 squashed commits)
Squashed commits:
[f2da510] wip
[318c119] wip
[923b4eb] wip
[9d46365] wip

use a dict instead of a series of ifs (+6 squashed commits)
Squashed commits:
[90f2024] fix import order
[0edd321] add a few docstrings
[77a0ac0] wip
[adcf159] wip
[96cbd67] wip
[d8bfbab] wip
diff --git a/examples/avrcp_as_sink.html b/examples/avrcp_as_sink.html
new file mode 100644
index 0000000..7c96744
--- /dev/null
+++ b/examples/avrcp_as_sink.html
@@ -0,0 +1,274 @@
+<html>
+
+<head>
+    <style>
+        * {
+            font-family: sans-serif;
+        }
+    </style>
+</head>
+<body>
+    Server Port <input id="port" type="text" value="8989"></input> <button id="connectButton" onclick="connect()">Connect</button><br>
+    <div id="socketState"></div>
+    <br>
+    <div id="buttons"></div><br>
+    <hr>
+    <button onclick="onGetPlayStatusButtonClicked()">Get Play Status</button><br>
+    <div id="getPlayStatusResponseTable"></div>
+    <hr>
+    <button onclick="onGetElementAttributesButtonClicked()">Get Element Attributes</button><br>
+    <div id="getElementAttributesResponseTable"></div>
+    <hr>
+    <table>
+        <tr>
+            <b>VOLUME</b>:
+            <button onclick="onVolumeDownButtonClicked()">-</button>
+            <button onclick="onVolumeUpButtonClicked()">+</button>&nbsp;
+            <span id="volumeText"></span><br>
+        </tr>
+        <tr>
+            <td><b>PLAYBACK STATUS</b></td><td><span id="playbackStatusText"></span></td>
+        </tr>
+        <tr>
+            <td><b>POSITION</b></td><td><span id="positionText"></span></td>
+        </tr>
+        <tr>
+            <td><b>TRACK</b></td><td><span id="trackText"></span></td>
+        </tr>
+        <tr>
+            <td><b>ADDRESSED PLAYER</b></td><td><span id="addressedPlayerText"></span></td>
+        </tr>
+        <tr>
+            <td><b>UID COUNTER</b></td><td><span id="uidCounterText"></span></td>
+        </tr>
+        <tr>
+            <td><b>SUPPORTED EVENTS</b></td><td><span id="supportedEventsText"></span></td>
+        </tr>
+        <tr>
+            <td><b>PLAYER SETTINGS</b></td><td><div id="playerSettingsTable"></div></td>
+        </tr>
+    </table>
+    <script>
+        const portInput = document.getElementById("port")
+        const connectButton = document.getElementById("connectButton")
+        const socketState = document.getElementById("socketState")
+        const volumeText = document.getElementById("volumeText")
+        const positionText = document.getElementById("positionText")
+        const trackText = document.getElementById("trackText")
+        const playbackStatusText = document.getElementById("playbackStatusText")
+        const addressedPlayerText = document.getElementById("addressedPlayerText")
+        const uidCounterText = document.getElementById("uidCounterText")
+        const supportedEventsText = document.getElementById("supportedEventsText")
+        const playerSettingsTable = document.getElementById("playerSettingsTable")
+        const getPlayStatusResponseTable = document.getElementById("getPlayStatusResponseTable")
+        const getElementAttributesResponseTable = document.getElementById("getElementAttributesResponseTable")
+        let socket
+        let volume = 0
+
+        const keyNames = [
+            "SELECT",
+            "UP",
+            "DOWN",
+            "LEFT",
+            "RIGHT",
+            "RIGHT_UP",
+            "RIGHT_DOWN",
+            "LEFT_UP",
+            "LEFT_DOWN",
+            "ROOT_MENU",
+            "SETUP_MENU",
+            "CONTENTS_MENU",
+            "FAVORITE_MENU",
+            "EXIT",
+            "NUMBER_0",
+            "NUMBER_1",
+            "NUMBER_2",
+            "NUMBER_3",
+            "NUMBER_4",
+            "NUMBER_5",
+            "NUMBER_6",
+            "NUMBER_7",
+            "NUMBER_8",
+            "NUMBER_9",
+            "DOT",
+            "ENTER",
+            "CLEAR",
+            "CHANNEL_UP",
+            "CHANNEL_DOWN",
+            "PREVIOUS_CHANNEL",
+            "SOUND_SELECT",
+            "INPUT_SELECT",
+            "DISPLAY_INFORMATION",
+            "HELP",
+            "PAGE_UP",
+            "PAGE_DOWN",
+            "POWER",
+            "VOLUME_UP",
+            "VOLUME_DOWN",
+            "MUTE",
+            "PLAY",
+            "STOP",
+            "PAUSE",
+            "RECORD",
+            "REWIND",
+            "FAST_FORWARD",
+            "EJECT",
+            "FORWARD",
+            "BACKWARD",
+            "ANGLE",
+            "SUBPICTURE",
+            "F1",
+            "F2",
+            "F3",
+            "F4",
+            "F5",
+        ]
+
+        document.addEventListener('keydown', onKeyDown)
+        document.addEventListener('keyup', onKeyUp)
+
+        const buttons = document.getElementById("buttons")
+        keyNames.forEach(name => {
+            const button = document.createElement("BUTTON")
+            button.appendChild(document.createTextNode(name))
+            button.addEventListener("mousedown", event => {
+                send({type: 'send-key-down', key: name})
+            })
+            button.addEventListener("mouseup", event => {
+                send({type: 'send-key-up', key: name})
+            })
+            buttons.appendChild(button)
+        })
+
+        updateVolume(0)
+
+        function connect() {
+            socket = new WebSocket(`ws://localhost:${portInput.value}`);
+            socket.onopen = _ => {
+                socketState.innerText = 'OPEN'
+                connectButton.disabled = true
+            }
+            socket.onclose = _ => {
+                socketState.innerText = 'CLOSED'
+                connectButton.disabled = false
+            }
+            socket.onerror = (error) => {
+                socketState.innerText = 'ERROR'
+                console.log(`ERROR: ${error}`)
+                connectButton.disabled = false
+            }
+            socket.onmessage = (message) => {
+                onMessage(JSON.parse(message.data))
+            }
+        }
+
+        function send(message) {
+            if (socket && socket.readyState == WebSocket.OPEN) {
+                socket.send(JSON.stringify(message))
+            }
+        }
+
+        function hmsText(position) {
+            const h_1 = 1000 * 60 * 60
+            const h = Math.floor(position / h_1)
+            position -= h * h_1
+            const m_1 = 1000 * 60
+            const m = Math.floor(position / m_1)
+            position -= m * m_1
+            const s_1 = 1000
+            const s = Math.floor(position / s_1)
+            position -= s * s_1
+
+            return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}:${position}`
+        }
+
+        function setTableHead(table, columns) {
+            let thead = table.createTHead()
+            let row = thead.insertRow()
+            for (let column of columns) {
+                let th = document.createElement("th")
+                let text = document.createTextNode(column)
+                th.appendChild(text)
+                row.appendChild(th)
+            }
+        }
+
+        function createTable(rows) {
+            const table = document.createElement("table")
+
+            if (rows.length != 0) {
+                columns = Object.keys(rows[0])
+                setTableHead(table, columns)
+            }
+            for (let element of rows) {
+                let row = table.insertRow()
+                for (key in element) {
+                    let cell = row.insertCell()
+                    let text = document.createTextNode(element[key])
+                    cell.appendChild(text)
+                }
+            }
+            return table
+        }
+
+        function onMessage(message) {
+            console.log(message)
+            if (message.type == "set-volume") {
+                updateVolume(message.params.volume)
+            } else if (message.type == "supported-events") {
+                supportedEventsText.innerText = JSON.stringify(message.params.events)
+            } else if (message.type == "playback-position-changed") {
+                positionText.innerText = hmsText(message.params.position)
+            } else if (message.type == "playback-status-changed") {
+                playbackStatusText.innerText = message.params.status
+            } else if (message.type == "player-settings-changed") {
+                playerSettingsTable.replaceChildren(message.params.settings)
+            } else if (message.type == "track-changed") {
+                trackText.innerText = message.params.identifier
+            } else if (message.type == "addressed-player-changed") {
+                addressedPlayerText.innerText = JSON.stringify(message.params.player)
+            } else if (message.type == "uids-changed") {
+                uidCounterText.innerText = message.params.uid_counter
+            } else if (message.type == "get-play-status-response") {
+                getPlayStatusResponseTable.replaceChildren(message.params)
+            } else if (message.type == "get-element-attributes-response") {
+                getElementAttributesResponseTable.replaceChildren(createTable(message.params))
+            }
+        }
+
+        function updateVolume(newVolume) {
+            volume = newVolume
+            volumeText.innerText = `${volume} (${Math.round(100*volume/0x7F)}%)`
+        }
+
+        function onKeyDown(event) {
+            console.log(event)
+            send({ type: 'send-key-down', key: event.key })
+        }
+
+        function onKeyUp(event) {
+            console.log(event)
+            send({ type: 'send-key-up', key: event.key })
+        }
+
+        function onVolumeUpButtonClicked() {
+            updateVolume(Math.min(volume + 5, 0x7F))
+            send({ type: 'set-volume', volume })
+        }
+
+        function onVolumeDownButtonClicked() {
+            updateVolume(Math.max(volume - 5, 0))
+            send({ type: 'set-volume', volume })
+        }
+
+        function onGetPlayStatusButtonClicked() {
+            send({ type: 'get-play-status', volume })
+        }
+
+        function onGetElementAttributesButtonClicked() {
+            send({ type: 'get-element-attributes' })
+        }
+</script>
+</body>
+
+</html>
\ No newline at end of file