3

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()?

Passiday
  • 7,573
  • 8
  • 42
  • 61
  • It's not a solution, but if you can not work around starting as root, you could also consider dropping privileges after startup - https://stackoverflow.com/a/15707075/1730895 . At least this stops the script maintaining the execution as root. – Kingsley Aug 09 '19 at 00:19
  • I have the [same issue](https://stackoverflow.com/questions/70757953/pygame-display-init-fail-to-initialize-framebuffer-for-non-root-user), have you found a fix @Passiday ? – vinalti Jan 24 '22 at 11:36

1 Answers1

0

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.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • I had to do the display init exactly because I needed the sound events. Eventually I was forced to implement my own event solution using Timer from threading because there was a limit of events in pygame. – Passiday Feb 03 '23 at 16:47