일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- APK 동적로딩
- convert Intent to string
- 오픈소스라이선스
- so파일 동적로딩
- 음량표준화
- enum performance
- Service관리
- Dagger2란
- android enum
- callstack 출력
- 네트워크 디버깅
- HashMap vs ArrayMap
- Replaygain
- mitmproxy
- android network
- java callstack
- BlockingQueue Capacity
- lufs
- gitignore작성법
- gitignore
- APK로딩
- MediaDataSource
- print callstack
- RxJava 스터디
- convert string to intent
- Intent String 변환
- RxJava Programming
- Service 팁
- ArrayMap
- corePoolSize
- Today
- Total
일상&개발 로그
MediaDataSource를 이용한 프로그레시브 재생 구현 본문
Android에서 제공하는 기본 MediaPlayer는 Uri, FilePath, FileDescriptor만 dataSource로 지정 가능 했습니다.
또 내부로직이 거의 native로 구현되어 reflection의 여지도 없었습니다.
그래서 다운로드와 동시에 재생하는 버퍼링을 외부에서 구현할 수 없었습니다.
(setDataSource를 이용하면 MediaPlayer내부에서 버퍼링하긴 합니다.)
MarshMallow부터 제공되는 MediaDataSource를 이용하면 외부에서도 버퍼링처럼 동작하도록 구현이 가능합니다.
(주의: 제공되는 음원포맷이 프로그레시브 다운로드를 지원해야합니다.)
@RequiresApi(api = Build.VERSION_CODES.M)
public class BufferMediaDataSource extends MediaDataSource {
private volatile byte[] mBuffer; // byte array for whole media
private int fileSize;
private int writeIndex;
private BufferListener listener;
public BufferMediaDataSource(long fileSize, BufferListener listener) {
this.fileSize = Integer.parseInt(String.valueOf(fileSize));
mBuffer = new byte[this.fileSize];
this.listener = listener;
}
public void inputData(byte[] data, int length) {
if (mBuffer != null) {
System.arraycopy(data, 0, mBuffer, writeIndex, length);
writeIndex += length;
}
}
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
if(position == writeIndex) {
return -1;
}
if(position + size > writeIndex) {
if(fileSize == writeIndex) {
int rest = (int) (writeIndex - position);
System.arraycopy(mBuffer, (int) position, buffer, offset, rest);
return rest;
} else {
// loading data is faster than downloading data.
try {
Thread.sleep(300); // wait a second for downloading.
// or MediaPlayer.pause();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (mBuffer != null) {
System.arraycopy(mBuffer, (int) position, buffer, offset, size);
return size;
}
return 0;
}
@Override
public long getSize() throws IOException {
return fileSize;
}
@Override
public void close() throws IOException {
mBuffer = null;
}
}
MediaPlayer가 reatAt을 통해 byte[]를 계속 읽어가기 때문에 inputData를 통해 mBuffer를 계속 채워줘야 합니다.
readAt의 파라미터 중 position은 읽기 시작하는 위치, buffer는 MediaPlayer가 읽을 버퍼, offset은 offset, size는 버퍼 크기입니다.
유의할 점은 읽어야 하는 위치가 아직 준비되지 않았을 경우 MediaPlayer를 pause시켜야 하고 마지막으로 읽어갈 사이즈는 기존 버퍼 사이즈보다 작기 때문에 읽어가는 값 만큼 return을 해줘야 합니다.
'개발 > 안드로이드 개발' 카테고리의 다른 글
mitmproxy를 이용한 Android 네트워크 디버깅 (0) | 2018.08.24 |
---|---|
미디어 음량 표준화 - ReplayGain 적용하기 (0) | 2017.09.13 |
[PerformancePattern] Enum (0) | 2017.05.23 |
[PerformancePattern] ArrayMap vs HashMap (0) | 2017.05.22 |
[PerformancePatterns] Service 올바르게 사용하기 (0) | 2017.05.18 |