效果图

源码

我这里主要是用到了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_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();

android 左右声道,Android左右声道的控制相关推荐

  1. RK3328 Android 7.1 录音左右声道分离的情况下,有时候会出现,右声道的声音和左声道一样的问题

    RK3328 Android 7.1 录音左右声道分离的情况下,有时候会出现,右声道的声音和左声道一样的问题 问题现象: 产品有语音识别功能,需要回音消除,所以立体声录音需要左右声道分离,左声道为主M ...

  2. android声音播放函数双声道合并,Android音视频系列(七):PCM音频单声道与双声道的相互转换...

    前言 上一篇我们已经学习了PCM音频的保存格式,这一篇我们通过掌握的知识,完成PCM音频的单声道和双声道的互相转换. 正文 首先我们把上一篇的最核心部分贴出来: PCM音频保存格式 我们首先完成单声道 ...

  3. android scrollview居中,使用 HorizontalScrollView 实现滚动控制

    功能要求是屏幕上固定显示 3 个 Layout 项(图片+文字),支持点击切换到选择的 Layout 项,并支持滑动切换到最近的 Layout 项. 最后的效果如下: 下面逐步上代码: 布局文件 ac ...

  4. android 键盘使用教程,用鼠标键盘控制你的Android手机完整图文教程

    网上大都是91助手for android来连接手机和电脑,我自己比较偏向于豌豆荚,都可以的,下面给出我的步骤及过程中遇到的几个小问题,供大家参考! 一.鼠标键盘控制手机教程 1.在PC上,安装豌豆荚, ...

  5. android之DPAD上下左右四个键控制

    我们代码的目的很简单,那就是监听上下左右中这几个键的事件触发.直接上代码: dpad.xml <?xml version="1.0" encoding="utf-8 ...

  6. Android:剖析源码,随心所欲控制Toast显示

                  本文转载于:http://www.cnblogs.com/net168/p/4058193.html                前言 Toast相信大家都不会陌生吧,如 ...

  7. android 智能设备管理,基于Android平台上BLE的智能家居控制系统设计与实现

    摘 要:基于智能家居无线控制的市场需求,以集成了CSR1010低功耗蓝牙芯片的智能插座为例,在Android平台上设计了一套基于蓝牙4.0通信协议的智能家居控制系统,实现了对此智能插座的无线通断电控制 ...

  8. Android与Unity交互及手机震动控制

    背景 Unity开发过程中,自身提供的API或方案无法满足需求时,就需要Android工程交互通信.网络上交互方案很多,通常为jar包和aar包,经过对比本人采用aar包来实现,过程相对简单. Uni ...

  9. 基于android的网络音乐播放器-通知栏控制(RemoteViews)(十)

    到这里音乐播放器该有的功能基本都有了,最后再添加一个通知栏控制功能--当我们后台运行的时候可以在通知栏看到我们的音乐播放状态并且可以控制音乐的暂停/播放/上一首/下一首:点击通知图标即可返回音乐播放器 ...

最新文章

  1. python调用第三方软件发信代码_【IT专家】python调用第三方邮件接口
  2. 为什么手机联系人里有permission_为什么有人在咖啡馆里不看手机不看电脑没有同伴,独自喝咖啡?...
  3. Navicat for MySQL数据库管理工具
  4. vue中的uri_浅谈vue-resource和vue-axios的区别
  5. 哪里是我们最好的避风港?
  6. Oracle delete input与delete all input
  7. nginx linux 系统服务,把ngnix注册为linux服务 将Nginx设置为linux下的服务
  8. android label关闭按钮,iOS弹出关闭按钮标签:“OK”还是“Okay”?
  9. Java并发编程之volatile关键字解析
  10. python的代码保存到文档中 打不开怎么办_Python 制作网页打不开 直接跳到打开或者保存文件...
  11. 《程序员的数学》读后感
  12. 威纶通触摸屏MT6071IP如何使用宏指令编程设置密码登陆界面进行用户操作权限管理
  13. 留给19371213看的
  14. 特殊字符在英语中的读法
  15. python68个内置函数_Python中68个内置函数的总结
  16. 时之歌 服务器维护,时之歌抽卡卡住了怎么办 时之歌手游招募吞卡解决方法
  17. 大疆Onboard SDK 3.2玫瑰线例程浅析
  18. JVM成神之路(二)-- JDK,JER与JVM的关系
  19. 怎么给word文档注音_如何为整篇word文档加拼音标注
  20. 计算机毕业设计Java中医保健网站(源码+系统+mysql数据库+Lw文档)

热门文章

  1. localhost(操作系统有默认值与其对应,所以不必一定在hosts文件里明写)
  2. 23、Java——常见异常的原因和解决办法
  3. bandzip与WinRAR
  4. c# 超时时间已到.在操作完成之前超时时间已过或服务器未响应,c#执行插入sql 时,报错:异常信息:超时时间已到。在操作完成之前超时时间已过或服务器未响应...
  5. 帝国cms常用插件推荐:支付接口、登陆插件
  6. DIY可视化导出uni-app源码生成器
  7. 开票系统导出的OFD文档如何转换PDF格式?
  8. 什么是404页面,404有什么做用,网站做404有什么好处?
  9. 新大陆物联网开发-物联网竞赛-物联网开发中必须要知道的协议-单片机嵌入式开发
  10. 微小区V2 v2.3.2