Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't reset the media without re-initializing the media player #44

Closed
moham96 opened this issue Apr 3, 2018 · 2 comments
Closed

Can't reset the media without re-initializing the media player #44

moham96 opened this issue Apr 3, 2018 · 2 comments

Comments

@moham96
Copy link

moham96 commented Apr 3, 2018

Hi,

I want to use the event manager to play the next item of a list but only the first item is being played,
to get the rest of the list to play i need to re initialize the media player object every time I set the new media

import vlc
import time

class player:
	def __init__(self):
		self.items = ['/home/mohammad/foo.wav',
		'/home/mohammad/bar.wav',
		'/home/mohammad/egg.wav']
		self.libvlc_Instance = vlc.Instance('--verbose 2')
		self.libvlc_player = self.libvlc_Instance.media_player_new()

	def play_next(self,num):
		self.play_item(num)

	def play_item(self,num=0):
		print(num)

		self.libvlc_player_event_manager = self.libvlc_player.event_manager()
		self.libvlc_list_player = self.libvlc_Instance.media_list_player_new()
		self.libvlc_Media_list = self.libvlc_Instance.media_list_new()
		self.libvlc_list_player.set_media_player(self.libvlc_player)
		media=self.libvlc_Instance.media_new(self.items[num])
		self.libvlc_Media_list.add_media(media)
		self.libvlc_list_player.set_media_list(self.libvlc_Media_list)
		self.libvlc_list_player.play_item(media)
		if num < len(self.items)-1:
			self.libvlc_player_event_manager.event_attach(
				vlc.EventType.MediaPlayerEndReached, lambda event :self.play_next(num+1))

	def is_playing(self):
		if self.libvlc_player.get_state()==vlc.State.Opening or self.libvlc_player.get_state()== vlc.State.Playing:
			return True

mpl=player()
mpl.play_item(0)

while mpl.is_playing():
	time.sleep(1)

so the above code plays the first item and then exits, but if i move the line where i create the media player object to inside the play_item function (so the object get's created every time) the code wil work and items will be played sequentially, like so:

import vlc
import time

class player:
	def __init__(self):
		self.items = ['/home/mohammad/foo.wav',
		'/home/mohammad/bar.wav',
		'/home/mohammad/egg.wav']
		self.libvlc_Instance = vlc.Instance('--verbose 2')


	def play_next(self,num):
		self.play_item(num)

	def play_item(self,num=0):
		print(num)
		self.libvlc_player = self.libvlc_Instance.media_player_new()
		self.libvlc_player_event_manager = self.libvlc_player.event_manager()
		self.libvlc_list_player = self.libvlc_Instance.media_list_player_new()
		self.libvlc_Media_list = self.libvlc_Instance.media_list_new()
		self.libvlc_list_player.set_media_player(self.libvlc_player)
		media=self.libvlc_Instance.media_new(self.items[num])
		self.libvlc_Media_list.add_media(media)
		self.libvlc_list_player.set_media_list(self.libvlc_Media_list)
		self.libvlc_list_player.play_item(media)
		if num < len(self.items)-1:
			self.libvlc_player_event_manager.event_attach(
				vlc.EventType.MediaPlayerEndReached, lambda event :self.play_next(num+1))

	def is_playing(self):
		if self.libvlc_player.get_state()==vlc.State.Opening or self.libvlc_player.get_state()== vlc.State.Playing:
			return True

mpl=player()
mpl.play_item(0)

while mpl.is_playing():
	time.sleep(1)

So why can't I use the same media player and change the media ?!

@oaubert
Copy link
Owner

oaubert commented Apr 4, 2018

I see two things here:

  • your code seem fairly convoluted. Here is a simple version of a player playing a list of items:

``
#! /usr/bin/env python3

import code
import vlc

player = vlc.MediaListPlayer()

sounds = player.get_instance().media_list_new(("/usr/share/psi-plus/sound/attention.wav",
"/usr/share/psi-plus/sound/chat1.wav",
"/usr/share/psi-plus/sound/chat2.wav",
"/usr/share/psi-plus/sound/chess_error.wav"))
player.set_media_list(sounds)
player.play()
code.interact(local=locals())
``

  • the event handlers are not re-entrant. That means that you cannot call the libvlc API directly from an event handler, you need to delegate this to some mainloop of your application.

@oaubert oaubert closed this as completed Apr 4, 2018
@moham96
Copy link
Author

moham96 commented Apr 4, 2018

@oaubert well the thing is the code I put doesn't reflect what I'm doing, instead, I made up the above code to explain the problem I am having.
What I'm trying to do is to use gmusicapi with VLC. If you are not familiar with this library it generates URLs for the songs that are in your google music library.
So, I don't have a prepared list of items to pass to the media list player,
instead, Each time the playing song reaches the end and invoke the callback function, the callback function would fetch the URL of the song and pass it to the player

from gmusicapi import Mobileclient
import vlc
import json
import time
import os
import sys

USER_AGENT = ' '.join([
    'Mozilla/5.0 (X11; Linux x86_64)'
    'AppleWebKit/537.36 (KHTML, like Gecko)'
    'Chrome/62.0.3202.94 Safari/537.36'
])

class sampleplayer():
	def __init__(self):
		self.libvlc_Instance = vlc.Instance('--verbose 2')
		self.libvlc_Instance.set_user_agent('My own player', USER_AGENT)
		self.libvlc_player = self.libvlc_Instance.media_player_new()
		self.libvlc_list_player = self.libvlc_Instance.media_list_player_new()
		self.libvlc_Media_list = self.libvlc_Instance.media_list_new()
		self.libvlc_list_player.set_media_player(self.libvlc_player)
		self.libvlc_list_player.set_media_list(self.libvlc_Media_list)
		self.libvlc_player_event_manager = self.libvlc_player.event_manager()
		self.api = Mobileclient()
		self.api.login(email, password,
			Mobileclient.FROM_MAC_ADDRESS)

	def loadplaylist(self,playlistnum):
	    track_ids = []
	    if os.path.isfile(os.path.expanduser("~/playlist.json")):
	        with open(os.path.expanduser('~/playlist.json'), 'r') as input_file:
	            playlistcontents = json.load(input_file)
	    else:
	        playlistcontents = self.api.get_all_user_playlist_contents()
	        with open(os.path.expanduser('~/playlist.json'), 'w') as output_file:
	            json.dump(playlistcontents, output_file)
	        print(playlistcontents[0])
	    for i in playlistcontents[playlistnum]['tracks']:
	        track_ids.append(i['trackId'])
	    return track_ids

	def play_next(self,num):
		print('playing next')
		self.play_item(num)

	def play_item(self,num=0):
	    tracks=self.loadplaylist(1)
	    print(tracks)
	    print(num)
	    url=self.api.get_stream_url(tracks[num])
	    media = self.libvlc_Instance.media_new(url)
	    self.libvlc_Media_list.add_media(media)
	    print(url)
	    self.libvlc_player.set_media(media)
	    self.libvlc_list_player.play()

	    if num < len(tracks)-1:
	        print('hooking event ')
	        self.libvlc_player_event_manager.event_attach(
	        	vlc.EventType.MediaPlayerEndReached, lambda event:self.play_next(num+1))

player=sampleplayer()

player.play_item(0)

while True:
	time.sleep(10)

Regarding your second point do you mean I should make a loop to check libvlc_player.get_state() and when it is equal to vlc.State.Ended I can play the next item? If my understanding is wrong could you elaborate and give an example?

blacklight added a commit to blacklight/platypush that referenced this issue Feb 28, 2021
For some reason, vlc event handlers are not re-entrant (oaubert/python-vlc#44 (comment)).

This means that the vlc API can't be used from an event handler,
and that an event handler that reacts to stop/end-of-stream by
releasing the player and the vlc instance will likely get stuck
and the app may eventually die with SIGSEGV.

Because of this design limitation on the vlc side, the plugin has
to run another thread in the main app that monitors the stop event
set by the event handler and releases the resources appropriately.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants