Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

집요정 도비의 일기

Step 4. 음악 스트리밍 서버(Spring boot), 앱(Android)을 만들어보자. 본문

개발 일기

Step 4. 음악 스트리밍 서버(Spring boot), 앱(Android)을 만들어보자.

집요정_도비 2016. 3. 5. 15:27

15. 목적

- 음악 스트리밍이 가능하게 한다.

* How?

두 가지 방법 정도를 생각하였다.

1. 파일을 전부 다운로드 한 후, 안드로이드의 파일 시스템에서 파일을 찾아서 재생한다.

2. MediaPlayer 객체를 활용하여 서버의 url로 파일을 재생한다.


처음에는 조사가 부족하여 1의 방법으로 구현하였으나, 보다 클라이언트 소스가 간결한 2번을 찾게되었다.

본 포스트에서는 2번의 방법으로 구현한다.



16-1. 서버(Spring boot) 구현

- 서버가 음악 파일에 대한 적절한 url을 제공할 필요가 있다.

- 따라서 기존의 RequestController에 아래와 같은 메소드를 추가한다.

* RequestController.java

- 동작 원리는 무척 단순하다. 요청 받은 파일이 존재하면 파일을 스트림에 써준다.

- URLDecoder가 필요한 이유는 16-2에서 설명.

- 이 메소드는 사실 MediaPlayer 말고도, 단순 파일을 다운로드 받는데도 사용 가능하다. 


서버 끝.


16-2. 안드로이드 구현

- 저번 포스트에서 MainActivity.java의 MainClickListener에서 하다만 작업을 완성한다.

- 앞선 포스트들에서는 HttpSender를 상속받는 클래스들을 통하여 서버에 request를 보냈지만, 이번엔 그러지 않는다.

- Response를 처리하기 위한 ResultHandler도 사용하지 않는다.

- MediaPlayer자체가 url만 주면 알아서 파일을 받아서 재생해주기 때문이다.

- 만약, 파일을 다운로드 받아서 스마트폰의 특정 디렉토리에 저장하길 원한다면, HttpSender를 상속받는 클래스와, ResultHandler와는 다른 핸들러를 하나 더 구현하여 받으면 된다.  


*구현 순서 (Steps)

(1) MediaPlayer객체에서 사용하기 위한 URL을 조립한다.

(2) (1)의 URL을 이용하여 서버의 음악 파일을 재생한다. 

특별한 설명 없이 바로 구현에 들어감.


(1) MediaPlayer객체에서 사용하기 위한 URL을 조립한다.

* MainActivity.java

private class MainListListener implements MainListAdapter.MainItemClickListener {

@Override
public void onClick(FileItem item, int position) {

if (item.isGoBack) {
//pressed go back button...
Log.e("MAIN_CLICK", "GO BACK");
int index = StaticVals.MovedDirectory.size() - 1;
StaticVals.MovedDirectory.remove(index);
doMoveDirectory();
} else {
if (!item.isFile) {
//If the selection is a directory, move.
Log.e("MAIN_CLICK", "DIRECTORY");
StaticVals.MovedDirectory.add(item.fileName);
doMoveDirectory();
} else { //여기서부터 구현
//if it's a file, play it.
try {
String url = HttpSender.URL + "/download?name=";
String contents = "";
for (String dir : StaticVals.MovedDirectory) {
contents += dir + "\\";
}

url = url + URLEncoder.encode(contents + item.fileName, "UTF-8");

//play
StartMusic(url);

} catch (Exception e) {
Log.e("MUSIC", e.getMessage());
}
}
}
}
}

-위의 소스는 MediaPlayer가 사용하기 위한 파일의 url을 조립하는 과정이다. ( StartMusic() 메소드는 후술)

(ㄱ) 먼저, 기본 url을 만든다. 이런 모습이 될 것이다.

"http://11.111.111.111:8080/download?name="

서버의 RequestController의 '/download'의 형식이 GET으로 되있기 때문이 이런 구조를 취할 필요가 있다.


(ㄴ) 선택한 파일의 이름과 디렉토리를 세팅한다. 우선 List<String> MovedDirectory의 요소들 + "\"를 통해 디렉토리를 맞추고, 마지막으로 파일 이름을 더한다.


(ㄷ) **URL ENCODING GET방식일 때는 공백, 특수문자 등은 제약이 있다. 예를 들어, 파일 경로가 아래와 같을 경우다.

Persona 4/Shadow World.mp3

이를 인코딩 없이 조립하면 아래와 같아진다.

"http://11.111.111.111:8080/download?name=Persona 4\Shadow World.mp3"

서버는 공백 문자가 보일 시, 쿼리문이 끝났다고 보기 때문에, 서버에서는 http://11.111.111.111:8080/download?name=Persona 까지 밖에 받지 못한다.

따라서 없는 파일에 대한 File객체를 생성하게 되므로 당연히 에러가 발생한다.

이런 에러를 피하기 위해서 UTF-8으로 ?name= 이후의 쿼리를 인코딩한다.




(2) (1)의 URL을 이용하여 서버의 음악 파일을 재생한다. 

우선 MainActivity.java에 MediaPlayer 필드를 추가한다.

private MediaPlayer mediaPlayer;


* MainActivity.java

public void StartMusic(String url) {
try {

if(mediaPlayer!=null){
mediaPlayer.stop();
}

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Log.e("PREPARED", "STARTING Music");
mp.start();
}
});

} catch (Exception e) {
Log.e("MusicPlayer", e.getMessage());
}
}

- (1)의 마지막에 호출되는 StartMusic() 메소드를 구현한다.

(ㄱ) 위 소스는 딱히 설명할 구석이 없다. MediaPlayer객체가 null이 아니면 재생 중인 음악이 있다는 것이므로 일단 음악을 종료한다.

(ㄴ) MediaPlayer객체를 생성 후, (1)에서 생성한 url을 입력하여 준비(prepareAsync)한 후, 준비가 완료되면 음악을 재생한다.


17. 테스트

- 포스트에 업로드할 수단이 없지만, 파일이 문제 없이 재생되었다.

- 다만, 아직은 재생만 될 뿐, 재생 중 특정 위치로 이동하기는 커녕 앱을 완전히 죽이는거 외에는 음악을 끌 수도 없다.


18. ToDo..

- 재생된 음악을 제어하기 위한 적절한 UI의 추가, 그리고 그 UI의 기능을 구현한다.




Comments