2014-10-27 16:29:04 -06:00
# -*- coding: utf-8 -*-
import os
import logging as original_logger
2019-01-23 17:28:05 -06:00
import sys
2014-10-27 16:29:04 -06:00
import subprocess
import platform
2019-01-23 17:28:05 -06:00
import tempfile
import glob
import audio_services
import paths
import sound_lib
2014-11-12 20:41:29 -06:00
import output
2019-02-26 21:44:15 +01:00
from audio_services import youtube_utils
2019-01-23 17:28:05 -06:00
import application
2014-10-27 16:29:04 -06:00
system = platform . system ()
2018-08-12 14:50:58 +02:00
if system == "Windows" and not hasattr ( sys , 'frozen' ): # We are running from source on Windows
2021-06-16 16:18:41 -05:00
current_dir = os . getcwd ()
os . chdir ( os . environ [ 'PYTHON_VLC_MODULE_PATH' ])
2018-08-12 14:50:58 +02:00
import vlc
if system == "Windows" and not hasattr ( sys , 'frozen' ): # Restore the original folder
2021-06-16 16:18:41 -05:00
os . chdir ( current_dir )
2019-02-20 17:21:27 -06:00
import sound_lib.output , sound_lib.input , sound_lib.stream , sound_lib.recording
2014-10-27 16:29:04 -06:00
from mysc.repeating_timer import RepeatingTimer
2015-05-14 10:01:37 -04:00
from mysc.thread_utils import call_threaded
2019-01-23 17:28:05 -06:00
2015-01-20 15:40:33 -06:00
URLPlayer = None
2014-10-27 16:29:04 -06:00
2019-01-23 17:28:05 -06:00
log = original_logger . getLogger ( "sound" )
2014-10-27 16:29:04 -06:00
def setup ():
2021-06-16 16:18:41 -05:00
global URLPlayer
if not URLPlayer :
log . debug ( "creating stream URL player..." )
URLPlayer = URLStream ()
2014-10-27 16:29:04 -06:00
def recode_audio ( filename , quality = 4.5 ):
2021-06-16 16:18:41 -05:00
global system
if system == "Windows" : subprocess . call ( r '" %s " -q %r " %s "' % ( os . path . join ( paths . app_path (), 'oggenc2.exe' ), quality , filename ))
2014-10-27 16:29:04 -06:00
def recording ( filename ):
2021-06-16 16:18:41 -05:00
# try:
val = sound_lib . recording . WaveRecording ( filename = filename )
2014-10-27 16:29:04 -06:00
# except sound_lib.main.BassError:
# sound_lib.input.Input()
# val = sound_lib.recording.WaveRecording(filename=filename)
2021-06-16 16:18:41 -05:00
return val
2014-10-27 16:29:04 -06:00
class soundSystem ( object ):
2021-06-16 16:18:41 -05:00
def check_soundpack ( self ):
""" Checks if the folder where live the current soundpack exists."""
self . soundpack_OK = False
if os . path . exists ( os . path . join ( paths . sound_path (), self . config [ "current_soundpack" ])):
self . path = os . path . join ( paths . sound_path (), self . config [ "current_soundpack" ])
self . soundpack_OK = True
elif os . path . exists ( os . path . join ( paths . sound_path (), "default" )):
log . error ( "The soundpack does not exist, using default..." )
self . path = os . path . join ( paths . sound_path (), "default" )
self . soundpack_OK = True
else :
log . error ( "The current soundpack could not be found and the default soundpack has been deleted, " + application . name + " will not play sounds." )
self . soundpack_OK = False
2014-10-27 16:29:04 -06:00
2021-06-16 16:18:41 -05:00
def __init__ ( self , soundConfig ):
""" Sound Player."""
self . config = soundConfig
# Set the output and input default devices.
try :
self . output = sound_lib . output . Output ()
self . input = sound_lib . input . Input ()
except :
pass
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
try :
log . debug ( "Setting input and output devices..." )
self . output . set_device ( self . output . find_device_by_name ( self . config [ "output_device" ]))
self . input . set_device ( self . input . find_device_by_name ( self . config [ "input_device" ]))
except :
log . error ( "Error in input or output devices, using defaults..." )
self . config [ "output_device" ] = "Default"
self . config [ "input_device" ] = "Default"
2017-07-19 15:23:34 +02:00
2021-06-16 16:18:41 -05:00
self . files = []
self . cleaner = RepeatingTimer ( 60 , self . clear_list )
self . cleaner . start ()
self . check_soundpack ()
2014-10-27 16:29:04 -06:00
2021-06-16 16:18:41 -05:00
def clear_list ( self ):
if len ( self . files ) == 0 : return
try :
for i in range ( 0 , len ( self . files )):
if self . files [ i ] . is_playing == False :
self . files [ i ] . free ()
self . files . pop ( i )
except IndexError :
pass
2014-10-27 16:29:04 -06:00
2021-06-16 16:18:41 -05:00
def play ( self , sound , argument = False ):
if self . soundpack_OK == False : return
if self . config [ "session_mute" ] == True : return
sound_object = sound_lib . stream . FileStream ( file = " %s / %s " % ( self . path , sound ))
sound_object . volume = float ( self . config [ "volume" ])
self . files . append ( sound_object )
sound_object . play ()
2014-10-27 16:29:04 -06:00
2014-11-12 20:41:29 -06:00
class URLStream ( object ):
2021-06-16 16:18:41 -05:00
""" URL Stream Player implementation."""
2018-02-20 11:47:33 -06:00
2021-06-16 16:18:41 -05:00
def __init__ ( self ):
# URL status. Should be True after URL expansion and transformation.
self . prepared = False
log . debug ( "URL Player initialized" )
# LibVLC controls.
2022-11-25 15:29:21 -06:00
self . instance = vlc . Instance ( "--quiet" )
self . instance . log_unset ()
2021-06-16 16:18:41 -05:00
self . player = self . instance . media_player_new ()
2021-09-10 15:05:05 -05:00
self . event_manager = self . player . event_manager ()
self . event_manager . event_attach ( vlc . EventType . MediaPlayerEndReached , self . end_callback )
2014-10-27 16:29:04 -06:00
2021-06-16 16:18:41 -05:00
def prepare ( self , url ):
""" Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL."""
log . debug ( "Preparing URL: %s " % ( url ,))
self . prepared = False
2021-11-08 15:30:40 -06:00
self . url = url
2021-06-16 16:18:41 -05:00
if self . url == None :
self . url = url
log . debug ( "Expanded URL: %s " % ( self . url ,))
if self . url != None :
transformer = audio_services . find_url_transformer ( self . url )
transformed_url = transformer ( self . url )
self . url = transformed_url
log . debug ( "Transformed URL: %s . Prepared" % ( self . url ,))
self . prepared = True
2014-10-27 16:29:04 -06:00
2021-06-16 16:18:41 -05:00
def seek ( self , step ):
pos = self . player . get_time ()
pos += step
pos = self . player . set_time ( pos )
2016-08-10 21:59:19 -05:00
2021-06-16 16:18:41 -05:00
def playpause ( self ):
if self . player . is_playing () == True :
self . player . pause ()
else :
self . player . play ()
2016-08-10 21:59:19 -05:00
2021-06-16 16:18:41 -05:00
def play ( self , url = None , volume = 1.0 , announce = True ):
if announce :
output . speak ( _ ( u "Playing..." ))
log . debug ( "Attempting to play an URL..." )
if url != None :
self . prepare ( url )
if self . prepared == True :
media = self . instance . media_new ( self . url )
self . player . set_media ( media )
self . player . audio_set_volume ( int ( volume * 100 ))
self . player . play ()
log . debug ( "played" )
self . prepared = False
2015-05-14 10:01:37 -04:00
2021-06-16 16:18:41 -05:00
def stop_audio ( self ):
output . speak ( _ ( u "Stopped." ), True )
self . player . stop ()
2021-09-10 15:05:05 -05:00
def end_callback ( self , event , * args , ** kwargs ):
call_threaded ( self . player . stop )
def __del__ ( self ):
self . event_manager . event_detach ( vlc . EventType . MediaPlayerEndReached )