編輯:關於Android編程
我這裡主要是用到了AudioTrack實現的左右聲道的控制,手機一般都只有兩個聲道,即左聲道和右聲道,我們在輸出的時候可以選擇單聲道,也可以選擇雙聲道(立體聲)。
查看了AudioTrack的API,提供了play()、pause()、stop()、write()等一系列的方法。
通過write()方法,可以實現將音頻數據發送出去(播放出來)。
有三個構造方法
AudioTrack (int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) AudioTrack (int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode, int sessionId) AudioTrack (AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int mode, int sessionId)
主要參數有如下幾個
streamType:以什麼形式播放
STREAM_VOICE_CALL STREAM_SYSTEM STREAM_RING STREAM_MUSIC STREAM_ALARM STREAM_NOTIFICATIONsampleRateInHz:采樣率
channelConfig:聲道
AudioFormat.CHANNEL_OUT_MONO:輸出單聲道音頻數據 AudioFormat.CHANNEL_OUT_STEREO:輸出雙聲道音頻數據(立體聲)audioFormat:音頻數據格式
mode:緩沖模式
MODE_STATIC:一次性將音頻載入以後再播放 MODE_STREAM:以流的形式,加載一點就播放一點把channelConfig的相關參數都看了一遍,沒發現有可以指定向某聲道發送數據的,只能通過AudioFormat.CHANNEL_OUT_MONO和AudioFormat.CHANNEL_OUT_STEREO選擇是輸出單聲道的音頻數據還是雙聲道的音頻數據。
構造的時候不能選擇指定聲道輸出音頻,但是有這樣一個方法
setStereoVolume(float leftGain, float rightGain)
可以通過把某一個聲道的音量設置到最小,達到只想某個聲道輸出音頻的效果。
我自己也有點”呵呵“,但是也沒有發現還有別的方法可以實現這樣的效果。
這個方法還有一點小問題,在個別手機上,即使將某個聲道的聲音設置到了最小,也還是會有一點聲音,這個我也還沒有搞清楚為什麼,個人猜測可能和手機硬件有關系。
我這裡的緩沖模式使用的MODE_STREAM的形式,以流的形式播放,因為這個邏輯要稍微復雜一點,尤其是暫停以後再繼續播放的位置。
package kong.qingwei.androidsoundmanagerdemo; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; /** * Created by kqw on 2016/8/26. * 播放音樂的線程 */ public class PlayThread extends Thread { // 采樣率 private int mSampleRateInHz = 16000; // 單聲道 private int mChannelConfig = AudioFormat.CHANNEL_OUT_MONO; // 雙聲道(立體聲) // private int mChannelConfig = AudioFormat.CHANNEL_OUT_STEREO; private static final String TAG = "PlayThread"; private Activity mActivity; private AudioTrack mAudioTrack; private byte[] data; private String mFileName; public PlayThread(Activity activity, String fileName) { mActivity = activity; mFileName = fileName; int bufferSize = AudioTrack.getMinBufferSize(mSampleRateInHz, mChannelConfig, AudioFormat.ENCODING_PCM_16BIT); mAudioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, mSampleRateInHz, mChannelConfig, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM); } @Override public void run() { super.run(); try { if (null != mAudioTrack) mAudioTrack.play(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); InputStream inputStream = mActivity.getResources().getAssets().open(mFileName); // 緩沖區 byte[] buffer = new byte[1024]; // 播放進度 int playIndex = 0; // 是否緩沖完成 boolean isLoaded = false; // 緩沖 + 播放 while (null != mAudioTrack && AudioTrack.PLAYSTATE_STOPPED != mAudioTrack.getPlayState()) { // 字符長度 int len; if (-1 != (len = inputStream.read(buffer))) { byteArrayOutputStream.write(buffer, 0, len); data = byteArrayOutputStream.toByteArray(); Log.i(TAG, "run: 已緩沖 : " + data.length); } else { // 緩沖完成 isLoaded = true; } if (AudioTrack.PLAYSTATE_PAUSED == mAudioTrack.getPlayState()) { // TODO 已經暫停 } if (AudioTrack.PLAYSTATE_PLAYING == mAudioTrack.getPlayState()) { Log.i(TAG, "run: 開始從 " + playIndex + " 播放"); playIndex += mAudioTrack.write(data, playIndex, data.length - playIndex); Log.i(TAG, "run: 播放到了 : " + playIndex); if (isLoaded && playIndex == data.length) { Log.i(TAG, "run: 播放完了"); mAudioTrack.stop(); } if (playIndex < 0) { Log.i(TAG, "run: 播放出錯"); mAudioTrack.stop(); break; } } } Log.i(TAG, "run: play end"); } catch (IOException e) { e.printStackTrace(); } } /** * 設置左右聲道平衡 * * @param max 最大值 * @param balance 當前值 */ public void setBalance(int max, int balance) { float b = (float) balance / (float) max; Log.i(TAG, "setBalance: b = " + b); if (null != mAudioTrack) mAudioTrack.setStereoVolume(1 - b, b); } /** * 設置左右聲道是否可用 * * @param left 左聲道 * @param right 右聲道 */ public void setChannel(boolean left, boolean right) { if (null != mAudioTrack) { mAudioTrack.setStereoVolume(left ? 1 : 0, right ? 1 : 0); mAudioTrack.play(); } } public void pause() { if (null != mAudioTrack) mAudioTrack.pause(); } public void play() { if (null != mAudioTrack) mAudioTrack.play(); } public void stopp() { releaseAudioTrack(); } private void releaseAudioTrack() { if (null != mAudioTrack) { mAudioTrack.stop(); mAudioTrack.release(); mAudioTrack = null; } } }
mPlayThread = new PlayThread(this, "tts1.pcm"); mPlayThread.start();
mPlayThread.pause();
mPlayThread.play();
mPlayThread.stopp(); mPlayThread = null;
// 禁用左聲道(右聲道同理) mPlayThread.setChannel(false, true);
也是一個很”呵呵“的做法,但是依然還沒有找到更好的方法。
構造兩個AudioTrack對象,分別輸出兩個音頻,一個禁用左聲道,一個禁用右聲道,達到預期效果。
mChannelLeftPlayer = new PlayThread(this, "tts1.pcm"); mChannelRightPlayer = new PlayThread(this, "tts2.pcm"); mChannelLeftPlayer.setChannel(true, false); mChannelRightPlayer.setChannel(false, true); mChannelLeftPlayer.start(); mChannelRightPlayer.start();
先上一張圖可以看到,對話框的標題顏色是藍色的,下面還有一根線也是藍色的,在某些情況下,我們想改變程序的主題風格,顏色必須做修改,但又懶得去定制Dialog,
前面分析過 u-boot1.1.6 三個階段的啟動過程,也嘗試自己寫了一個簡單的 bootloader ,是時候嘗試移植一個相對較新一點的 u-boot 了,看過韋東山老
有時候我們添加的一些資源,如圖片和一些沒用的代碼,以及在添加第三方庫的時候我們只需要使用其中的一部分功能和一部分資源,那麼這個時候如果靠我們手工去怕是非常難做的,尤其是
第一步、先爆項目demo照片,代碼不多,不要怕 第二步、應該知道Java反射相關知識如果不知道或者忘記的小伙伴請猛搓這裡,Android插件化開發基礎之Java