Player becomes silent after 255 iterations

Issue #141 new
khamaileon
created an issue

Steps to reproduce:

import pyglet
import time

pyglet.options['audio'] = ('openal', 'silent')
for i in range(300):
    print(i)
    player = pyglet.media.Player()
    source = pyglet.resource.media('samples/tom_l.wav', streaming=False)
    player.queue(source)
    player.play()
    time.sleep(0.1)

My config:

  • Ubuntu 16.04
  • Python 3.5.2

Comments (5)

  1. Benjamin Moran

    That's an interesting one... Thanks for opening the issue ticket. I'll see if I can have a look at this soon.

    By the way, does it happen with the PulseAudio driver, or only OpenAL?

    -Ben

  2. khamaileon reporter

    PulseAudio crashes after 42 iterations (no joke).

    Assertion '!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)' failed at pulse/thread-mainloop.c:178, function pa_threaded_mainloop_lock(). Aborting.
    Aborted (core dumped)
    

    It seems that OpenAL has a limit of 256 sources. So I came with a hack while waiting for a proper fix:

    pyglet.options['audio'] = ('openal', 'silent')
    for i in range(300):
        print(i)
        player = pyglet.media.Player()
        source = pyglet.resource.media('samples/Roland TR-505/Snaredrum.wav', streaming=False)
        player.queue(source)
        player.play()
        time.sleep(0.1)
        player._audio_player.delete()
    
  3. Benjamin Moran

    Thanks for the additional detail, and example script. The good news is that I can verify your results (both on OpenAL and Pulse). The bad news is that I did not see a simple fix yet. The Player code is a bit of a beast (and could use a rewrite), so it will take a bit more digging to find the issue.

    (To anyone looking at this, some confusion might come from shared terminology between the pyglet Player and Sources, and OpenAL's Player and Sources that are at the driver level.)

    I'll try to clarify what I see happing: Basically, the *low level sources * (not pyglet Sources) at the driver level are not being cleaned up. When we say that OpenAL has a limit of 256 sources, this should apply to concurrently playing audio streams. These should be freed when the sound stops playing. Instead, every new sound is tying up a new driver level source, causing them to eventually deplete. I tweaked your script a little to show the wasted sources:

    import pyglet
    import time
    
    pyglet.options['audio'] = ('openal', 'silent')
    
    source = pyglet.media.sources.StaticSource(pyglet.media.procedural.FM(1))
    
    for i in range(300):
        # print(i)
        player = pyglet.media.Player()
        player.queue(source)
        player.play()
        time.sleep(0.1)
        print("Exhausted players (should be freed): {0}".format(len(player._audio_player.driver._players)))
    
  4. Log in to comment