태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

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

2009.04.11 13:05


요즘 정말 날씨가 좋네요~ 공기가 좀 맑지 못한게 아쉽긴 하지만.....
아무튼, 요즘은 사진 찍으러 많이 나가곤 하는데, 사진 찍으러 나갈 때 거의 필수로 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;
    }


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

커니 멀티미디어 , , , , ,

  1. Blog Icon
    동근

    좋은글 감사합니다^^

  2. Blog Icon
    쓰폭

    저기.. 강좌 감사합니다!! 잘보고있어요 ㅎㅎ 근데 미디어 플레이어 예제 따라서 하고 있는데 실행하면
    The application AudioPlayer has stopped unexpectedly.Please try again 이라구 뜨는데 ㅠㅠ 소스는 똑같이 쓰고
    xml은 안드로이드사이드에 누즈님이 댓글 달아주신거 수정해서 썼거든요. ㅠ sd카드 스캔하구서 뭐 따로 해줘야 되는게 있는지요...ㅠ

  3. http://androidhuman.tistory.com/entry/%EB%9F%B0%ED%83%80%EC%9E%84-%EC%97%90%EB%9F%ACRun-time-Error%EC%97%90-%EB%8C%80%EC%B2%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95

    이 글을 참조하시고 이러 메시지를 한번 확인해보세요~

  4. Blog Icon
    안녕초코베리

    감사합니다 ㅠ ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

  5. Blog Icon
    metLife

    xml은 어디있나요? 테스트하고 싶은데...

  6. Blog Icon
    fan number 1

    강좌정말 잘보고있고, 너무 큰 도움이 되고있습니다!
    그런데 맨 마지막에 왜 미디어객체를 release 해줘야하는지..? 액티비티가 종료되면 저절로 꺼지는게아닌가요
    제가 release개념을 잘 모르고잇나봐요 T.T

  7. 액티비티와는 별개입니다 :)
    액티비티의 라이프사이클과 MediaPlayer의 라이프사이클 자체가 다르므로 어느 한 쪽을 따라가지는 않습니다.

  8. 백그라운드에서도 음악이 돌아가게 하고싶은데요 백그라운드 서비스를 이용하면 된다고 들었는데
    이 소스는 그냥 뒤로가기하면 프로그램은 종료되네요 홈버튼을 누른것처럼 백그라운드에 액티비티가 남아있었으면 좋겠는데 어떻게 해야하나요?;;

  9. 액티비티는 백그라운드에 남을 수 없습니다. 말씀하신 것처럼 구현하려면 서비스를 사용해야 합니다.

    서비스에서 음악이 재생되도록 하고, 서비스를 제어할 수 있는 AIDL을 작성하여 액티비티에서 서비스를 제어하는 방식으로 구현해야 합니다.

  10. Blog Icon

    비밀댓글입니다

  11. MediaPlayer.isPlaying()을 사용하시면 미디어가 재생 중인지 아닌지 판별할 수 있습니다. 이 결과를 토대로 제어를 처리하면 되겠네요.

  12. Blog Icon
    행인 1

    음악 어플을 제작하는중 노래 가사가 나오는 어플들을 보고 물결까진 아니어도 가사를 띄어주면 좋겠다라는 생각이들어서 가사를 띄어볼려고 했습니다. 그러나 안드로이드 DB 테이블을 봐도 가사라는 느낌을 가지고 있는 컬럼은 없더군요 혹시 가사를 얻올 수 있는 방법이 있는가 궁금하며 만약에 없다면, 어떤식으로 MP3 파일에 접근을 해서 노래 가사를 얻어올수 있는것 인지가 궁금합니다만...

  13. 안드로이드 DB에는 가사를 저장하는 공간은 없습니다. 직접 파일에 접근해서 가사를 추출하는 방법 말고는 없는 걸로 알고 있습니다. :)

  14. Blog Icon
    초보

    걱의 그대로 따라하면서 코드를 작성하였는데요.

    22. final EditText audioPath = (EditText)findViewById(R.id.srcEdt); 줄에서 부터 26번째 줄까지 id에 빨간줄이 가는데요.. 제가 따로 뭔가를 설정을 해줘야하는지 잘 모르겠습니다.

    코드를 한번 돌려보고싶은데 가능하시면 제가 뭐가 문제인지 가르쳐주셨으면 감사하겠습니다.


    자바를 접한지도 한달 정도밖에 되지 않았고, 안드로이드를 너무 빠르게 접했는데, 3d mediaplayer를 구현해야 할 것 같아 마음이 급합니다.

    다행이 좋은 글을 만나서 미디어 플레이어에 대해서 조금 알수 있었는데.... 너무 기초적인 질문을 하게 되서 부끄럽습니다.

    조금만 시간을 내어서 지도편달 부탁드립니다.

    혹시나 도움이 될까해서 메일 주소 남기겠습니다. -didion@naver.com

  15. id는 레이아웃에서 EditText에 지정한 id를 의미합니다. 즉 레이아웃에서 EditText에 지정한 id에 따라 해당 부분은 수정해주어야 합니다.

  16. Blog Icon
    궁금이

    mp3 파일에서 소리의 파장, 박자 비트등을 파라미터로 전송해주는 클래스나 그런 방법없을까요? 이러한걸 기준으로 음원리듬게임을 만들려고 하거든ㄷ요

  17. Blog Icon
    조니준

    강좌가 너무 잘 되어있네요...지금 앱데스크 어플을 만들고 있는데 정말 유용하게 잘 보고 있습니다...감사합니다~ ^^

  18. 좋은글 출처를 표시하고 블로그에 담아갑니다. ^^

  19. Blog Icon
    Jin

    혹시 MediaPlayer를 실행했는데, QCMediaPlayer could not located 등등의 QCMediaPlayer에 관한 에러가 발생하는데, 무슨 문제인지 아시나요?? 다른 분들은 다 되시는데, 저만 안되서.. 디바이스 바꿔서 실행해봐도 같은 에러가 발생합니다...