最近要做一个项目,利用手机的耳机口输出红外信号,从而把手机变成红外遥控器,信号处理的知识基本都还给老师了,刚开始真的挺头疼。找了不少资料研究了一下,总算有点心得,在这里做个备忘。

一、音频信号输出原理

音频耳机口输出信号的原理已经有大牛的文章,参考http://blog.csdn.net/xl19862005/article/details/8522869

再补充一点个人的理解,Android音频输出采样率一般为44.1kHz,AudioTrack源码中限制最大采样率为48kHz,也就是说耳机音频口输出的音频频率应该在20kHz左右,基本就是Android音频输出频率极限了。红外信号载波一般是38kHz,所以单纯的想通过音频信号是达不到要求的,需要借助外部硬件,找了一下,发现某宝上有的卖的,配套的app也有,下来试了一下,效果不错。不过既然是自己开发,需要搞清原理,反编译看了一下,核心代码都是native code,还是走正路,自己研究怎么实现。

网上找了一些相关资料,Linux平台下有相关的开源项目LIRC(Linux Infrared Remote Control):http://www.lirc.org/,支持各种类型的硬件,可以通过配置文件来支持各种类型的遥控设备,电视、dvd等等,是一个相对成熟的项目,目前google play中有很多红外遥控的应用都是基于此项目开发的。不过我这边只关注耳机口输出红外,LIRC中关于audio耳机口输出原理图(http://www.lirc.org/html/audio.html):

                    

利用耳机的左右声道,输出19kHz音频,通过左边的电路图,输出38kHz。

二、实现

原理搞清楚了,接下来实现,通过AudioTrack输出19kHz的正弦波形即可。这里没有将LIRC整体移植到android上,一来工程量太大,二来我只是用耳机这一种,其他的用不上,主要借鉴其中的音频输出原理。LIRC移植到Android可以参考开源项目irdroid:http://www.irdroid.com/

核心代码, 输出19kHz正弦,参考国外大牛:http://stackoverflow.com/questions/2413426/playing-an-arbitrary-tone-with-android

 public SignalProcessor(final int frequency) {
int buffSize = AudioTrack.getMinBufferSize(this.sampleRate,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT) * 4; genSignal = new byte[buffSize];
genSpace = new byte[buffSize]; for (int j = 0; j < buffSize;) {
double dVal = Math.sin(2 * Math.PI * ((double)j)/4.0
/ (((double)sampleRate) / ((double)frequency)));
final short val = (short) ((dVal * 32767));
final short val_minus = (short) -val;
// in 16 bit wav PCM, first byte is the low order byte
genSpace[j] = 0;
genSignal[j++] = (byte) (val & 0x00ff);
genSpace[j] = 0;
genSignal[j++] = (byte) ((val & 0xff00) >>> 8);
genSpace[j] = 0;
genSignal[j++] = (byte) (val_minus & 0x00ff);
genSpace[j] = 0;
genSignal[j++] = (byte) ((val_minus & 0xff00) >>> 8);
} audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
this.sampleRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT, buffSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
} public void play(final ArrayList<Integer> SignalSpaceList) {
boolean signal = true;
int count=0;
for (Integer d : SignalSpaceList) {
final int stop = (int) (((double) (d * sampleRate)) / 1000000.0) *4 ;
if (signal)
for (int i = 0; i < stop;)
{
if (stop - i < buffSize)
count= audioTrack.write(genSignal, 0, stop - i);
else
count = audioTrack.write(genSignal, 0, buffSize);
if(count>0)
i+=count;
}
else
for (int i = 0; i < stop;)
{
if (stop - i < buffSize)
count= audioTrack.write(genSpace, 0, stop - i);
else
count = audioTrack.write(genSpace, 0, buffSize);
if(count>0)
i+=count;
} signal = !signal;
}
}

解释一下:

 public void play(final ArrayList<Integer> SignalSpaceList)

传入信号与空闲时间的一个list,比如NEC编码中如图:

HEAD信号时间9ms,空闲时间4.5ms,list中传入9000,4500

测试耳机口单声道输出波形:

连接外设之后,输出方波:

Android使用AudioTrack发送红外信号的更多相关文章

  1. Android HTTP实例 发送请求和接收响应

    Android HTTP实例 发送请求和接收响应 Android Http连接 实例:发送请求和接收响应 添加权限 首先要在manifest中加上访问网络的权限: <manifest ... & ...

  2. Android - 向服务器发送数据(POST) - HTTPClient.

    该篇文章主要说明使用Apache提供的HTTPClient,通过post方式,向服务器发送数据.由于有些东西在 Android - 向服务器发送数据(GET)中提到过,就不再重复. 一,Android ...

  3. Android应用程序发送广播(sendBroadcast)的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6744448 前面我们分析了Android应用程 ...

  4. android下获取无线wif信号、ssid、MAC等操作类

    一个android下获取无线wif信号.ssid.MAC等操作的类. WifiAdmin.java package com.afu; import java.util.List; import and ...

  5. Android广播的发送与接收

    Android广播的发送与接收 效果图 广播发送 广播分为有序广播和无序广播 有序广播与无序广播的区别 无序广播:只要是广播接收者指定了接收的事件类型,就可以接收到发送出来的广播消息.不能修改消息. ...

  6. 向 Nginx 主进程发送 USR1 信号

    [1]Nginx重新打开日志文件 向 Nginx 主进程发送 USR1 信号.USR1 信号是重新打开日志文件: 方式一: kill -USR1 $(cat /usr/local/lib/ubcsrv ...

  7. 如何实现PyQt5与QML响应彼此发送的信号?

    对于PyQt5+QML+Python3混合编程,如何实现PyQt5与QML响应彼此发送的信号,这是一个棘手的问题. 大抵有如下五种方式: (要运行下面五个例子,千万不能在eric6中运行,会报错.错误 ...

  8. Android向unity发送消息

    有些时候需要Android向unity发送消息,有两种方法实现,一.通过unity再带的消息机制,二.通过注册回调的方式. 一.通过UnityPlayer.UnitySendMessage():方法 ...

  9. 向nginx发送reopen信号以重新打开日志文件

    先移动日志文件 mv /usr/local/openresty/nginx/logs/access.log /usr/local/openresty/nginx/logs/access.log.201 ...

随机推荐

  1. android开发中的问题集锦(慢慢搬运...)

    1, android 设置ExpandableListView 系统默认箭头到右边 if(android.os.Build.VERSION.SDK_INT < android.os.Build. ...

  2. JSP内置对象---用户登录页面(get和post)

    Login.jsp 页面: <%@ page language="java" import="java.util.*" contentType=" ...

  3. .Net Log4Net配置多文件日志记录

    其他配置详情在网上都可以找到,但是很多看着都晕,本人就记录一下如何使用: 1.按不同级别(官方说明)可记录的日志级别有: Info.Warn.Error.Debug 2.可以按着四个配置四个输出日志路 ...

  4. 10款html5开发工具,实用+好用

    利用HTML5工具不仅可以帮助设计师和开发者创建更具吸引力的网站,还能增加网站的可用性和可访问性.本文收集了10款HTML5开发工具让你在网页中搭建特效.动画.视频.音频等诸多功能,为你节省更多开发时 ...

  5. Git忽略规则及.gitignore规则不生效的解决办法

    在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法(如无,则需自己手工建立此文件).这个文件每一行保存了一个匹配的规则例如: # 此为注 ...

  6. 一个很奇怪的问题,程序没有改动加密参数应该也没有变化.但是两次的加密结果却不一致.md5加密问题

    从图上我们看出20160803的加密结果是AAEBA9C578EA522215EAE76AFCAF250.时间是9.4分 现在我们再看这个同样的加密地址与时间结果却是另一种 31672B16..... ...

  7. Android深度探索--HAL与驱动开发----第九章读书笔记

    Google为Android加入HAL主要有如下的目的. 统一硬件的调用接口.由于HAL 有标准的调用接口,所以可以利用HAL屏蔽Linux 驱动复杂.不统一的接口. 解决了GPL版权问题.由于Lin ...

  8. meteor报错之:MongoDB had an unspecified uncaught exception.

    今天测试的时候meteor报了个错 如下: MongoDB had an unspecified uncaught exception. This can be caused by MongoDB b ...

  9. python,django做中间件屏蔽非法访问

    我使用django1.6. django框架没有urlfilter这样的原生中间件,但是灵活的django设计者为我们留下了更自由的渠道. 在没有使用django以前,我没有接触过如此潇洒的编程方式, ...

  10. NSURLSession使用说明及后台工作流程分析

    原文摘自http://www.cocoachina.com/industry/20131106/7304.html NSURLSession是iOS7中新的网络接口,它与咱们熟悉的NSURLConne ...