SoundPool을 사용하여 효과음 재생(Duang~)


이 섹션 소개:

9장에서는 Android의 멀티미디어 개발을 다루기보다는 멀티미디어 관련 API에 대해 설명합니다. MediaPlayer를 호출하여 음악 파일을 찾고, 그런 다음 재생 메서드를 호출하여 재생합니다... 물론 실제 멀티미디어 개발은 ​​오디오 및 비디오 인코딩 및 디코딩이라는 또 다른 분야입니다. 우리가 이러한 API를 호출하는 방법을 알고 있다면 지금은 찾아보고 기다릴 수 밖에 없습니다! 그건 그렇고, 우리는 여전히 안드로이드 멀티미디어를 대중화해야 합니다 프레임워크에 대한 상식:

Android에서 기본 멀티미디어 프레임워크는

OpenCore

입니다. OpenCore의 장점은 두 가지 모두를 고려한다는 것입니다. 크로스 플랫폼 이식성이 뛰어나고 많은 당사자로부터 검증을 받았기 때문에 상대적으로 안정적이지만 너무 크고 복잡하다는 단점이 있습니다. 유지하는데 시간이 많이 걸립니다. 구글은 안드로이드 2.0부터 조금 더 단순한 아키텍처를 갖춘 Stagefright를 선보였습니다. 물론 OpenCore를 완전히 버린 것은 아니고 주로 OpenCore를 변형한 OMX 레이어를 만들었습니다. omx 구성 요소 부분이 참조됩니다. 점차적으로 OpenCORE를 대체하는 경향이 있었는데, 올해 8월에 제가 발견한 것은 특수 제작된 MMS 메시지를 악용하여 원격 코드 실행을 허용하는 Stagefright 취약점입니다. 이 취약점은 Android 2.2 이상 버전에 영향을 미치며 Android 4.1 이상 버전에는 상대적으로 약한 영향을 미칩니다.

무슨 말인지 모르겠어요(JB가 무슨 말을 하는지도 모르겠어요) 음, 알았어, 과학은 끝났어... 이런거 알면 좋다! 1.jpg그런데 이 멀티미디어 프레임워크는 Android 아키텍처의 세 번째 레이어(

Libraries

)의 Media Framework에 있습니다! 또한 Android 멀티미디어 프레임워크에서 지원되는 오디오 및 비디오 데이터 유형을 알고 싶다면 공식 문서를 참조하세요.

지원되는 미디어 형식

여기

미디어 및 카메라

를 직접 클릭한 다음 다음 문서를 보세요: 2.png

글쎄, 초반에 헛소리가 너무 많아서 오늘의 주인공은 SoundPool이라는 사실을 잊어버릴 뻔 했습니다. 제목 그대로 SoundPool이 일반적으로 사용됩니다. 게임에서 자주 사용되는 특수 효과: Duang~ 등 집중적이고 빠르며 수명이 짧은 음향 효과를 재생할 수도 있습니다. 예를 들어 Kugou Music을 재생하면 "Hello, Kugou"가 재생됩니다. 실제로 이 아이디어는 꽤 좋습니다. 사용자에게 플레이어의 현재 볼륨을 간접적으로 알려주거나, 사용자가 노래를 재생하자마자 갑자기 작은 사과가 나타나 근처의 사람들을 끌어당깁니다. 아줌마가 춤추면 안 되겠죠? 뮤직 플레이어에 추가하는 것 외에 푸시 알림을 받는 등 일반 APP에도 추가할 수 있죠. 메시지나 새 채팅 메시지를 입력한 다음 새 버전의 슈퍼 커리큘럼과 같은 프롬프트 사운드를 재생하고, 이것을 추가하고, 푸시 알림을 받습니다. 메시지는 짧은 "테이블" 소리를 재생합니다! SoundPool 객체는 APK에서 가져올 수 있는 리소스로 볼 수 있습니다. 또는 파일 시스템에서 샘플 파일 컬렉션을 로드합니다. MediaPlayer 서비스를 활용하여 오디오를 원시 16비트 오디오로 디코딩합니다. PCM 스트림. 이 기능을 사용하면 애플리케이션이 오디오 재생 중 압축 해제로 인한 CPU로드 및 대기 시간을 겪지 않고도 스트림 압축을 수행할 수 있습니다. SoundPool은 사운드 풀 개념을 사용하여 여러 플레이어 스트림을 관리합니다. 최대 스트림 수를 초과하면 SoundPool은 우선순위에 따라 이전에 재생된 스트림을 자동으로 중지합니다. 또한 SoundPool은 음질 설정도 지원합니다. 볼륨, 재생 비율 및 기타 매개변수. 좋습니다. 더 이상 고민하지 말고 이 섹션을 시작해 보겠습니다. 공식 API 문서: SoundPool


1. 관련 메소드 소개:


1) 구축 메소드:

SoundPool(int maxStreams, int streamType, int srcQuality) 매개변수는 다음과 같습니다.

  • ①지원되는 사운드 수와 SoundPool 개체에 동시에 존재할 수 있는 최대 스트림 수를 지정합니다.
  • ②사운드 유형을 지정합니다. 스트림 유형은 STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSICSTREAM_ALARM의 네 가지 유형으로 나눌 수 있습니다. AudioManager에 정의되어 있습니다.
  • ③음질(샘플링 레이트 변환 품질)을 지정하세요. 일반적으로 0으로 직접 설정됩니다!

위 구성 방법은 하위 버전에서도 사용할 수 있지만 API 21(Android 5.0) 이후에는 이 구성 방법이 사용되지 않습니다! SoundPool.Builder를 사용할 때 SoundPool을 인스턴스화하려면 다음을 호출하기만 하면 됩니다.

SoundPool.Builder spb = new SoundPool.Builder();
spb.setMaxStreams(10);
spb.setAudioAttributes(null);    //转换音频格式
SoundPool sp = spb.build();      //创建SoundPool对象

위 코드를 사용하려면 TargetSDK 버전을 21 이상으로 설정해야 합니다! minSDK 버전이 21 미만인 경우 다음 알림이 표시됩니다.

3.png


2) 일반적인 방법 소개:


사운드 리소스 로드 중:

  • load(컨텍스트 컨텍스트, int resId, int 우선순위)
  • load(문자열 경로, int 우선순위)
  • load(FileDescriptor fd, 긴 오프셋, 긴 길이, int 우선순위)
  • load (AssetFileDescriptor afd, int 우선순위) 위의 메소드는 모두 사운드 ID를 반환하고 나중에 이 ID를 사용하여 지정된 사운드

매개변수 소개:

  • context: context
  • resId: 리소스 ID
  • priority: 쓸모 없는 매개변수 , 향후 호환성을 유지하기 위해 1로 설정하는 것이 좋습니다
  • path: 파일 경로
  • FileDescriptor: 스트림인 것 같은데, 모르겠습니다.
  • AssetFileDescriptor: 자산에서 특정 리소스 파일을 읽습니다. 디렉터리, 사용법: AssetFileDescriptor 설명자 = AssetManager.openFd("biaobiao.mp3");

재생 제어:

play(int soundID, float leftVolume, float rightVolume, int 우선 순위, int loop, float rate)

매개변수는 다음과 같습니다:

  • soundID: Load()에서 반환된 사운드 ID 번호
  • leftVolume: 왼쪽 채널 볼륨 설정
  • rightVolume: 오른쪽 채널 볼륨 설정
  • priority: 우선순위 지정 재생 중인 사운드의 값이 높을수록 우선순위가 높을수록 우선순위가 높아집니다.
  • loop: 반복 여부 지정: -1은 무한 루프, 0은 반복 없음, 다른 값은 반복 재생 횟수를 나타냅니다.
  • rate: 재생 속도를 지정합니다. 1.0의 재생 속도는 사운드는 원래 주파수를 따르지만 재생 속도는 2.0 재생 속도이므로 사운드가 원래 주파수를 따를 수 있습니다. 원래 주파수의 두 배로 재생합니다. 재생 속도가 0.5라면 재생 속도는 원래 주파수의 절반이 됩니다. 재생 속도 범위는 0.5에서 2.0입니다.

3Resource release:

release() 메서드를 호출하여 모든 SoundPool 객체가 차지하는 메모리와 리소스를 해제할 수 있습니다. 물론 사운드를 기반으로 해제할 수도 있습니다. 아이디 공개!


3. 사용 코드 예:

렌더링 실행 :

4.png

버튼을 클릭하면 "Duang"이라는 두 가지 로드 방법이 나타납니다.

Key code:

MainActivity.java:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_play1;
    private Button btn_play2;
    private Button btn_play3;
    private Button btn_play4;
    private Button btn_play5;
    private Button btn_release;
    private AssetManager aManager;
    private SoundPool mSoundPool = null;
    private HashMap soundID = new HashMap();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        aManager = getAssets();
        try {
            initSP();
        } catch (Exception e) {
            e.printStackTrace();
        }
        bindViews();
    }

    private void bindViews() {
        btn_play1 = (Button) findViewById(R.id.btn_play1);
        btn_play2 = (Button) findViewById(R.id.btn_play2);
        btn_play3 = (Button) findViewById(R.id.btn_play3);
        btn_play4 = (Button) findViewById(R.id.btn_play4);
        btn_play5 = (Button) findViewById(R.id.btn_play5);
        btn_release = (Button) findViewById(R.id.btn_release);

        btn_play1.setOnClickListener(this);
        btn_play2.setOnClickListener(this);
        btn_play3.setOnClickListener(this);
        btn_play4.setOnClickListener(this);
        btn_play5.setOnClickListener(this);
        btn_release.setOnClickListener(this);

    }

    private void initSP() throws Exception{
        //设置最多可容纳5个音频流,音频的品质为5
        mSoundPool = new SoundPool(5, AudioManager.STREAM_SYSTEM, 5);
        soundID.put(1, mSoundPool.load(this, R.raw.duang, 1));
        soundID.put(2 , mSoundPool.load(getAssets().openFd("biaobiao.mp3") , 1));  //需要捕获IO异常
        soundID.put(3, mSoundPool.load(this, R.raw.duang, 1));
        soundID.put(4, mSoundPool.load(this, R.raw.duang, 1));
        soundID.put(5, mSoundPool.load(this, R.raw.duang, 1));
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_play1:
                mSoundPool.play(soundID.get(1), 1, 1, 0, 0, 1);
                break;
            case R.id.btn_play2:
                mSoundPool.play(soundID.get(2), 1, 1, 0, 0, 1);
                break;
            case R.id.btn_play3:
                mSoundPool.play(soundID.get(3), 1, 1, 0, 0, 1);
                break;
            case R.id.btn_play4:
                mSoundPool.play(soundID.get(4), 1, 1, 0, 0, 1);
                break;
            case R.id.btn_play5:
                mSoundPool.play(soundID.get(5), 1, 1, 0, 0, 1);
                break;
            case R.id.btn_release:
                mSoundPool.release();   //回收SoundPool资源
                break;
        }
    }
}

코드는 아주 간단하며, 마지막 버튼을 클릭하면 SoundPool이 해제되고, 그 다음에는 다른 버튼들이 해제됩니다. Duang은 아닐 겁니다~


4.OnLoadCompleteListener는 사운드 파일이 완전히 로드되었는지 모니터링합니다

글쎄, 이게 일시적으로 다른 글을 쓰다가 갑자기 생각나서 사용법도 매우 간단합니다. 위 코드에 OnLoadCompleteListener를 추가한 다음 onLoadComplete() 메서드를 재정의합니다. , 마지막으로 SoundPool 객체에 대해 이것을 설정합니다!

mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
    @Override
    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
        Toast.makeText(MainActivity.this,"加特技准备完毕~",Toast.LENGTH_SHORT).show();
    }
});

5. 샘플 코드 다운로드:

SoundPoolDemo.zip


이 섹션 요약:

좋아, 이 섹션에서는 Andorid 멀티미디어에 대한 상식을 제공하고 이를 수행하는 방법을 알려줍니다. 자신의 앱에 음향 효과를 추가하고, 간단한 SoundPool을 통해 달성할 수 있습니다. 무엇을 기다리고 계십니까? Duang~

5.gif

, 데모와 함께 사용하는 것이 좋습니다~