zoukankan      html  css  js  c++  java
  • android中常见声音操作方式(Ringtone,SoundPool,MediaPlayer)小结

    Android开发中有时候需要用到播放声音操作,在android API 的media包中有三种方式可供我们选择,它们分别是Ringtone,SoundPool,MediaPlayer。因为在我目前的项目中暂时用不到播放很长的音频文件,只需要播放一些简短的提示音,所以在这篇博文中我只是简单的记录下。

    • 1.Ringtone.java
    • 2.SoundPool.java
    • 3.MediaPlayer.java
    • 4.demo
    • 5.bug record

    注意:
    关于这三个类的介绍我全部用的是android 自身的Java doc描述;
    全部摘自于android-23;
    因为我的项目中主要用到Ringtone,所以展示了它全部的描述;

    1.Ringtone.java

    关于Ringtone的介绍。

    package android.media;
    /**
     * Ringtone provides a quick method for playing a ringtone, notification, or
     * other similar types of sounds.
     * <p>
     * For ways of retrieving {@link Ringtone} objects or to show a ringtone
     * picker, see {@link RingtoneManager}.
     * 
     * @see RingtoneManager
     */
     public class Ringtone {}

    2.SoundPool.java

    关于SoundPool的介绍。

    /**
     * The SoundPool class manages and plays audio resources for applications.
     *
     * <p>A SoundPool is a collection of samples that can be loaded into memory
     * from a resource inside the APK or from a file in the file system. The
     * SoundPool library uses the MediaPlayer service to decode the audio
     * into a raw 16-bit PCM mono or stereo stream. This allows applications
     * to ship with compressed streams without having to suffer the CPU load
     * and latency of decompressing during playback.</p>
     *
     * <p>In addition to low-latency playback, SoundPool can also manage the number
     * of audio streams being rendered at once. When the SoundPool object is
     * constructed, the maxStreams parameter sets the maximum number of streams
     * that can be played at a time from this single SoundPool. SoundPool tracks
     * the number of active streams. If the maximum number of streams is exceeded,
     * SoundPool will automatically stop a previously playing stream based first
     * on priority and then by age within that priority. Limiting the maximum
     * number of streams helps to cap CPU loading and reducing the likelihood that
     * audio mixing will impact visuals or UI performance.</p> 
     *
     * <p>Sounds can be looped by setting a non-zero loop value. A value of -1
     * causes the sound to loop forever. In this case, the application must 
     * explicitly call the stop() function to stop the sound. Any other non-zero
     * value will cause the sound to repeat the specified number of times, e.g.
     * a value of 3 causes the sound to play a total of 4 times.</p>
     *
     * <p>The playback rate can also be changed. A playback rate of 1.0 causes
     * the sound to play at its original frequency (resampled, if necessary,
     * to the hardware output frequency). A playback rate of 2.0 causes the
     * sound to play at twice its original frequency, and a playback rate of
     * 0.5 causes it to play at half its original frequency. The playback
     * rate range is 0.5 to 2.0.</p>
     *
     * <p>Priority runs low to high, i.e. higher numbers are higher priority.
     * Priority is used when a call to play() would cause the number of active
     * streams to exceed the value established by the maxStreams parameter when
     * the SoundPool was created. In this case, the stream allocator will stop
     * the lowest priority stream. If there are multiple streams with the same
     * low priority, it will choose the oldest stream to stop. In the case
     * where the priority of the new stream is lower than all the active
     * streams, the new sound will not play and the play() function will return
     * a streamID of zero.</p>
     *
     * <p>Let's examine a typical use case: A game consists of several levels of
     * play. For each level, there is a set of unique sounds that are used only
     * by that level. In this case, the game logic should create a new SoundPool
     * object when the first level is loaded. The level data itself might contain
     * the list of sounds to be used by this level. The loading logic iterates
     * through the list of sounds calling the appropriate SoundPool.load()
     * function. This should typically be done early in the process to allow time
     * for decompressing the audio to raw PCM format before they are needed for
     * playback.</p>
     *
     * <p>Once the sounds are loaded and play has started, the application can
     * trigger sounds by calling SoundPool.play(). Playing streams can be
     * paused or resumed, and the application can also alter the pitch by
     * adjusting the playback rate in real-time for doppler or synthesis
     * effects.</p>
     *
     * <p>Note that since streams can be stopped due to resource constraints, the
     * streamID is a reference to a particular instance of a stream. If the stream
     * is stopped to allow a higher priority stream to play, the stream is no
     * longer be valid. However, the application is allowed to call methods on
     * the streamID without error. This may help simplify program logic since
     * the application need not concern itself with the stream lifecycle.</p>
     *
     * <p>In our example, when the player has completed the level, the game
     * logic should call SoundPool.release() to release all the native resources
     * in use and then set the SoundPool reference to null. If the player starts
     * another level, a new SoundPool is created, sounds are loaded, and play
     * resumes.</p>
     */
    public class SoundPool {}

    3.MediaPlayer.java

    package android.media;
    /**
     * MediaPlayer class can be used to control playback
     * of audio/video files and streams. An example on how to use the methods in
     * this class can be found in {@link android.widget.VideoView}.
     * For ways of retrieving {@link Ringtone} objects or to show a ringtone
     * picker, see {@link RingtoneManager}.
     * 
     * @see RingtoneManager
     */
    public class MediaPlayer implements SubtitleController.Listener{}

    4.demo

    因为这个demo很简单,就一个Activity和xml,所以我就不提供源码下载了。
    请直接看码:

    package android.media;
    package org.tuzhao.demo.activity;
    
    import android.app.Activity;
    import android.content.res.AssetFileDescriptor;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import android.media.Ringtone;
    import android.media.RingtoneManager;
    import android.media.SoundPool;
    import android.net.Uri;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    
    import org.tuzhao.sqlite.R;
    
    import java.io.IOException;
    
    /**
     * three types to play sound
     * @author tuzhao
     */
    public class SoundActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Ringtone ringtone;
    
        private SoundPool soundPool;
        private int loadId;
    
        private MediaPlayer mediaPlayer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_sound);
            //初始化这三个方法
            ringtone = initRingtone(this);
    
            soundPool = initSoundPool();
            loadId = soundPool.load(this, R.raw.beep, 1);
    
            mediaPlayer = initMediaPlayer(this, 0);
    
            findViewById(R.id.bt_ringtone).setOnClickListener(this);
            findViewById(R.id.bt_sound_pool).setOnClickListener(this);
            findViewById(R.id.bt_media).setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt_ringtone:
                    ringtone.play();
                    break;
                case R.id.bt_sound_pool:
                    soundPool.play(loadId, 1.0f, 1.0f, 0, 0, 1.0f);
                    break;
                case R.id.bt_media:
                    mediaPlayer.start();
                    break;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //release resource of this two types.
            soundPool.release();
            mediaPlayer.release();
        }
    
        /**
         * init type of Ringtone
         * @param context Activity
         * @return Ringtone
         */
        private Ringtone initRingtone(Activity context) {
            Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            return RingtoneManager.getRingtone(context, notification);
        }
    
        /**
         * init type of  SoundPool
         * @return SoundPool
         */
        @SuppressWarnings("deprecation")
        private SoundPool initSoundPool() {
    
    //      The content of the comments need API-23
    //      SoundPool.Builder builder=new SoundPool.Builder();
    //      builder.setMaxStreams(10);
    //
    //      AudioAttributes.Builder audioBuilder=new AudioAttributes.Builder();
    //      audioBuilder.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN);
    //      audioBuilder.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED);
    //      audioBuilder.setLegacyStreamType(AudioManager.STREAM_SYSTEM);
    //      audioBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION);
    //      AudioAttributes attributes = audioBuilder.build();
    //
    //      builder.setAudioAttributes(attributes);
    //      SoundPool soundPool = builder.build();
            return new SoundPool(10, AudioManager.STREAM_NOTIFICATION, 5);
        }
    
        /**
         * init type of  MediaPlayer
         * @param context Activity
         * @param rawId   the id of raw
         * @return MediaPlayer
         */
        public MediaPlayer initMediaPlayer(Activity context, int rawId) {
            context.setVolumeControlStream(AudioManager.STREAM_MUSIC);
            final MediaPlayer mediaPlayer = new MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            /**
             * When the beep has finished playing, rewind to queue up another one.
             */
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mediaPlayer.seekTo(0);
                }
            });
            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    mediaPlayer.release();
                    return true;
                }
            });
            AssetFileDescriptor file;
            if (rawId == 0) {
                file = context.getResources().openRawResourceFd(R.raw.beep);
            } else {
                file = context.getResources().openRawResourceFd(rawId);
            }
            try {
                mediaPlayer.setDataSource(file.getFileDescriptor(), 
                    file.getStartOffset(), file.getLength());
                file.close();
                float BEEP_VOLUME = 1.0f;
                mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
                mediaPlayer.prepare();
            } catch (IOException e) {
                e.printStackTrace();
                Log.i("initSpecifiedSound", "what happened to init sound? you need to deal it .");
                return null;
            }
            return mediaPlayer;
        }
    
    }
    

    下面是xml布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="org.tuzhao.sqlite.activity.SoundActivity">
    
        <Button
            android:id="@+id/bt_ringtone"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="88dp"
            android:text="Ringtone"
            android:textAllCaps="false"
            />
    
        <Button
            android:id="@+id/bt_sound_pool"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/bt_ringtone"
            android:layout_alignStart="@+id/bt_ringtone"
            android:layout_below="@+id/bt_ringtone"
            android:layout_marginTop="15dp"
            android:text="SoundPool"
            android:textAllCaps="false"/>
    
        <Button
            android:id="@+id/bt_media"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/bt_sound_pool"
            android:layout_alignStart="@+id/bt_sound_pool"
            android:layout_below="@+id/bt_sound_pool"
            android:layout_marginTop="15dp"
            android:text="MediaPlayer"
            android:textAllCaps="false"/>
        </RelativeLayout>

    5.bug record

    bugs:
    AudioTrack: AudioFlinger could not create track, status: -12
    AudioFlinger: no more track names available
    AudioSink: Unable to create audio track
    MediaPlayer: Should have subtitle controller already set

    resolve:我出现这种情况是因为我最刚开始采用的不是上面Java文件初始化的方法,而是每播放一次声音就new 一个对象来播放声音。这样能播放,但是播放了十几次就报上面的错误。正确做法是只初始化一次。
    每次调用下面这三个分别对应方法:
    soundPool.play(sourceId, 1.0f, 1.0f, 0, 0, 1.0f);
    ringtone.play();
    mediaPlayer.start();


    本人才疏学浅,出错在所难免。如文中有错误的地方望指正,谢谢!
    欢迎关注我的Github账号:https://github.com/tuzhao

  • 相关阅读:
    Cookie 学习笔记
    IEDA的图片视频等文件在Tomcat上部署不能访问的问题
    JavaWeb 的路径访问问题,以及路径命名规则。
    HttpServlet 的 Request 方法 学习笔记
    Servlet概念 ,体系结构及配置 HTTP概念
    XML学习笔记
    IDEA创建Tomcat服务器,以及新创建的JaveWeb项目(JavaEE)如何部署在Tomcat上,以及出现404的原因,以及一些设置。
    IDEA将多个项目创建在同一个文件夹下,及创建JavaWeb项目方法
    Spring JDBCTemplate对象的增删查改写法 学习笔记
    Druid 数据库连接池技术(JDBCUtils工具类的编写) 学习笔记
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6704932.html
Copyright © 2011-2022 走看看