Android左右声道的控制

效果图

效果图

源码

源码下载,请先移步Android左右声道的控制

我这里主要是用到了AudioTrack实现的左右声道的控制,手机一般都只有两个声道,即左声道和右声道,我们在输出的时候可以选择单声道,也可以选择双声道(立体声)。

查看了AudioTrack的API,提供了play()pause()stop()write()等一系列的方法。
通过write()方法,可以实现将音频数据发送出去(播放出来)。

AudioTrack对象的构造

有三个构造方法

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_NOTIFICATION
  • sampleRateInHz:采样率

  • channelConfig:声道

    • AudioFormat.CHANNEL_OUT_MONO:输出单声道音频数据
    • AudioFormat.CHANNEL_OUT_STEREO:输出双声道音频数据(立体声)
  • audioFormat:音频数据格式

  • mode:缓冲模式

    • MODE_STATIC:一次性将音频载入以后再播放
    • MODE_STREAM:以流的形式,加载一点就播放一点

把channelConfig的相关参数都看了一遍,没发现有可以指定向某声道发送数据的,只能通过AudioFormat.CHANNEL_OUT_MONOAudioFormat.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();
优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/454554

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。