저번에 PiFaceCAD를 이용해 만들었던 음악플레이어에 이어서 인터넷 라디오 스트리머를 만들어보자.
먼저 PiFaceCAD를 위한 SW설치, IR Remote 설정, Configuring LIRC 는 저번 음악플레이어 만들기와 동일하니 혹시 안했다면 아래 링크에 가서 한번 해보자.
2017/03/29 - [Raspberry] - PiFaceCAD를 이용해 MusicPlayer 만들기
인터넷 라디오 스트리밍하기
간단하게 다음 코드를 입력해보자.
여러 줄로 뭐라고 뜨며 라디오가 재생된다면 성공이다. 인터넷 라디오는 환경에 따라 되는 주소도 아닌 주소도 있기 때문에 아래의 링크 혹은 검색을 통해 더 많은 주소들을 찾아보자.
http://changjhyun.tistory.com/35
mplayer 사용하기
mplayer 를 위와 같은 방식이 아닌 slave모드로 켜면 mplayer 가 실행되는 도중 command를 읽어 들여 일시정지나 볼륨조정 같은 설정을 할 수 있다. 또는 FIFO 파일을 통해 mplayer를 조종할 수 있다.
위와 같이 mplayer를 실행 시키면 fifo 파일을 읽어 mplayer를 조종할 수 있게 된다.
위 명령을 실행시킨 후 다른 터미널 창을 하나 더 켜서 다음 명령어를 입력해보자
다른 터미널에서 실행되던 mplayer가 일시 정지하는가? 일시정지 했을 것이다. 이것으로 fifo파일로 mplayer를 조종 할 수 있는것을 확인할 수 있다, 위에서 사용한 pause 함수 말고도 mplayer가 slave 모드로 실행 되었을 때 사용할 수 있는 함수들이 많다. 따라서 아래 링크를 따라가 documents를 확인하여 사용할 함수들을 알아보도록 한다.
http://www.mplayerhq.hu/DOCS/tech/slave.txt
파이썬에서 mplayer 실행시키기
터미널 창에 mplayer 명령을 치는 것과 같은 효과가 있다.
따라서 mplayer를 조종할 fifo 파일에 보낼 echo 명령도 os.system 함수를 통해 구현하면 된다. 그러나 코드안에서 mplayer를 실행시켰다 해도 mplayer가 실행되는 동안에는 코드가 os.system("mplayer ...")의 다음 줄로 넘어가지 못한다. 따라서 mplayer를 실행시키는 동안 스레드를 통해 echo 명령을 내려 mplayer를 조종하도록 구현하겠다.
이를 바탕으로 인터넷 라디오 스트리머를 구현해 보았다.
curNum = 0
channelLink = ["mms://211.181.136.136/livefm", "mms://114.108.140.39/magicfm_live",\
"mms://live.febc.net/LiveFm","mms://vod.ysmbc.co.kr/YSFM",\
"mms://121.254.230.3/FMLIVE","mms://210.96.79.102/Incheon"]
channelName = ["MBC", "SBS","SeoulFBEC","YeosooMBC","JIBS","TBN"]
cad.lcd.write('CH : '+channelName[curNum])
path = '/tmp/mplayer-control'
pin = -1
remote = -1
mute = False
play = True
volume = 50
def radioMainFunc():
global pin
global remote
global volume
global play
global mute
f = open(path,'w')
if mute:
f.write('volume 0 1\n')
else:
f.write('volume '+ str(volume) +' 1\n')
f.close()
play = True;
curCh = 0
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
while True:
showTime()
# play control
if pin == 2 or remote == 2: # pause and unpause
os.system('echo \"pause\" > /tmp/mplayer-control')
if play:
play = False;
else:
play = True;
writeBottomLine()
pin = -1
remote = -1
elif pin == 3 or remote == 3: # next channel
curCh = (curCh + 1) % len(channelLink)
os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
pin = -1
remote = -1
elif pin == 1 or remote == 1: # prev channel
if curCh == 0:
curCh = len(channelLink)-1
else:
curCh -= 1
os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
pin = -1
remote = -1
# volume control
elif pin == 6 or remote == 6: # volume down
while True:
volume -= 3
if volume < 0:
volume = 0
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
updateVolume();
sleep(0.2)
remote = -1
if not cad.switches[6].value:
break
pin = -1
elif pin == 7 or remote == 7: # volume up
while True:
volume += 3
if volume > 100 :
volume = 100
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
updateVolume();
sleep(0.2)
remote = -1
if not cad.switches[7].value:
break
pin = -1
elif pin == 5 or remote == 5: # mute
if mute:
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
mute = False;
else:
os.system('echo \"volume 0 1\" > /tmp/mplayer-control')
mute = True;
updateVolume();
pin = -1
remote = -1
elif pin == 4 or remote == 4:
pin = -1
remote = -1
os.system('echo \"quit\" > /tmp/mplayer-control')
return
main = threading.Thread(target=radioMainFunc)
main.start()
os.system('mplayer -slave -input file='+path+' '+channelLink[0])
radioMainFunc() 이외의 함수는 저번 음악플레이어를 만들었을 때 사용한 함수들을 그대로 사용하였다. 인터럽트 또한 이전과 같은 방식으로 작성하고 사용하였다. PiFace CAD의 버튼과 리모콘도 거의 같은 역할을 한다. 달라진 점이라고는 스레드를 사용한 것과 mplayer를 조종할 때 fifo파일과, echo 명령을 사용한다는 것이다.
인터럽트 반환 값이 2일 때 : echo "pause" > [path] 명령을 통해 일시정지 및 재생
1,3일 때 : echo "loadfile" [url] > [path] 명령을 통해 이전채널, 다음채널 스트리밍
5,6,7일 때 : echo "volume" <value> 1 > [path] 명령을 통해 볼륨 조정(5: 음소거 및 해제, 6: 감소, 7: 증가)
4 일 떄 : echo "quit"] > [path] 명령을 통해 mplayer 종료
이 코드와 저번에 작성한 음악플레이어 코드를 병합 및 수정하여 라디오와 음악플레이어를 선택하여 들을 수 있는 플레이어를 구현하였다.
from pygame import mixer # Load the required library
import pifacecad
import time
import datetime
import threading
import os
cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()
cad.lcd.blink_off()
cad.lcd.cursor_off()
# bitmap
bmp_note = pifacecad.LCDBitmap([2,3,2,2,14,30,12,0])
bmp_play = pifacecad.LCDBitmap([0,8,12,14,12,8,0,0])
bmp_pause = pifacecad.LCDBitmap([0,27,27,27,27,27,0,0])
bmp_clock = pifacecad.LCDBitmap([0,14,21,23,17,14,0,0])
bmp_vol1 = pifacecad.LCDBitmap([1,3,15,15,15,3,1,0])
bmp_vol2 = pifacecad.LCDBitmap([8,16,0,24,0,16,8,0])
cad.lcd.store_custom_bitmap(0, bmp_note)
cad.lcd.store_custom_bitmap(1, bmp_play)
cad.lcd.store_custom_bitmap(2, bmp_pause)
cad.lcd.store_custom_bitmap(3, bmp_clock)
cad.lcd.store_custom_bitmap(4, bmp_vol1)
cad.lcd.store_custom_bitmap(5, bmp_vol2)
# music
song = ['We Don\'t Talk Anymore.mp3','Closer.mp3','Shape Of You.mp3','Starving.mp3','The Ocean.mp3'\
,'Happy.mp3','Daft Punk.mp3', 'Chandelier.mp3','The Greatest.mp3', 'Lean On.mp3']
# radio
path = '/tmp/mplayer-control'
channelLink = ["mms://211.181.136.136/livefm", "mms://114.108.140.39/magicfm_live",\
"mms://live.febc.net/LiveFm","mms://vod.ysmbc.co.kr/YSFM",\
"mms://121.254.230.3/FMLIVE","mms://210.96.79.102/Incheon"]
channelName = ["MBC", "SBS","SeoulFBEC","YeosooMBC","JIBS","TBN"]
pin = -1 # PiFaceCAD button
remote = -1 # IR remote control button
volume = 50 # current volume
play = True # current playing status (playing : True, pause: False)
mute = False # current mute status
curSong = 0 # current song number
stridx = 0 # current printed song string index
def update_pin_text(event):
global pin
pin = event.pin_num
def print_ir_code(event):
global remote
remote = int(event.ir_code)
def showTime(): # print current hour and minute
now = datetime.datetime.now()
nowTime = now.strftime('%H:%M')
cad.lcd.set_cursor(10,1)
cad.lcd.write_custom_bitmap(3)
cad.lcd.write(nowTime)
cad.lcd.set_cursor(0,0)
def writeVolume(): # print current volume
global volume
global mute
cad.lcd.set_cursor(0,1)
cad.lcd.write_custom_bitmap(4)
cad.lcd.write_custom_bitmap(5)
if mute:
cad.lcd.write('mute')
else:
cad.lcd.write(str(volume).rjust(4))
def updateVolume():
global volume
cad.lcd.set_cursor(2,1)
if mute:
cad.lcd.write('mute')
else:
cad.lcd.write(str(volume).rjust(4))
def writeBottomLine(): #print LCD bottom line
global play
showTime()
writeVolume()
cad.lcd.set_cursor(7,1)
if play:
cad.lcd.write_custom_bitmap(1)
else:
cad.lcd.write_custom_bitmap(2)
cad.lcd.set_cursor(0,0)
def writeTopLine(): #print LCD top line and rotate when length > 16
global curSong
global stridx
cad.lcd.set_cursor(0,0)
str = song[curSong]
if len(str)>16:
str_rotate = (str+' '+str)[stridx:stridx+15]
stridx += 1
if stridx == len(str)+4:
stridx = 0
cad.lcd.write(str_rotate)
else :
cad.lcd.write(str)
def musicMainfunc():
global pin
global remote
global volume
global play
global mute
global curSong
global stridx
curSong = 0
pin = -1
remote = -1
mixer.init()
mixer.music.set_volume(float(volume)/100)
while True:
if curSong == len(song):
curSong = 0
cad.lcd.clear()
cad.lcd.blink_off()
cad.lcd.cursor_off()
mixer.music.load(song[curSong])
mixer.music.play()
writeTopLine()
count_t = time.time()
while mixer.music.get_busy() == True:
writeBottomLine()
if time.time()-count_t > 1: # writeTopLine every 1 second
writeTopLine()
count_t = time.time()
# song control
if pin == 1 or remote == 1: # prev song
curSong-=2
if curSong==-2:
curSong=len(song)-2
pin = -1
remote = -1
stridx = 0
break;
elif pin == 3 or remote == 3: # next song
pin = -1
remote = -1
stridx = 0
break;
elif pin == 2 or remote == 2: # play and pause
if play:
mixer.music.pause()
play = False
else:
mixer.music.unpause()
play = True
pin = -1
remote = -1
# volume control
elif pin == 6 or remote == 6: # volume down
while True:
volume -= 3
if volume < 0:
volume = 0
mixer.music.set_volume(float(volume)/100)
updateVolume();
time.sleep(0.2)
if not cad.switches[6].value:
break
pin = -1
remote = -1
elif pin == 7 or remote == 7: # volume up
while True:
volume += 3
if volume > 100:
volume = 100
mixer.music.set_volume(float(volume)/100)
updateVolume();
time.sleep(0.2)
if not cad.switches[7].value:
break
pin = -1
remote = -1
elif pin == 5 or remote == 5: # mute
if mute:
mixer.music.set_volume(float(volume)/100)
mute = False
else:
mixer.music.set_volume(0)
mute = True
pin = -1
remote = -1
elif pin == 4 or remote == 4: # quit
pin = -1
remote = -1
mixer.quit()
return
curSong+=1
def radioMainFunc(): # Internet radio streaming player
global pin
global remote
global volume
global play
global mute
f = open(path,'w')
if mute:
f.write('volume 0 1\n')
else:
f.write('volume '+ str(volume) +' 1\n')
f.close()
play = True;
curCh = 0
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
while True:
showTime()
# play control
if pin == 2 or remote == 2: # pause and unpause
os.system('echo \"pause\" > /tmp/mplayer-control')
if play:
play = False;
else:
play = True;
writeBottomLine()
pin = -1
remote = -1
elif pin == 3 or remote == 3: # next channel
curCh = (curCh + 1) % len(channelLink)
os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
pin = -1
remote = -1
elif pin == 1 or remote == 1: # prev channel
if curCh == 0:
curCh = len(channelLink)-1
else:
curCh -= 1
os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
cad.lcd.clear()
writeBottomLine()
cad.lcd.write('CH : '+channelName[curCh])
pin = -1
remote = -1
# volume control
elif pin == 6 or remote == 6: # volume down
while True:
volume -= 3
if volume < 0:
volume = 0
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
updateVolume();
time.sleep(0.2)
remote = -1
if not cad.switches[6].value:
break
pin = -1
elif pin == 7 or remote == 7: # volume up
while True:
volume += 3
if volume > 100 :
volume = 100
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
updateVolume();
time.sleep(0.2)
remote = -1
if not cad.switches[7].value:
break
pin = -1
elif pin == 5 or remote == 5: # mute
if mute:
os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
mute = False;
else:
os.system('echo \"volume 0 1\" > /tmp/mplayer-control')
mute = True;
updateVolume();
pin = -1
remote = -1
elif pin == 4 or remote == 4: # quit
pin = -1
remote = -1
os.system('echo \"quit\" > /tmp/mplayer-control')
return
def mainFunc():
global volume
listener = pifacecad.SwitchEventListener(chip=cad)
for i in range(8):
listener.register(i, pifacecad.IODIR_FALLING_EDGE, update_pin_text)
listener.activate()
remote_listener = pifacecad.IREventListener(prog='myprogram')
for i in range(8):
remote_listener.register(str(i), print_ir_code)
remote_listener.activate()
radioMain = threading.Thread(target=radioMainFunc)
while True:
musicMainfunc()
radioMain = threading.Thread(target=radioMainFunc)
os.mkfifo(path)
radioMain.start()
os.system('mplayer -slave -input file='+path+' '+channelLink[0])
radioMain.join()
os.remove(path)
mainFunc()
1. 이전 곡 & 이전 채널 <- KEY_CHANNELDOWN
2. 재생 및 일시정지 <- KEY_OK
3. 다음 곡 & 다음 채널 <- KEY_CHANNELUP
4. 음악, 라디오 모드 변경 <- KEY_MENU
5. 음소거 및 해제 <- KEY_MUTE
6. 볼륨 낮추기 <- KEY_VOLUMEUP
7. 볼륨 올리기 <- KEY_VOLUMEDOWN
위와 같이 수정 하였다. 아래 데모를 보고 제대로 실행되는지 확인해 보자.
'Raspberry' 카테고리의 다른 글
Korean Alexa with Raspberry pi (1) | 2017.05.09 |
---|---|
Raspberry Pi로 LED 제어하기 (0) | 2017.04.11 |
Pi Camera를 이용해 Timelapse 촬영하기 (0) | 2017.04.08 |
Raspberry 부팅시에 자동으로 파이썬 스크립트 실행하기 (0) | 2017.04.02 |
PiFaceCAD를 이용해 MusicPlayer 만들기 (0) | 2017.03.29 |