Made a script to control VLC with HDMI-CEC and my TV's remote

The Raspberry Pi is a series of credit card-sized single-board computers developed in the United Kingdom by the Raspberry Pi Foundation to promote the teaching of basic computer science in schools and developing countries.

Post Reply
User avatar
/RaspberryPi
Corporate
Posts: 2449
Joined: Wed Jun 05, 2019 1:29 am

Made a script to control VLC with HDMI-CEC and my TV's remote

Post by /RaspberryPi »


A couple of days ago I asked for help in setting up a remote control to control VLC on my pi running raspbian. Due to my USB IR receiver being pretty old, and some other module recieving IR inputs, I wasn't able to use it. Luckily u/doomygloomytunes told me about HDMI-CEC. This was really cool news to me, because it meant I could just use my TV's normal remote control, but sadly there wasn't an obvious way to use it to control VLC. But through some digging, I learned about VLC's RC interface and was able to use that along with cec-client from the cec-utils package to receive key inputs from my TV, and then send the command to VLC.

It's pretty straight-forward, but I have a suspicion the information sent from different TVs might be unique, so I can't really call this a tutorial. But I figured it might help someone get started, keeping a few things in mind:
  • You need to map your TV's keys on your own
  • You need to launch vlc with --rc-host=host:port where host is the address you wish to bind to (should be localhost) and port can be anything above 1024 (I use 12345)

The first thing I did was find out how to parse the HDMI-CEC information to read key presses. The cool thing is that it offers a lot of information per key press, such as this:

DEBUG: [ 178259] SetCurrentButton select (0) D:0ms cur:b33fdcec DEBUG: [ 178259] key pressed: select (0) current(ff) duration(0) DEBUG: [ 178259] Changed key select (0) D:0ms cur:ff DEBUG: [ 178259] key pressed: select (0, 0) DEBUG: [ 178259] CheckKeypressTimeout T:180812.027 DEBUG: [ 178259] Key select: idle (duration:0) (0) timeout:31502356ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 178259] >> TV (0) -> Recorder 1 (1): user control pressed (44) DEBUG: [ 178552] CLinuxCECAdapterCommunication::Process - ioctl CEC_RECEIVE - rx_status=01 len=2 addr=01 opcode=45 DEBUG: [ 178552] key released: select (0) D:293ms Theoretically, I could use the various information to be able to handle press-and-hold situations, such as if I wanted to press a button and hold it to continuously seek. Or, maybe if I wanted to hit the fast-forward button subsequent times to increase the playback rate 2x, 4x, 8x, etc. with each press. But for now I don't really require that fine of control so I just needed to find out how to simply find which button was pressed. Luckily for me, there was a convenient case-sensitive pattern to match for each key input.

So then to find my key names from my TV, I ran cec-client in a loop and grep'd the case sensitive pattern that appears before each key press. I ran cec-client | while read line ; do echo $line ; done to find what pattern precedes each key press. For me it was Key (with space included). The -d option specifies what log level to show, which in this case will be 16 for 'DEBUG' because the key titles showed up as debug messages for me; this just helps speed things up a bit since it won't have to parse through other information. Throw it together, and I ran this loop and pressed the buttons to find all the key names.

cec-client -d 16 | while read key ; do grep "Key " ; done That gave me this output:

DEBUG: [ 13556] Key up: idle (duration:0) (1) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 14115] Key right: idle (duration:0) (4) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 14564] Key down: idle (duration:0) (2) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 14949] Key left: idle (duration:0) (3) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 15470] Key select: idle (duration:0) (0) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 17187] Key forward: idle (duration:0) (4b) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 17638] Key backward: idle (duration:0) (4c) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 18143] Key pause: idle (duration:0) (46) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 18554] Key rewind: idle (duration:0) (48) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 75297] Key stop: idle (duration:0) (45) timeout:21486612ms (rel:1000,rep:0,prs:500,rel:0) DEBUG: [ 75538] Key stop: idle (duration:0) (45) timeout:21486612ms (rel:759,rep:0,prs:259,rel:0) DEBUG: [ 75734] Key Fast forward: idle (duration:0) (49) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 76296] Key play: idle (duration:0) (44) timeout:21486612ms (rel:500,rep:0,prs:500,rel:0) DEBUG: [ 76662] Key rewind: idle (duration:0) (48) timeout:21486612ms (rel:499,rep:0,prs:499,rel:0) The man page for 'cec-client' doesn't tell you what the log levels are, but instead tells you to find them in cectypes.h:

typedef enum cec_log_level { CEC_LOG_ERROR = 1, CEC_LOG_WARNING = 2, CEC_LOG_NOTICE = 4, CEC_LOG_TRAFFIC = 8, CEC_LOG_DEBUG = 16, CEC_LOG_ALL = 31 } cec_log_level; Once I found all the corresponding key values, I just used those values in a case-switch statement with wildcard matching in a bash script to send the corresponding rc command to VLC via netcat. Again, the case-sensitivity of it printing 'Key' with a capital 'k' before each key came in really handy, because othwerwise it would match to all those other messages pertaining to a certain key and I'd have to create a lot more conditional tests to know what to do.

#!/bin/bash VLC_HOST=localhost VLC_PORT=12345 EXIT_NC_SECONDS=1 send_command() { echo "$1" | netcat $VLC_HOST $VLC_PORT -q $EXIT_NC_SECONDS &> /dev/null sleep 1s } cec-client -d 16 | while read key ; do case $key in *"Key pause"*) echo "Pause Pressed" send_command pause ;; *"Key play"*) echo "Play Pressed" send_command pause ;; *"Key stop"*) echo "Stop Pressed" send_command normal ;; *"Key forward"*) echo "Next Pressed" send_command next ;; *"Key backward"*) echo "Previous Pressed" send_command prev ;; *"Key rewind"*) echo "Reverse Pressed" send_command rewind ;; *"Key Fast forward"*) echo "Forward Pressed" send_command fast_forward ;; *"Key up"*) echo "Up Pressed" send_command "seek +300" ;; *"Key right"*) echo "Right Pressed" send_command "seek +5" ;; *"Key down"*) echo "Down Pressed" send_command "seek -300" ;; *"Key left"*) echo "Left Pressed" send_command "seek -5" ;; *"Key select"*) echo "Select Pressed" send_command fullscreen ;; *"Key exit"*) echo "Exit Pressed" send_command shutdown ;; esac done Now I can easily control my VLC playback via my TV's remote. Instead of relying on the extra information about when the button was released and for what duration it was held, I just make sure that the send_command function sleeps for a second. That way if I accidentally hold the skip button for too long, it creates enough of a delay that it won't send 'next' to VLC twice and double-skip.

Anyway, I'm glad I was told about HDMI-CEC and think it's pretty cool. Hopefully this might help someone else.
submitted by /u/kennbr
[link] [comments]

Source: https://www.reddit.com/r/raspberry_pi/c ... ec_and_my/
/RaspberryPi
Post Reply

Return to “Raspberry Pi Forum”