목차

라즈베리 파이로 라디오 듣기

개요

라즈베리 파이를 이용해 Digitally Imported의 라디오를 듣도록 한다. 간단하게 재생/멈춤을 지원하며 웹서버의 특정 URL을 이용해 재생을 제어한다고 생각한다.

작업 내용

라즈베리에 패키지 설치

라즈베리에 mplayer와 sudo를 설치한다. 웹서버 및 PHP는 이미 동작하고 있다고 가정한다.

$ sudo apt-get install sudo mplayer

라즈베리 파이에서 소리가 나도록 조정

라즈베리 파이로 스피커 출력이 되도록 명령어를 입력해 조절한다.

$ sudo amixer cset numid=3 1

라디오를 위한 유저 생성

그리고 라디오만 전담하는 유저를 하나 생성한다. 그리고 이 유저는 사운드를 이용할 수 있어야 한다.

$ sudo useradd -M -N -g nogroup -G audio radio
$ sudo passwd -l radio

웹서버는 www-data 계정으로 동작한다. 그러므로 www-data가 자유롭게 mplayer를 radio계정을 사용할 수 있도록 조작할 수 있어야 한다. visudo 명령을 내린 후 다음을 추가한다.

$ sudo visudo

# www-data can run mplayer as radio
www-data ALL=(radio) NOPASSWD: /usr/bin/mplayer, /usr/bin/pkill

그리고 일단 radio 계정으로 mplayer가 동작하고, 스피커로 음악이 출력되는지 확인해본다.

$ wget http://robtowns.com/music/blind_willie.mp3  # 테스트 음원입니다. 저작권 걱정없이 쓸 수 있습니다.
$ sudo -s      # user -> root
# su radio     # root -> radio
$ mplayer blind_willie.mp3 # 소리가 나와야 합니다!

Ctrl+C를 눌러 일단 종료한다. 이제 같은 방법으로 웹서버가 음악을 실행할 수 있는지도 재차 테스트한다.

$ exit         # radio -> root
# su www-data  # root  -> www-data
$ sudo -u radio mplayer blind_willie.mp3 # 소리가 나와야 합니다!

재생 중에 터미널 하나를 더 이용해 임의로 mplayer를 멈출 수 있는지도 확인합니다.

$ sudo -s      # user -> root
# su www-data  # root -> www-data
$ sudo -u radio pkill mplayer # 음악이 연주되는 중에 이 명령을 입력합니다. mplayer가 종료되면서 음악이 멈추어야 한다.

명령이 모두 동작하면 이제 동작시킬 준비가 된다.

플레이리스트 받기

  1. http://www.di.fm 에 접속하고 로그인한다.
  2. 'My Account'에 들어가 'Player Settings'를 선택한다. http://www.di.fm/settings 로도 들어갈 수 있다.
  3. 'Preferred Player'에서 'Hardware Player'를 선택한다.
  4. 'Server Information'에서 적당한 장르를 선택한다. 선택된 장르에 따라 'Playlist'와 'Servers' 항목이 달라진다. mplayer는 playlist 파일을 잘 지원하므로 Playlist 파일만 받아오면 된다. 이후 설명에선느 'Ambient' 장르를 가져와 작업하는 것으로 가정한다.
  5. pls 파일을 ambient.pls로 고치고, 라즈베리 파이로 옮긴다.

제어 구문 작성 (PHP)

일단 아주 간단하게 PHP 스크립트 몇 줄을 이용하여 재생/정지 기능을 구현한다.

# cd /usr/share/nginx/www # 웹서버의 루트로 이동. 서버마다, 설정마다 달라지므로 각자 확인
# mkdir difm              # difm 이라는 디렉토리에서 작업

이 difm 디렉토리에 ambient.pls 파일을 옮긴다. 그리고 웹서버의 difm에 다음과 같은 간단한 두 가지 스크립트를 작성한다.

ambient.php
<?php
$cmd = 'sudo -u radio mplayer -playlist ambient.pls 1>/dev/null 2>&1 &';
echo exec($cmd);
echo "playing ambient";
?>
stop.php
<?php
$cmd="sudo -u radio pkill mplayer";
exec($cmd);
?>

웹서버의 주소를 통해 음악이 재생되는지 확인해본다!

개선안

위 방법은 테스트이고, 그나마 조금 쓰기 편하게 하려면 다음과 같은 PHP 구문으로 대체하는 것이 좋다. 이번의 PHP는 difm이라는 디렉토리 내부의 모든 PLS 파일을 순서대로 목록화하여 보여준다.

아래 스크립트에서 각 방송국(스테이션)은 하위 디렉토리 하나를 점유하고 있으며 각 하위 디렉토리에는 각 채널의 그림 파일과 pls 파일을 보유하고 있다.

ipcheck.php
<?php
function ipcheck()
{
	$allow = array("^192.168.0.*");
 
	foreach($allow as $ip)
		if(eregi($ip, $_SERVER['REMOTE_ADDR']))
			return;
 
	die('Unauthorized');
}
?>
index.php
<?php
        include('ipcheck.php');
        ipcheck();
 
        function get_channels($sitename)
        {
                $handle = opendir("./$sitename");
                $channels = array();
                while(false !== ($entry = readdir($handle)))
                {
                        $path = pathinfo($entry);
                        $name = $path['filename'];
                        $ext = $path['extension'];
 
                        if($ext == 'pls')
                                array_push($channels, $name);
                }
                sort($channels);
                return $channels;
        }
 
        function get_img($channel)
        {
                $exts = array('.png', '.jpg');
                foreach($exts as $e)
                {
                        $imgfile = $channel.$e;
                        if(file_exists($imgfile))
                                return $imgfile;
                }
 
                return "";
        }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
        <head>
                <title>di.fm@PI-0 Server!</title>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
                <style type="text/css">
                .station {margin-right:10px; float:left; }
                </style>
        </head>
        <body>
                <h1>Radio at Raspberry Pi Server!</h1>
                <h2>Choose your channel!</h2>
                <h3><a href="control.php?action=stop">Just stop playing!</a><br></h3>
                <div class="station">
                        <h3>Digitally Imported</h3>
                        <ul>
<?php
// print all .pls file in the current directory
$difm = get_channels('di.fm');
foreach($difm as $ch)
{
        $url = urlencode("di.fm/".$ch);
        $img = get_img("di.fm/".$ch);
        echo "<li><a href=\"control.php?action=play&channel=$url\"><img src=\"$img\" width=\"48\"> $ch</a>\n";
}
?>
                        </ul>
                </div>
                <div class="station">
                        <h3>SKY.FM</h3>
                        <ul>
<?php
$skyfm = get_channels('sky.fm');
foreach($skyfm as $ch)
{
        $url = urlencode("sky.fm/".$ch);
        $img = get_img("sky.fm/".$ch);
        echo "<li><a href=\"control.php?action=play&channel=$url\"><img src=\"$img\" width=\"48\"> $ch</a>\n";
}
?>
                        </ul>
                </div>
        </body>
</html>
control.php
<?php
include('ipcheck.php');
ipcheck();
?>
<html>
        <head>
        </head>
<body>
<?php
function play($channel)
{
        $filename = str_replace(' ', '\\ ', $channel);
        $cmd = "sudo -u radio mplayer -playlist $filename.pls 1>/dev/null 2>&1 &";
        exec($cmd);
        echo "<p>Playing ".$channel."... Request from ".$_SERVER["REMOTE_ADDR"]."</p>";
}
 
function stop()
{
        exec('sudo -u radio pkill mplayer > /dev/null 2>&1');
        echo "<p>Music stopped</p>";
}
 
if($_GET["action"]=="play")
{
        $channel = $_GET['channel'];
        echo "Channel name: ".$channel;
        if(file_exists($channel.".pls"))
        {
                stop();
                play($channel);
        }
        else
        {
            echo "Channel ".$channel." not found!";
        }
}
else if($_GET["action"]=="stop")
{
        stop();
}
else
{
        echo "Unknown action!";
}
 
?>
<h1><a href="index.php">Go to index</a></h1>
</body>
</html>

이제는 각 스테이션 별 디렉토리 내부에 pls 파일만 채워 주면 알아서 웹페이지가 갱신되는 편리함이 추가되었다.

또다른 개선안