2014-10-27 16:29:04 -06:00
# -*- coding: utf-8 -*-
2019-01-23 17:28:05 -06:00
import os
import logging as original_logger
2014-10-27 16:29:04 -06:00
import sys
2019-01-23 17:28:05 -06:00
import subprocess
import platform
import tempfile
import glob
2014-10-27 16:29:04 -06:00
import url_shortener
import audio_services
import paths
2017-07-19 08:25:09 -05:00
import sound_lib
2014-11-12 20:41:29 -06:00
import output
2018-02-16 17:58:57 -06:00
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 07:50:58 -05:00
if system == " Windows " and not hasattr ( sys , ' frozen ' ) : # We are running from source on Windows
current_dir = os . getcwd ( )
os . chdir ( os . environ [ ' PYTHON_VLC_MODULE_PATH ' ] )
import vlc
if system == " Windows " and not hasattr ( sys , ' frozen ' ) : # Restore the original folder
os . chdir ( current_dir )
2019-01-23 17:28:05 -06:00
import sound_lib . output , sound_lib . input , sound_lib . stream
2014-10-27 16:29:04 -06:00
from mysc . repeating_timer import RepeatingTimer
2015-05-14 09:01:37 -05: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 ( ) :
2015-01-20 15:40:33 -06:00
global URLPlayer
2014-11-12 20:41:29 -06:00
if not URLPlayer :
2015-01-18 17:19:39 -06:00
log . debug ( " creating stream URL player... " )
2014-11-12 20:41:29 -06:00
URLPlayer = URLStream ( )
2014-10-27 16:29:04 -06:00
def recode_audio ( filename , quality = 4.5 ) :
global system
if system == " Windows " : subprocess . call ( r ' " %s " -q %r " %s " ' % ( paths . app_path ( ' oggenc2.exe ' ) , quality , filename ) )
def recording ( filename ) :
# try:
2017-07-19 08:25:09 -05:00
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)
return val
class soundSystem ( object ) :
def check_soundpack ( self ) :
""" Checks if the folder where live the current soundpack exists. """
self . soundpack_OK = False
2015-01-20 15:40:33 -06:00
if os . path . exists ( paths . sound_path ( self . config [ " current_soundpack " ] ) ) :
self . path = paths . sound_path ( self . config [ " current_soundpack " ] )
2014-10-27 16:29:04 -06:00
self . soundpack_OK = True
elif os . path . exists ( paths . sound_path ( " default " ) ) :
2015-01-18 17:19:39 -06:00
log . error ( " The soundpack does not exist, using default... " )
2014-10-27 16:29:04 -06:00
self . path = paths . sound_path ( " default " )
self . soundpack_OK = True
else :
2015-04-19 18:10:34 -05:00
log . error ( " The current soundpack could not be found and the default soundpack has been deleted, " + application . name + " will not play sounds. " )
2014-10-27 16:29:04 -06:00
self . soundpack_OK = False
2015-01-20 15:40:33 -06:00
def __init__ ( self , soundConfig ) :
2014-10-27 16:29:04 -06:00
""" Sound Player. """
2015-01-20 15:40:33 -06:00
self . config = soundConfig
2014-10-27 16:29:04 -06:00
# Set the output and input default devices.
2017-07-19 08:23:34 -05:00
try :
2017-07-19 08:25:09 -05:00
self . output = sound_lib . output . Output ( )
self . input = sound_lib . input . Input ( )
except :
2017-07-19 08:23:34 -05:00
pass
2017-07-19 08:25:09 -05:00
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
2017-07-19 08:23:34 -05:00
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 :
2017-07-19 08:25:09 -05:00
log . error ( " Error in input or output devices, using defaults... " )
2017-07-19 08:23:34 -05:00
self . config [ " output_device " ] = " Default "
self . config [ " input_device " ] = " Default "
2014-10-27 16:29:04 -06:00
self . files = [ ]
self . cleaner = RepeatingTimer ( 60 , self . clear_list )
self . cleaner . start ( )
self . check_soundpack ( )
def clear_list ( self ) :
2014-11-12 20:41:29 -06:00
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
def play ( self , sound , argument = False ) :
if self . soundpack_OK == False : return
2015-03-11 17:17:29 -06:00
if self . config [ " session_mute " ] == True : return
2017-07-19 08:25:09 -05:00
sound_object = sound_lib . stream . FileStream ( file = " %s / %s " % ( self . path , sound ) )
2015-01-20 15:40:33 -06:00
sound_object . volume = float ( self . config [ " volume " ] )
2014-10-27 16:29:04 -06:00
self . files . append ( sound_object )
sound_object . play ( )
2014-11-12 20:41:29 -06:00
class URLStream ( object ) :
2018-02-20 11:47:33 -06:00
""" URL Stream Player implementation. """
def __init__ ( self ) :
# URL status. Should be True after URL expansion and transformation.
2014-10-27 16:29:04 -06:00
self . prepared = False
2015-03-11 06:11:42 -06:00
log . debug ( " URL Player initialized " )
2018-02-20 11:47:33 -06:00
# LibVLC controls.
self . instance = vlc . Instance ( )
self . player = self . instance . media_player_new ( )
2014-10-27 16:29:04 -06:00
2014-11-12 20:41:29 -06:00
def prepare ( self , url ) :
2018-02-20 11:47:33 -06:00
""" 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. """
2015-03-11 06:11:42 -06:00
log . debug ( " Preparing URL: %s " % ( url , ) )
2014-10-27 16:29:04 -06:00
self . prepared = False
2014-11-12 20:41:29 -06:00
self . url = url_shortener . unshorten ( url )
2017-12-10 10:22:12 -06:00
if self . url == None :
self . url = url
2018-02-20 11:47:33 -06:00
log . debug ( " Expanded URL: %s " % ( self . url , ) )
2014-11-12 20:41:29 -06:00
if self . url != None :
transformer = audio_services . find_url_transformer ( self . url )
2018-02-20 11:47:33 -06:00
transformed_url = transformer ( self . url )
2018-02-16 17:58:57 -06:00
self . url = transformed_url
2017-12-10 10:22:12 -06:00
log . debug ( " Transformed URL: %s . Prepared " % ( self . url , ) )
2017-09-22 10:38:03 -05:00
self . prepared = True
2014-10-27 16:29:04 -06:00
2018-02-20 11:47:33 -06:00
def seek ( self , step ) :
pos = self . player . get_time ( )
2016-08-10 21:59:19 -05:00
pos + = step
2018-02-20 11:47:33 -06:00
pos = self . player . set_time ( pos )
2016-08-10 21:59:19 -05:00
def playpause ( self ) :
2018-02-20 11:47:33 -06:00
if self . player . is_playing ( ) == True :
self . player . pause ( )
2016-08-10 21:59:19 -05:00
else :
2018-02-20 11:47:33 -06:00
self . player . play ( )
2016-08-10 21:59:19 -05:00
2018-02-20 11:47:33 -06:00
def play ( self , url = None , volume = 1.0 , announce = True ) :
2015-07-03 17:23:25 -05:00
if announce :
output . speak ( _ ( u " Playing... " ) )
log . debug ( " Attempting to play an URL... " )
if url != None :
self . prepare ( url )
if self . prepared == True :
2018-02-20 11:47:33 -06:00
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 " )
2018-02-16 17:58:57 -06:00
self . prepared = False
2015-05-14 09:01:37 -05:00
2018-02-20 11:47:33 -06:00
def stop_audio ( self ) :
output . speak ( _ ( u " Stopped. " ) , True )
self . player . stop ( )