본문 바로가기

멀티미디어

Media Player를 이용한 음악 재생 어플리케이션 만들어보기


요즘 정말 날씨가 좋네요~ 공기가 좀 맑지 못한게 아쉽긴 하지만.....
아무튼, 요즘은 사진 찍으러 많이 나가곤 하는데, 사진 찍으러 나갈 때 거의 필수로 mp3플레이어를 챙겨나갑니다.
음악 들으면서 감상(?)에 빠져있다보면 뭔가 좋은 사진이 나오지 않을까.. 싶어서요. ^^;;

그런 의미에서(?) 이번 강좌에서는 간단한 음악 재생 어플리케이션을 만들어보도록 하겠습니다.
저도 멀티미디어 쪽은 처음 다뤄보는 것이라, 지금 이 예제에서 다루는 정도까지밖에 공부를 하지 못했네요 -_-
조금 더 궁부를 하고 나면 기본 내장되어 있는 어플 정도까지는 만들 수 있겠지요? ㅎㅎㅎ

이번에 만들어볼 어플의 작동 영상입니다.~



앞서도 말했지만, 이게 저도 필이 꽃혀서(?) API보고 간단하게 만들어본지라 어플리케이션 구성 자체는 허접합니다^^;;
그냥 음악파일 재생을 어떻게 하는구나~ 정도만 알고 갈 정도로만 봐주세요-ㅎㅎ

일단, 레이아웃 구성을 보겠습니다.


왼쪽 화면이 처음 어플리케이션을 실행했을 때의 모습, 오른쪽 화면이 파일을 불러왔을 때의 모습입니다.
파일을 불러오지 않은 상태에서는 파일 재생이나 반복 설정을 하지 못하게 되어있고, 파일 로드가 완료되면 반복 재생 여부 선택/ 재생/일시정지, 정지 버튼이 활성화됩니다. 이렇게 만든 이유는 차차 살펴보도록 하지요~

소스 파일을 보면서 설명하도록 하겠습니다.

package com.androidhuman.AudioPlayer;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
import android.media.MediaPlayer;

public class AudioPlayer extends Activity {
	private MediaPlayer mp; // MediaPlayer 객체입니다.
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        final EditText audioPath = (EditText)findViewById(R.id.srcEdt);
        final CheckBox loopControl = (CheckBox)findViewById(R.id.setLoop);
        final Button PlayPause = (Button)findViewById(R.id.PlayPause);
        final Button Stop = (Button)findViewById(R.id.Stop);
        final Button Load = (Button)findViewById(R.id.load);
        
        // 파일 불러오기 버튼에 대한 리스너
        Load.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
        		if(!loadAudio(audioPath.getText().toString())){
        			// 오디오 파일을 불러옵니다.
        			Toast // 오디오 파일 불러오기에 실패한 경우
        			.makeText(getApplicationContext(), "파일 불러오기에 실패했습니다.", Toast.LENGTH_LONG)
        			.show();
        			return;
        		}
        		audioPath.setEnabled(false); // 파일 Path 입력란을 비활성화합니다.
        		PlayPause.setEnabled(true);
        		Stop.setEnabled(true);
        		loopControl.setEnabled(true);
        		Load.setEnabled(false);
        		
        		Toast
        		.makeText(getApplicationContext(), "파일 : " + audioPath.getText().toString() +" 로드가 완료되었습니다.", Toast.LENGTH_LONG)
        		.show();
        	}
        });
        
        // 재생 반복 여부 선택 버튼에 대한 리스너
        loopControl.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
        		if(loopControl.isChecked()){ // 체크박스에 체크하면
        			mp.setLooping(true); // 반복을 활성화합니다.
        			Toast
        			.makeText(getApplicationContext(), "반복 활성화됨", Toast.LENGTH_SHORT)
        			.show();
        		}else{
        			mp.setLooping(false); // 반복을 비활성화합니다.
        			Toast
        			.makeText(getApplicationContext(), "반복 해제됨", Toast.LENGTH_SHORT)
        			.show();
        		}
        	}
        });
        
        // 재생/일시정지 버튼에 대한 리스너
        PlayPause.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
	           	if(PlayPauseAudio()==0){ // 재생시 
		       		PlayPause.setText("일시정지"); // 버튼의 캡션을 일시정지로 변경합니다.
		       	}else{ // 일시정지시
		       		PlayPause.setText("재생"); // 버튼의 캡션을 재생으로 변경합니다.
		       	}
	        }
        	
        });
        
        // 정지버튼에 대한 리스너
        Stop.setOnClickListener(new OnClickListener(){ // 정지버튼을 누르면
        	public void onClick(View v){
        		mp.stop(); // 정지합니다.
        		
        		// 정지가 되면, Load버튼을 눌러 파일을 prepare 해야 하므로, 설정값들을 초기화합니다.
        		audioPath.setEnabled(true); // 비활성화 되었던 입력란을 활성화합니다.
        		PlayPause.setText("재생");
        		loopControl.setChecked(false);
        		PlayPause.setEnabled(false);
        		Stop.setEnabled(false);
        		loopControl.setEnabled(false);
        		Load.setEnabled(true);
        	}
        });
               
        }
    
    private int PlayPauseAudio(){
    	if(!mp.isPlaying()){ // 재생중이 아니라면
    		mp.start(); // 파일을 재생합니다.
        	Toast.makeText(getApplicationContext(), "재생", Toast.LENGTH_SHORT).show();
        	return 0;
        	
    	}else{ // 재생중이라면
    		mp.pause(); // 일시정지합니다.
    		Toast.makeText(getApplicationContext(), "일시 정지됨", Toast.LENGTH_SHORT).show();
    		return 1;
    	}
    	
    	
    }
    
    
    private boolean loadAudio(String path){ // 오디오 파일을 로드합니다.
    	mp = new MediaPlayer(); // MediaPlayer 객체를 생성합니다.
    	try{
    		mp.setDataSource(path);
    		mp.prepare(); // 파일을 준비합니다.
    		return true;
    	}catch(Exception e){ // 오디오 파일 로드에 실패하면
    		Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
    		return false; // false를 반환합니다.
    	}
    }
    
       
    public void onDestroy(){ // 액티비티가 종료될 때
    	super.onDestroy();
    	if(mp != null)
    		mp.release(); // MediaPlayer 객체를 Release합니다.
    	mp = null;
    }
}

좀 소스가 길어보이죠? 하지만 별로 어려울 건 없습니다.
길어진 건 제가 급하게 짜느라 효율성 이런걸 고려하지 않아서 그래요~~

import android.media.MediaPlayer;

일단, MediaPlayer 객체를 사용하려면 위와 같이 import 를 해주셔야 합니다.
저 객체에 멀티미디어 파일들을 불러오게 되는 것이죠~

미디어플레이어 객체(오디오)의 사용 단계는 다음과 같습니다.

1. 객체 생성
2. setDataSource()를 이용하여 파일을 불러옴 (다른 작업을 하기 전에 이 과정이 꼭 필요합니다! 안하면 에러..)
3. prepare()메소드를 이용하여 사용할 준비를 함
4. start() 메소드로 재생 시작, 이후 미디어 플레이어의 각종 메소드로 재생 컨트롤
5. 재생이 끝나면 미디어플레이어 객체를 소멸시킴 (Garbage collection)


객체를 생성하는 과정 및 setDataSource()를 통해 재생 준비를 하는 과정을 보겠습니다.
    private boolean loadAudio(String path){ // 오디오 파일을 로드합니다.
    	mp = new MediaPlayer(); // MediaPlayer 객체를 생성합니다.
    	try{
    		mp.setDataSource(path);
    		mp.prepare(); // 파일을 준비합니다.
    		return true;
    	}catch(Exception e){ // 오디오 파일 로드에 실패하면
    		Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
    		return false; // false를 반환합니다.
    	}
    }

위와 같이 path를 인자로 받아 오디오 파일을 불러오는 과정을 볼 수 있습니다. 파일의 path에 관한 설명은 이전 포스트(2009/04/07 - [안드로이드 이야기/이거, 알고있니?] - 안드로이드에서 재생할 수 있는 멀티미디어 파일 형식들 & 파일 사용법)을 참고하세요~

path 인자를 통해 받아온 것을 토대로 setDataSource()메소드에서 객체에 불러올 파일을 지정해주게 됩니다. 이 때, 에러가 발생하게 되면 적절히 예외 처리를 해 주시면 됩니다. 저는 에러 메시지를 Toast를 통해 사용자에게 보여주도록 하였습니다.
        // 파일 불러오기 버튼에 대한 리스너
        Load.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
        		if(!loadAudio(audioPath.getText().toString())){
        			// 오디오 파일을 불러옵니다.
        			Toast // 오디오 파일 불러오기에 실패한 경우
        			.makeText(getApplicationContext(), "파일 불러오기에 실패했습니다.", Toast.LENGTH_LONG)
        			.show();
        			return;
        		}
        		audioPath.setEnabled(false); // 파일 Path 입력란을 비활성화합니다.
        		PlayPause.setEnabled(true);
        		Stop.setEnabled(true);
        		loopControl.setEnabled(true);
        		Load.setEnabled(false);
        		
        		Toast
        		.makeText(getApplicationContext(), "파일 : " + audioPath.getText().toString() +" 로드가 완료되었습니다.", Toast.LENGTH_LONG)
        		.show();
        	}
        });
 
파일 불러오기 버튼을 누르면, 위에서 봤던 loadAudio()메소드를 호출하고, 그 결과에 따라서 에러 메시지를 표시할 것인지, 파일 재생 준비를 하는지 결정하게 됩니다.

그럼, 다음으로 재생하는 과정을 보도록 하죠.
        // 재생/일시정지 버튼에 대한 리스너
        PlayPause.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
	           	if(PlayPauseAudio()==0){ // 재생시 
		       		PlayPause.setText("일시정지"); // 버튼의 캡션을 일시정지로 변경합니다.
		       	}else{ // 일시정지시
		       		PlayPause.setText("재생"); // 버튼의 캡션을 재생으로 변경합니다.
		       	}
	        }
        	
        });

저는 이 어플리케이션에서 재생 버튼을 누르면 일시정지 기능도 수행할 수 있게끔 구현하여서 버튼을 누를 때마다 상태에 따라서 레이블이 바뀌도록 하였습니다. 실질적인 재생 컨트롤에 대한 소스는 다음과 같습니다.
    private int PlayPauseAudio(){
    	if(!mp.isPlaying()){ // 재생중이 아니라면
    		mp.start(); // 파일을 재생합니다.
        	Toast.makeText(getApplicationContext(), "재생", Toast.LENGTH_SHORT).show();
        	return 0;
        	
    	}else{ // 재생중이라면
    		mp.pause(); // 일시정지합니다.
    		Toast.makeText(getApplicationContext(), "일시 정지됨", Toast.LENGTH_SHORT).show();
    		return 1;
    	}
    	
    	
    }

재생/ 일시정지 여부는 MediaPlayer객체의 isPlaying() 메소드를 통해 구현하였습니다. 재생중일경우 isPlaying() 메소드는 true를, 아닐 경우 false를 반환하게 됩니다.

정지 버튼을 누르면, 정지를 수행하고 어플리케이션의 상태를 초기상태로 되될립니다.
        // 정지버튼에 대한 리스너
        Stop.setOnClickListener(new OnClickListener(){ // 정지버튼을 누르면
        	public void onClick(View v){
        		mp.stop(); // 정지합니다.
        		
        		// 정지가 되면, Load버튼을 눌러 파일을 prepare 해야 하므로, 설정값들을 초기화합니다.
        		audioPath.setEnabled(true); // 비활성화 되었던 입력란을 활성화합니다.
        		PlayPause.setText("재생");
        		loopControl.setChecked(false);
        		PlayPause.setEnabled(false);
        		Stop.setEnabled(false);
        		loopControl.setEnabled(false);
        		Load.setEnabled(true);
        	}
        });

마지막으로, 액티비티가 종료될 때 미디어플레이어 객체를 반환하게 됩니다.
    public void onDestroy(){ // 액티비티가 종료될 때
    	super.onDestroy();
    	if(mp != null)
    		mp.release(); // MediaPlayer 객체를 Release합니다.
    	mp = null;
    }


이번 강좌는 예전 것들에 비해 생소한 것들이 좀 있어서 어렵게 느껴시질지도 모르겠지만... 차근차근 보시다 보면 그리 어렵지 않다는 것을 알게 되실 겁니다. ㅎㅎ
연구하셔서 저보다 더 좋은 예제(..) 만드실 수 있으면 합니다~ ^^