2016-12-28 11 views
0

macOSアラートを表示して同時にアラームを開始するpythonスクリプトを作成しようとしています。macOSアラートが閉じた後にサブプロセスが終了しない

警告音は、警告が閉じた後に停止する必要がありますが、警告音は閉じていません。

def show_alert(message="Flashlight alarm"): 
    """Display a macOS dialog.""" 
    message = json.dumps(str(message)) 
    exit_status = os.system("osascript dialog.scpt {0}".format(message)) 
    return exist_status 

def play_alarm(file_name = "beep.wav", repeat=3): 
    """Repeat the sound specified to mimic an alarm.""" 
    process = subprocess.Popen(['sh', '-c', 'while :; do afplay "$1"; done', '_', file_name], shell=False) 
    return process 

def alert_after_timeout(timeout, message, sound = True): 
    """After timeout seconds, show an alert and play the alarm sound.""" 
    time.sleep(timeout) 
    process = None 
    if sound: 
     process = play_alarm() 
    exit_status = show_alert(message) 
    if process is not None: 
     os.killpg(os.getpgid(process.pid), signal.SIGINT) 
     process.kill() 
    # also, this below line doesn't seem to open an alert. 
    show_alert(exit_status) 

alert_after_timeout(1, "1s alarm") 

上記のコードは、(ファイルbeep.wavに)ループに警報音を開始した後MacOSの警告を表示しなければなりません。警報が閉じられると、警報音は直ちに止まるはずです。

のAppleScriptファイルdialog.scptがアラートをトリガーし、それがわずか数行の長さである:

on run argv 
    tell application "System Events" to display dialog (item 1 of argv) with icon file (path of container of (path to me) & "Icon.png") 
end run 
+0

'プロセスがNoneでない場合:' => 'の場合プロセス: '。 'is 'と比較しないでください。 –

+0

私はむしろバックグラウンドで実行するシェルのループで 'サブプロセス 'を使用する代わりにサウンドを再生するスレッドを作成したいです...私には壊れやすい音。 –

+0

@ Jean-FrançoisFabre私はその提案( 'if process:')を実装しましたが、スクリプトは引き続き同じ方法で失敗します。 – theonlygusti

答えて

1

私はあなたが実行を模倣するために、サブプロセスを使用して、シェルで実行しているプロセスを強制終了することができない理由を私は知らない認めますバックグラウンドとして...そして、後に他のコマンドが実行されないという事実は、おそらくどこかにデッドロックがあることを意味します。ですから、その解決策を打ち破りましょう。

私はもっとpythonic解決策を提案しましょう。オーディオ再生部分はhow to play wav file in python?から適応されましたが、現在はループで再生され、Python 3でも動作します。

アイデアは、Pythonモジュールのみを使用してループでサウンドを再生するスレッドを開始することです。スレッドはグローバル変数を認識しています。 stop_audio変数が設定されている場合、スレッドは無限ループを終了して再生を停止する必要があることを認識します。

他の手順からフラグを制御します。メッセージがクリックされると、フラグを設定すると、オーディオの再生が直ちに停止します。それが使用され、私はそれの何の意味を成していないていなかったとして、私はrepeat=3パラメータを落としてきた

import pyaudio 
import wave 
import threading 

# global variable used to gently tell the thread to stop playing 
stop_audio = False 

def show_alert(message="Flashlight alarm"): 
    """Display a macOS dialog.""" 
    message = json.dumps(str(message)) 
    exit_status = os.system("osascript dialog.scpt {0}".format(message)) 
    return exit_status 

# initialize audio 

def play_alarm(file_name = "beep.wav"): 
    #define stream chunk 
    chunk = 1024 

    #open a wav format music 
    f = wave.open(file_name,"rb") 

    #instantiate PyAudio 
    p = pyaudio.PyAudio() 
    #open stream 
    stream = p.open(format = p.get_format_from_width(f.getsampwidth()), 
        channels = f.getnchannels(), 
        rate = f.getframerate(), 
        output = True) 

    while not stop_audio: 
     f.rewind() 
     #read data 
     data = f.readframes(chunk) 

     #play stream 
     while data and not stop_audio: 
      stream.write(data) 
      data = f.readframes(chunk) 

    #stop stream 
    stream.stop_stream() 
    stream.close() 

    #close PyAudio 
    p.terminate() 


def alert_after_timeout(timeout, message, sound = True): 
    """After timeout seconds, show an alert and play the alarm sound.""" 
    time.sleep(timeout) 
    process = None 
    if sound: 
     t = threading.Thread(target=play_alarm,args=("beep.wav",)) 
     t.start() 
    exit_status = show_alert(message) 

    global stop_sound 
    if sound: 
     stop_sound = True # tell the thread to exit 
     t.join() 

    show_alert(exit_status) 

alert_after_timeout(1, "1s alarm") 

注意。 pyaudioを使用せずに

代替は、このことによって、上記play_alarmを交換、ループ内で外部プレーヤーを呼び出すために、次のようになります。

def play_alarm(file_name = "beep.wav"): 
    global stop_sound 
    while not stop_sound: 
     subprocess.call(["afplay",file_name]) 

stop_soundTrueあるとき、音は「最後まで演奏を続けているが、doesnのt再開します。その効果は瞬間的ではありませんが、単純です。

そして、より反応性の方法で音をカットするための別の代替:

def play_alarm(file_name = "beep.wav"): 
    global stop_sound 
    while not stop_sound: 
     process = subprocess.Popen(["afplay",file_name]) 
     while not stop_sound: 
      if process.poll() is not None: 
       break # process has ended 
      time.sleep(0.1) # wait 0.1s before testing process & stop_sound flag 
     if stop_sound: 
      process.kill() # kill if exit by stop_sound 
+0

もう 'process'を割り当てることはできません。関数は何も返さないので? – theonlygusti

+0

私は 'pyaudio'という名前のモジュールがなく、グローバルにインストールしたくありません – theonlygusti

+0

また、あなたの答えに' threading'モジュールを使用していません:/ – theonlygusti

関連する問題