Open DavidM42 opened 5 years ago
I found some resources for what to do with the bluetooth stack:
import dbus
#XX_XX_XX_XX_XX_XX is a placeholder for bt mac adress of connected device
#probs dict should yield same results as terminal command but in more structured format
#qdbus --system org.bluez /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/player0
bus = dbus.SystemBus()
player = bus.get_object("org.bluez", "/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/player0")
BT_Media_iface = dbus.Interface(player, dbus_interface="org.bluez.MediaPlayer1")
BT_Media_probs = dbus.Interface(player, "org.freedesktop.DBus.Properties")
probs = BT_Media_probs.GetAll("org.bluez.MediaPlayer1")
print(probs)
And this command for skipping the current song
dbus-send --system --type=method_call --dest=org.bluez /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/player0 org.bluez.MediaPlayer1.Next
The last word in the value can be:
as found in the reddit question.
I'm not that familiar with dbus so I couldn't figure out yet how to send the commands with the python library.
Now the thing I'm unsure with is how to integrate the metadata into the extisting rds services and the commands into the button service to use when BT is connected.
also just saw #29 . info here should help with this issue
Hello! First of all, thanks for your interest, second, there are so many good informations here, I'll have to read through them carefully when I get a slot of free time. Also, I wouldn't worry too much about integrations if I were in you, because I've got a good news as well: I'm thinking about re-writing the whole project in python, it would be much easier to integrate, and right now the project suffers from a variety of reliability inconsistencies when it comes to bluetooth audio playback (for some works, for others don't) probably due to it relying on system and bash scripts for detecting new devices upon connection. You want to help, you're very welcome! I'd suggest you to improve your python3 because we'll probably need it soon :)
That's some good news as python is my preferred language. I'd like to help as far as I can. Do you have any plan when you want to start the rewrite?
I got a working script to control BT media playback. It does not do anything for local playback as I only use bluetooth but it seems to work.
I replaced the mpradio-pushbutton-skip.py
in my local /bin/
folder with mine to utilize the existing service.
import RPi.GPIO as GPIO
import time
from subprocess import check_output, call
import re
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def get_mac():
device_cmd = "bt-device -l"
result = check_output(device_cmd, shell=True)
regex = "[(].*[)]"
mac = re.findall(regex, result)[0]
#print(mac)
return mac.replace(":","_").replace("(","").replace(")","")
#TODO refactor for less code repetition to just alter print and last command
last_play = True
def pause():
cmd_arr = ["dbus-send", "--system" , "--type=method_call", "--dest=org.bluez", "/org/bluez/hci0/dev_" + get_mac() + "/player0", "org.bluez.MediaPlayer1.Pause"]
global last_play
if last_play == False:
print("Play")
cmd_arr[5] = "org.bluez.MediaPlayer1.Play"
else:
print("Pause")
#inverse last play after command
last_play = not last_play
call(cmd_arr)
def skip():
print("skip")
global last_play
last_play = True
cmd_arr = ["dbus-send", "--system" , "--type=method_call", "--dest=org.bluez", "/org/bluez/hci0/dev_" + get_mac() + "/player0", "org.bluez.MediaPlayer1.Next"]
call(cmd_arr)
def previous():
print("previous")
#spotify start playing on previous command so removed
#global last_play
#last_play = True
cmd_arr = ["dbus-send", "--system" , "--type=method_call", "--dest=org.bluez", "/org/bluez/hci0/dev_" + get_mac() + "/player0", "org.bluez.MediaPlayer1.Previous"]
call(cmd_arr)
def shutdown():
print('shutdown')
call(["killall", "mpradio"])
call(["killall", "sox"])
call(["shutdown", "-h", "now"])
time.sleep(10)
state = True
max_delay = 1
shutdown_push_time = 5
last_time = time.time()
pulse_count = 0
while True:
new_state = GPIO.input(18)
if new_state == False and state == False and (time.time() - last_time) > shutdown_push_time:
#if button is still pressed after 5 seconds shutdown device
shutdown()
if new_state == False and state == True: #going from off to on
pulse_count += 1
state = new_state
last_time = time.time()
elif new_state and state == False: #on to off
state = True
if time.time() > (last_time + max_delay) and pulse_count > 0: #too long a delay so after end of sequence
if pulse_count == 1:
pause()
elif pulse_count == 2:
skip()
elif pulse_count == 3:
previous()
else:
pause()
pulse_count = 0
@DavidM42 I can't make precise schedule at the moment because everything's so "dynamic" in this period, but I probably would start with the bluetooth a2dp part to see if it makes sense.
So I've been laying down some "projectual ideas" and I think I'm going for this logic In python we can easily popen processes and attach to their stdin/stdout so I think it will also be possible to hotswap sources (players) and sinks (outputs) without having to restart
Nice. Seems good. pi_fm_adv should be the go to. From my testing it produces much better quality than the other driver. I still have a question regarding the "old" current implementation. How is the rds input handled? I'd like to write a test script to pipe Bluetooth song info into rds but I couldn't figure out the correct way.
@DavidM42 have a look at mpradio-legacyRDS.sh
, but basically it's a matter of piping your text like so: echo "PS $legacytitle" >/home/pi/rds_ctl
and pi_fm_adv reads polls the control pipe. more info about that in its repo
It's been a while since I've poked around on this, but I think I'll throw my hat into the ring this weekend. I am not the strongest Python coder, but I love the ideas you put together in that diagram @morrolinux, so I should be able to help cobble something together if you want to cooperate on a python branch.
Python also means we can rely on stronger id3
libraries. I'm quite excited to figure out how to interface with stdin
/stdout
of processes via popen
.
@DavidM42 nice discoveries RE: AVRCP! I'd tried but failed to scratch that itch a while ago :( I'll see what I can do to help now :)
@Hurricos Cool! since the last schematic I've changed the design just a bit on the remote controller part, but overall that's the thing. I'll update the schematic soon. This afternoon I'm going to open a new repo on github to share the current progress. (spoiler: core functionalities are already working!) :)
@Hurricos I've published a new repo for the python version here I'm currently putting the basis for a media indexer to feed to the playlist manager, I'll create an ad-hoc data structure and I'd like you to take care of the id3 stuff and filling-in the data structure with those data. just tell me if/when you start working on something, so that we can coordinate better
@DavidM42 same for you of course :)
I've got a few questions about the rewrite.
And concerning bluetooth rds I'm facing a bit of a non technical problem. I couldn't find any radio which has rds info besides the car but I won't be debugging on a pi in a car :D
I created a rough draft for the id3 tag reading. Was easy to implement thanks to the nice library mutagen it's in my fork here I would also suggest some kind of dependancy managment (a requirements.txt or setup.py to make it a module or something)
And regarding my pushbutton script. I tested it a few times in the last days and the recognition of pushes does not quite work as wanted. Double clicking leads to a skip and then pause -> the timing probably needs to probably be edited for it to be usable. Two other things I notices in my testing: There still is a noticable boot up time (not ideal for car use). Nothing game breaking but maybe we should evalutate a build with a more lightweight faster booting os or even docker container/resin os kind of OS. And lastly when I try to connect, the device often asks my phone for repairing which is kind of odd and annoying (but maybe an effect of the read only setting?)
- Which python version is the minimum supported?
Well I haven't set a requirement as of yet, but of course it must run on Raspbian 9 which comes with python 3.5 so if it runs on it, it's fine to me. Portability on other platofrms is not really a need because of hardware constraints in FM transmission with PiFmAdv.
- Any requirements concerning additional python libraries? License wise restricted, maybe as few dependancies as possible or whatever?
I'm not a big expert on licenses, so I guess anything different from GPL will have to be checked for requirements for integration in the project. But I guess it should generally be fine if we link it in the README. As few dependencies as possible is always a nice goal to acheive, unless it results in the code being utterly convoluted and unnecessarely complicated... then I would say who cares, let's not make it an unreadable mess.
- Could you explain how to setup a usable dev environment. So linux of course but any other reccomendations?
I'm not really sure what you mean by that. As of now, no non-standard python libraries are being used and I'm not using a python environment. If you run mpradio.py on your computer, it will play "storage" files on speakers instead of attempting to stream on FM
And concerning bluetooth rds I'm facing a bit of a non technical problem. I couldn't find any radio which has rds info besides the car but I won't be debugging on a pi in a car :D
Oh but don't worry about that, it will probably won't be needed. I'll put the basis for the RDS updater module and running it on something that's not a Raspberry Pi will just print out RDS info to the screen so that we'll all be able to work comfortably
I created a rough draft for the id3 tag reading. Was easy to implement thanks to the nice library mutagen it's in my fork here I would also suggest some kind of dependancy managment (a requirements.txt or setup.py to make it a module or something)
Cool. I would start with a requirements.txt just because we're in a really early stage of the work, then make it a module with the very first release, but really, if you start to work on the setup.py I won't say no
There still is a noticable boot up time (not ideal for car use). Nothing game breaking but maybe we should evalutate a build with a more lightweight faster booting os or even docker container/resin os kind of OS
Are you using a pre-built mpradio image? or maybe you're running on raspbian 9 with the "classic" mpradio installed? because it has lots of systemd unit dependencies and it doesn't really work out to be fast. With mpradio-py I would only check for the bluetooth interface to be available and let mpradio.py
start all the needed services
And lastly when I try to connect, the device often asks my phone for repairing which is kind of odd and annoying (but maybe an effect of the read only setting?)
Most likely yes. But again, now I think you're working on the "classic" mpradio. Here we should start from scratch
@DavidM42 I'm waiting for your PR about id3 data the new repo, which has now a skeleton to be placed to
So first of all thanks for this really cool project. The only two things I'm still missing from this is the possibility to skip songs/pause on a bt client player device (like a phone) and the forwarding of the currently playing track into rds. I've done some reasearch because I'd like to help integrating them via PR but I don't understand the project enough for now. The thing needed for this is probably the AVCRP protocol to control media playback and get more info from apps integrating into this protocol on phones. I found out that you can access this information/send info to bluez via the dbus but I could not get it done myself (partly because of bluez documentation beeing sparse). Does anybody know more about this topic?