Raspberry Pi freezes when python starts to play - python

I've written a program in python, on my Mac, which I intend to run on a Raspberry Pi.
It includes a background picture that changes, and a button that starts/stops music playing.
The program uses pygame.
On the Mac it runs exactly as I expect it to do.
But when I run it on the Pi, and the play button is pressed, the whole program freezes for 25 - 30 seconds (the images stop changing, can't ctrl+alt+f to a different login) with no sound. After the freeze the program resumes, sound start playing ....
There's nothing logged in /var/log/syslog ....
In the main object for the program I initialise the mixer.
def __init__(self):
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.mixer.init()
pygame.init()
Then the play button in the program calls this method to toggle the button image between a play and stop icon, and start the current tune (the media files are ogg files called 001.ogg, 002.ogg etc):
def clickButtonPlay(self):
self.buttonPlay+=1
if self.buttonPlay > 2:
self.buttonPlay=1
self.drawButtonPlay()
if self.buttonPlay == 1:
self.song.stop()
else:
newTune = "tunes/%03d.ogg" %self.tuneNo
self.song = pygame.mixer.Sound(newTune)
self.song.play()
Any ideas what's causing the freeze?

Doh!Should have used pygame.mixer.music, not pygame.mixer.Sound.

Related

How can I keep my Python script focused while running a video game that wants to take window focus?

I've written a script in python that takes input from my webcam to control my desktop's keyboard and mouse using hand gestures with the intention of using it to play video games with gesture control.
The gesture control works perfectly but I've run into a problem that whenever I boot up any games they instantly want to take window focus and my script no longer runs. Is there a way to keep focus on two windows or have my script run in the background?

python-vlc: Exit the player programatically

I'm trying to play a video using VLC, and close the window after the video is finished. However, I can't close the player window. I tried releasing instances of the player and media, but it doesn't work. And I couldn't find anything else in the API documentation.
Note that I don't want to terminate the whole application after the player finished, so sys.exit is not an option.
The following code is what I'm doing.
import vlc
VIDEO_PATH="/path/to/video.mp4"
def get_end_callback(mediaplayer):
def end_callback(event):
print("End of playing reached")
mediaplayer.stop()
mediaplayer.get_media().release()
mediaplayer.release()
mediaplayer.get_instance().release()
return end_callback
def play():
vlc_instance = vlc.Instance(["--no-xlib"])
media_player = vlc.MediaPlayer(vlc_instance, VIDEO_PATH)
media_player.play()
event_manager = media_player.event_manager()
event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, get_end_callback(media_player))
play()
input("press Enter to exit")
I'm testing it with python=3.9, python-vlc=3.0.12118, vlc=3.0.9.2, on Ubuntu=20.04. I also tried another machine with older OS and older VLC.
So LibVLC will spawn a window to draw on, if you don't provide one. You don't want that, as you won't be able to manage it easily.
Before calling media_player.play(), you want to call media_player.set_hwnd(window.handle) (for Windows) / media_player.set_xwindow(window.xid) (for Linux) with a window handle.
Creating and managing and deleting this window is up to you and it does not have to be your main window of your app.
Here you can find more complete yet minimal samples with Qt and GTK frameworks https://github.com/oaubert/python-vlc/tree/master/examples

Pygame display init on headless Raspberry Pi Zero (Raspbian Buster Lite)

I have Pi Zero running Raspbian Buster Lite, there's no display attached. It runs a python program at startup (crontab #reboot entry), something like this:
#reboot sudo su username /home/username/launcher.sh >> /home/username/crontab.log 2>&1
I have to initialize pygame display, because I need to process the Sound object end events. Without initializing the display, the events are not triggered.
The code breaks at this line, with error "pygame.error: Unable to open a console terminal"
os.putenv('SDL_VIDEODRIVER', 'dummy')
pygame.display.init() # error at this line
My code used to work in the previous Raspbian (Stretch) version. I have experimented with all kinds of drivers, added/removed pygame.display.set_mode((1, 1)), but no luck.
I am aware of the other posts that tackle with the same question, but I have exhausted all those approaches - changing the driver to fbcon, skipping the set_mode line, etc. The only thing that works is running the program as root:
#reboot /home/username/launcher.sh >> /home/username/crontab.log 2>&1
But it's a bad idea, from the security perspective. I'd rather run it as unpriviliged user.
Is there a new kind of hack to get it past the display.init()?
pygame.init initializes all Pygame modules. You do not need to initialize all Pygame modules, only the ones you need. For playing music it is sufficient to initialize pygame.mixer. Some examples
import pygame
pygame.mixer.init()
pygame.mixer.music.load('music.mp3')
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pygame.time.delay(10)
pygame.mixer.quit()
import pygame
pygame.mixer.init()
my_sound = pygame.mixer.Sound('music.mp3')
my_sound.play(0)
while pygame.mixer.get_busy():
pygame.time.delay(10)
pygame.quit()
import pygame.mixer
pygame.mixer.init()
my_sound = pygame.mixer.Sound('sound.wav')
my_sound.play(0)
pygame.time.wait(int(my_sound.get_length() * 1000))
pygame.mixer.quit()
However, you cannot use the event module because it is tied to the display module.

python tkinter if no button pressed run function

I am currently working on a roulette game in tkinter. The problem is that I want the roulette automatically to run after a ceirtan time (20sec). But right now it will only run if the player inputs something inform of pressing a button and entering an amount of money. But I want the roulette to run every 20 sec even if the player didnt bet anything(so no button got pressed). But I cant seem to find out how.
pseudocode:
if no button got pressed after 20 sec:
run roulette #(roll roulette without player input and without his money)
Not having any code makes answering this a bit harder. I believe what you're looking for is after.
This could run after a time period to check if the user has clicked to play. You should have a variable monitoring the user's clicks and reseting once the game's done.
some real code:
clicked = False
def force_play():
if not clicked:
play()
after(1000 * 20, force_play)

urllib.urlretrieve stops download when no activity on Tkinter window on Mac only

I'm trying to make a file downloader with a Tkinter GUI window, which will download a file using the following line:
urllib.urlretrieve(url = fileurl, filename = file, reporthook = progBar)
Progbar is a progress bar on my Tkinter GUI window. When I run my code on Windows, the download works fine and runs normally, as does the progress bar.
However, when I run the same code on a Mac, the download and progress bar will only progress if there is activity in the Tkinter GUI window. For example, if the window is in the background, the download will pause until the window is clicked on. Even then, when the Tkinter GUI window is not in the background, the download will only progress if I am doing something like moving the mouse around the screen or repeatedly pressing buttons on the keyboard, otherwise the download pauses again. It seems like it is timing out for some reason, and I'm not sure how to fix this or why it only happens on Mac and not windows.
If I put a print statement in the progBar method, the download also slows down.
I have also tried removing the reporthook argument from the call to urllib.urlretrieve, when I do this the download progresses fine.
My progBar method is as follows:
def progBar(blocks, blocksize, totalsize) :
global pb
bytesdownloaded = blocksize*blocks
mbdownloaded = bytesdownloaded/1024/1024
mbsize = float(blocksize)/float(totalsize)
totalsize = totalsize/1024/1024
percent = mbsize*100
global v
va.set("(" + str(mbdownloaded) + 'MB out of ' + str(totalsize) + 'MB)')
pb.step(percent)
I am using Python 2.7 if this helps.
Edit: for further information, the download (call to urllib.urlretrieve) is performed in a background thread, while the GUI window is meant to be the main thread. This may have something to do with the problem.
This is just a guess, but it's possible that the UI output command in the reporthook is hanging due to the fact that the event loop is (I'm guessing) paused for a program when it's in the background. I have vague recollection of the Tkinter UI model but one solution might be to set some global variable with your current progress in the hook, and have UI paint it separately - do not issue UI commands in the hook.

Categories

Resources