Android多媒體開發 音樂播發以及使用SoundPool播放音效

tags:    時間:2014-04-07 16:39:04
Android多媒體開發 音樂播放以及使用SoundPool播放音效

音樂播放

MediaPlayer mediaPlayer = new MediaPlayer();

if (mediaPlayer.isPlaying()) {
   mediaPlayer.reset();//重置為初始狀態
}
mediaPlayer.setDataSource("/mnt/sdcard/god.mp3");
mediaPlayer.prepare();
mediaPlayer.start();//開始或恢復播放
mediaPlayer.pause();//暫停播放
mediaPlayer.start();//恢復播放
mediaPlayer.stop();//停止播放
mediaPlayer.release();//釋放資源
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {//播出完畢事件
        @Override public void onCompletion(MediaPlayer arg0) {
   mediaPlayer.release();
        }
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {// 錯誤處理事件
         @Override public boolean onError(MediaPlayer player, int arg1, int arg2) {
mediaPlayer.release();
return false;
         }

});

音樂播放代碼示例:

DemoActivity.java:
package cn.itcast.mp3;  import java.io.File; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnPreparedListener; import android.os.Bundle; import android.os.SystemClock; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Chronometer; import android.widget.Chronometer.OnChronometerTickListener; import android.widget.EditText; import android.widget.Toast;  public class DemoActivity extends Activity implements OnClickListener, 		OnChronometerTickListener { 	private EditText et_path; 	private Chronometer et_time; 	private Button bt_play, bt_pause, bt_replay, bt_stop; 	private MediaPlayer mediaPlayer; 	private TelephonyManager manager; 	/** 	 * subtime:點擊「續播」到暫停時的間隔的和 beginTime:重新回到播放時的bash值 falgTime:點擊「播放」時的值 	 * pauseTime:「暫停」時的值 	 */ 	private long subtime = 0, beginTime = 0, falgTime = 0, pauseTime = 0;  	@Override 	public void onCreate(Bundle savedInstanceState) { 		super.onCreate(savedInstanceState); 		setContentView(R.layout.main); 		manager = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE); 		manager.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);  		et_path = (EditText) this.findViewById(R.id.et_path); 		et_time = (Chronometer) this.findViewById(R.id.et_time); 		bt_play = (Button) this.findViewById(R.id.play); 		bt_pause = (Button) this.findViewById(R.id.pause); 		bt_replay = (Button) this.findViewById(R.id.replay); 		bt_stop = (Button) this.findViewById(R.id.stop);  		bt_play.setOnClickListener(this); 		bt_pause.setOnClickListener(this); 		bt_replay.setOnClickListener(this); 		bt_stop.setOnClickListener(this); 		et_time.setOnChronometerTickListener(this);  	}  	public void onClick(View v) { 		String path; 		try { 			switch (v.getId()) { 			case R.id.play: 				falgTime = SystemClock.elapsedRealtime(); 				path = et_path.getText().toString().trim(); 				play(path); 				pauseTime = 0; 				et_time.setBase(falgTime); 				et_time.start(); 				break; 			case R.id.pause: 				pause(); 				break; 			case R.id.replay: 				if (mediaPlayer != null && mediaPlayer.isPlaying()) { 					mediaPlayer.seekTo(0); 					et_time.setBase(SystemClock.elapsedRealtime()); 					et_time.start(); 				} else { 					path = et_path.getText().toString().trim(); 					play(path); 					et_time.setBase(SystemClock.elapsedRealtime()); 					et_time.start();  				} 				if ("續播".equals(bt_pause.getText().toString().trim())) { 					bt_pause.setText("暫停");  				} 				falgTime = SystemClock.elapsedRealtime(); 				subtime = 0; 				break; 			case R.id.stop: 				if (mediaPlayer != null && mediaPlayer.isPlaying()) { 					mediaPlayer.stop(); 					mediaPlayer = null; 					et_time.setBase(SystemClock.elapsedRealtime()); 					et_time.start(); 					et_time.stop(); 					bt_play.setEnabled(true); 					bt_play.setClickable(true); 				} 				falgTime = 0; 				subtime = 0; 				break;  			} 		} catch (Exception e) { 			e.printStackTrace(); 			Toast.makeText(getApplicationContext(), "文件播放出現異常", 0).show(); 		}  	}  	private void pause() { 		// 判斷音樂是否在播放  		if (mediaPlayer != null && mediaPlayer.isPlaying()) { 			// 暫停音樂播放器 			mediaPlayer.pause(); 			bt_pause.setText("續播"); 			et_time.stop();  			pauseTime = SystemClock.elapsedRealtime(); 			System.out.println("1 pauseTime" + pauseTime); 		} else if (mediaPlayer != null 				&& "續播".equals(bt_pause.getText().toString())) { 			subtime += SystemClock.elapsedRealtime() - pauseTime; 			System.out.println("2 subtime:" + subtime); 			mediaPlayer.start(); 			bt_pause.setText("暫停"); 			beginTime = falgTime + subtime; 			System.out.println("3 beginTime" + beginTime); 			et_time.setBase(beginTime); 			et_time.start(); 		} 	}  	/** 	 * 播放指定地址的音樂文件 .mp3 .wav .amr 	 *  	 * @param path 	 */ 	private void play(String path) throws Exception { 		if ("".equals(path)) { 			Toast.makeText(getApplicationContext(), "路徑不能為空", 0).show(); 			return; 		} 		File file = new File(path); 		if (file.exists()) { 			// 如果文件存在 才進行播放操作 			// if (mediaPlayer == null) { 			mediaPlayer = new MediaPlayer(); 			mediaPlayer.setDataSource(path); 			// mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化 			// 同步方法 			// 採用非同步的方式 			mediaPlayer.prepareAsync(); 			// 為播放器註冊 			mediaPlayer.setOnPreparedListener(new OnPreparedListener() {  				public void onPrepared(MediaPlayer mp) { 					// TODO Auto-generated method stub 					mediaPlayer.start(); 					bt_play.setEnabled(false); 					bt_play.setClickable(false); 				} 			});  			// 註冊播放完畢后的監聽事件 			mediaPlayer.setOnCompletionListener(new OnCompletionListener() {  				public void onCompletion(MediaPlayer mp) { 					mediaPlayer.release(); 					mediaPlayer = null; 					bt_play.setEnabled(true); 					bt_play.setClickable(true); 					et_time.setBase(SystemClock.elapsedRealtime()); 					et_time.start(); 					et_time.stop(); 				} 			});  			// }else{ 			// mediaPlayer.reset(); // 重置 播放器的狀態 			// mediaPlayer.setDataSource(path); 			// mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化 			// mediaPlayer.start(); 			// }  		} else { 			Toast.makeText(getApplicationContext(), "文件不存在", 0).show(); 			return; 		}  	}  	private class MyListener extends PhoneStateListener {  		@Override 		public void onCallStateChanged(int state, String incomingNumber) { 			super.onCallStateChanged(state, incomingNumber); 			switch (state) { 			case TelephonyManager.CALL_STATE_RINGING: 				// 音樂播放器暫停 				pause(); 				break; 			case TelephonyManager.CALL_STATE_IDLE: 				// 重新播放音樂 				pause(); 				break; 			} 		} 	}  	public void onChronometerTick(Chronometer chronometer) {  	} }
main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:orientation="vertical" >      <TextView         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="請輸入音樂的路徑" />      <Chronometer         android:id="@+id/et_time"         android:layout_width="fill_parent"         android:layout_height="wrap_content" />      <EditText         android:id="@+id/et_path"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="/sdcard/e.mp3" />      <LinearLayout         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:gravity="center_horizontal"         android:orientation="horizontal" >          <Button             android:id="@+id/play"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:text="播放" />          <Button             android:id="@+id/pause"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:text="暫停" />          <Button             android:id="@+id/replay"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:text="重播" />          <Button             android:id="@+id/stop"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:text="停止" />     </LinearLayout>  </LinearLayout>

使用SoundPool播放音效:

   在Android開發中我們經常使用MediaPlayer來播放音頻文件,但是MediaPlayer存在一些不足,例如:資源佔用量較高、延遲時間較長、不支持多個音頻同時播放等。這些缺點決定了MediaPlayer在某些場合的使用情況不會很理想,例如在對時間精準度要求相對較高的遊戲開發中。 
   在遊戲開發中我們經常需要播放一些遊戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下,我們可以使用SoundPool代替MediaPlayer來播放這些音效。 
   SoundPool(android.media.SoundPool),顧名思義是聲音池的意思,主要用於播放一些較短的聲音片段,支持從程序的資源或文件系統載入。與MediaPlayer相比,SoundPool的優勢在於CPU資源佔用量低和反應延遲小。另外,SoundPool還支持自行設置聲音的品質、音量、播放比率等參數,支持通過ID對多個音頻流進行管理。
   就現在已知的資料來說,SoundPool有一些設計上的BUG,從固件版本1.0開始有些還沒有修復,我們在使用中應該小心再小心。相信將來Google會修復這些問題,但我們最好還是列出來:
  1. SoundPool最大隻能申請1M的內存空間,這就意味著我們只能用一些很短的聲音片段,而不是用它來播放歌曲或者做遊戲背景音樂。
  2. SoundPool提供了pause和stop方法,但這些方法建議最好不要輕易使用,因為有些時候它們可能會使你的程序莫名其妙的終止。建議使用這兩個方法的時候儘可能多做測試工作,還有些朋友反映它們不會立即中止播放聲音,而是把緩衝區里的數據播放完才會停下來,也許會多播放一秒鐘。
  3. SoundPool的效率問題。其實SoundPool的效率在這些播放類中算是很好的了,但是有的朋友在G1中測試它還是有100ms左右的延遲,這可能會影響用戶體驗。也許這不能管SoundPool本身,因為到了性能比較好的Droid中這個延遲就可以讓人接受了。
  在現階段SoundPool有這些缺陷,但也有著它不可替代的優點,基於這些我們建議大在如下情況中多使用SoundPool:
      1.應用程序中的聲效(按鍵提示音,消息等)2.遊戲中密集而短暫的聲音(如多個飛船同時爆炸)

開發步驟:
1> 往項目的res/raw目錄中放入音效文件。
2> 新建SoundPool對象,然後調用SoundPool.load()載入音效,調用SoundPool.play()方法播放指定音效文件。
public class AudioActivity extends Activity {
private SoundPool pool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//指定聲音池的最大音頻流數目為10,聲音品質為5
pool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
final int sourceid = pool.load(this, R.raw.pj, 0);//載入音頻流,返回在池中的id
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//播放音頻,第二個參數為左聲道音量;第三個參數為右聲道音量;第四個參數為優先順序;第五個參數為循環次數,0不循環,-1循環;第六個參數為速率,速率最低0.5最高為2,1代表正常速度
pool.play(sourceid, 1, 1, 0, -1, 1);
}
});
}
}

使用SoundPool播放音效代碼示例:

DemoActivity.java:

package cn.itcast.soundpool;  import android.app.Activity; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.view.View;  public class DemoActivity extends Activity { 	int soundid; 	SoundPool pool;  	@Override 	public void onCreate(Bundle savedInstanceState) { 		super.onCreate(savedInstanceState); 		setContentView(R.layout.main); 		pool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); 		// 這語句代碼 是一個非同步的操作 		soundid = pool.load(this, R.raw.ring, 1); // 需要花費一定的時間 	}  	public void shoot(View view) { 		// 不會播放 因為上面非同步的載入聲音的操作 還沒完成 		pool.play(soundid, 1.0f, 1.0f, 0, 0, 1.0f); 		// taking tom 	} }

推薦閱讀文章

Bookmark the permalink ,來源:互聯網