安卓手把手教你学习并实现 安卓耳机口音频转红外发射

###安卓实现耳机口音频转红外发射

前一段时间因为找工作,完了之后又有两个项目做,一个 BLE4.0 的项目,一个红外控制的项目,因此也好久没写文章了。BLE4.0 的资料网上一抓一大把,就不多说了。

虽说红外很早就开始火了,从最早的遥控器,到红外测距等等,但是网上关于 Android 红外开发的相关资料几乎没有。那就只能硬着头皮自己上。

手机自带红外有 ConsumerIrManager 类,很好用,略过。而我们今天看的是另一种红外发送方式:音频转红外


1、相关知识介绍:

这里写图片描述
这是网上找的格力空调的开机短码,将这些数字理解成一个 TA 自己规定的协议,9000,4500 为帧头,560,1690 代表 1,560,560 代表 0。先不管帧头,剩下的翻译过来就是{1,0,1,0 , 1,0,1,0,0,1,0,1,0,1,0,1},再翻译为16进制,即为0xAA,0x55,这是一个开机命令。

注:红外遥控器原理和NEC协议这里面有相关的知识,建议先阅读。


采样率 44100:通俗理解就是 在1s内在一条连续的正玄波上面采集 44100 个点。
载波 38KHZ: 即为我们发出的音频信号需要放在 38KHZ 的载波上才能发送出去被红外接收头接收。

音频转红外要做的就是生成 PCM(单/双声道)数据,即为音频数据,按照硬件支持的 NEC 协议,指定采样率,指定载波,使用 Android SDK 中的 audioTrack 类播放这段音频即可

这里写图片描述

注:多媒体基础知识之PCM数据这里面有 PCM 相关的知识,包括采样率、载波等。

注:硬件自己焊接或者淘宝:android 音频红外发射头,附焊接教程


2、音频调试:

音频调试我使用的电脑软件 cooledit,百度一下就有免费的,再加一根3.5mm 的公对公耳机线。

这里写图片描述这里写图片描述

  • step1:使用遥控精灵搜到你的空调型号。

  • step2:公头线一头插耳机口,一头插电脑音频 mic 口,手机音量调到最大,并在电脑上打开 cooledit 软件。

  • step3:点击 cooledit 的录音键,选择采样率 44100,双声道,16 位。打开遥控精灵,打到你的空调按钮面板,连续点击几次开机键。

  • step4:可以看到 cooledit 软件界面上有一些绿色的声音波形。

这里写图片描述

上面这张图片是我抓的遥控精灵发出的电平信号,可以看到 9ms 的高电平和 4.5ms 的低电平,虽然看到这儿是方波,但是再往后其实 TA 也是正玄波。高电平这儿全部是标准的正玄波组成的,宽度为时间宽度 9ms。

那对于我们来说只要仿造出图中那样的波形,9ms高、4.5ms低…,即可和遥控精灵一样控制我们的空调了。

3、仿造波形:

要仿造一段 20KHZ(因为耳机口只能输出这么大),采样率 44100 , 16 位双声道的 PCM 音频数据,网上还是有点资料可寻的。

目前,我没有找到输出方波的方法,再加上经过对遥控精灵输出波形的观察,也是输出的正玄波,所以就放心的输出 Sin 正玄波吧。

必要了解 ①:

 buffSize = AudioTrack.getMinBufferSize(this.sampleRate,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT) * 4;

AudioTrack:音频播放类。
sampleRate:采样率。
AudioFormat.CHANNEL_OUT_STEREO:双声道输出,即为立体声,但同时也增加了文件大小。
AudioFormat.ENCODING_PCM_16BIT:16位,一个采样点占16位。但同时也增加了文件大小。

必要了解 ②:

y(t) = A * sin (ωt + φ)

//ω即为角速度,在一段周期内转过了多少角度。
//T为周期。
//f为频率。
ω = 2π/T = 2πf  

y(t) = A * sin (2πft + φ)

正玄波重要函数,

  • A: 振幅,这里为1;
  • f : 频率,这里为 freqOfTone;(即为19000HZ)
  • t: 时间,这里为 (i/sampleRate);(当i为44100时是不是就是1s了)
  • φ: 相位,这里为0;

表示下来就是这样:

  sample[i] = Math.sin(2 * Math.PI  * i * (freqOfTone /sampleRate));

必要了解 ③:

 audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    this.sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT, bytes1.length,
                    AudioTrack.MODE_STREAM);

STREAM_MUSIC:播放类型,有 Alerm、Notification 等。
AudioTrack.MODE_STREAM:MODE 有 STREAM 和 STATIC 两种。STREAM 类型意味着音频可以被连续播放,只需要一直往缓冲池写即可。STATIC 通常用于播放游戏音等,适合短小音频。
bytes1.length:一次可播放音频文件的缓冲池大小。

核心代码片段:

       for (final double dVal : sample) {
          final short val = (short) ((dVal * 32767));
          final short val_minus = (short) -val;
          //左声道
          generatedSnd[idx] = (byte) (val & 0x00ff);
          generatedSnd[idx+1] = (byte) ((val & 0xff00) >>> 8);
          //16位双声道  右声道
          generatedSnd[idx+2] = (byte) (val_minus & 0x00ff);
          generatedSnd[idx+3] = (byte) ((val_minus & 0xff00) >>> 8);
          idx=idx+4;
        }

代码解释:

上面第2行和第3行是将振幅缩放到最大振幅(32767是16位整数的最大值)。

上面第5、6行和第8、9行是填充PCM数据,上面有文章讲了PCM数据格式,在16位wav PCM中,低字节到高字节:
|样本大小| 数据格式| 最小值| 最大值|
|: -------------|:-------------|: -----|: -----|
|8位PCM | int |-128|127|
| 16位PCM | int | -32768 |32767|

填充完毕后,我们就有了完整的正玄波数据。(即高电平正玄波)

        List<Byte> listByte = new ArrayList<>();
        for (int j = 0; j < patterns.length; j++) {
            int d=patterns[j];
            final int points = (int) ((((double) d / 1000000.0) * sampleRate)*4);
              if (j % 2 == 0) {
                for (int i = 0; i < points; i++) {
                    listByte.add(generatedSnd[i]);
                }
              } else {
                 for (int i = 0; i < points; i++) {
                     listByte.add((byte) 0);
                 }
              }
        }

代码解释:
patterns 即为我们要发送的电平数组,9000 , 4500… 那个。

看第4行,9000是 μs,9000/1000000,是将 μs 转化为秒,再乘sampleRate 即为在9000μs 这段时间内占有多少个采样点。

因为9000为高电平,4500为低电平,再接下来又为高电平,然后又是低电平…所以偶数位为高电平 ,所以偶数位上这 points 个点都为高电平,到奇数位了这 points 个点都为低电平,低电平使用0表示即可。然后将所有的点拼装到一起,组成完成的PCM数据,使用 AudioTrack 播放即可。

try {
            audioTrack.play();
        } catch (IllegalStateException e) {
            LogUtil.e( e.getMessage());
        }
           audioTrack.write(listByte, 0, listByte.length);

格力空调的控制码网上一搜一大堆,在这里我不会开放源代码,核心代码已经给出了,自己好好理解理解,分析分析,就可以自己写出来了。

这个也是自己花了好长时间才搞定的,所以请尊重他人劳动成果,不做伸手党。当然有不明白的可以在下面留言,欢迎交流,共同学习。


my QQ : 1003077897
my csdn:http://blog.csdn.net/u012534831
my gay:https://github.com/qht1003077897

欢迎交流。

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
学习IEC 104协议和编程实现九号遥控功能是一项复杂的任务。本文将以300字的篇幅简要概述该过程。 首先,IEC 104协议是电力自动化系统中常用的通信协议之一,用于远程监控和控制通信。要学习IEC 104协议,首先需要了解其基本原理和通信过程。可以通过阅读相关技术文档、书籍和在线程来深入了解IEC 104协议的细节。 接下来,学习IEC 104协议的编程实现需要有一定的编程基础。主要编程语言可以选择C、C++或者其他常用的编程语言。编程实现九号遥控功能需要掌握IEC 104协议的编码和解码过程,了解相应的数据结构和流程控制。 在编程实现九号遥控功能时,首先需要建立与远程终端设备的连接。可以利用TCP/IP协议进行通信,建立socket连接。在连接建立后,必须正确配置IEC 104协议的站地址、传输参数等信息。 然后,需要编写代码实现IEC 104协议的编码和解码过程。首先,将要发送的遥控命令封装成IEC 104规定的格式,即APCI(Application Protocol Control Information)+ASDU(Application Service Data Unit)+ASDU信息组。然后,根据协议规定的解码方式,对接收到的遥控命令进行解码。 最后,根据九号遥控功能的具体需求,编写代码处理相应的逻辑。例如,判断遥控命令的类型,执行相应的操作,并及时响应给远程终端设备。 总结而言,学习IEC 104协议和编程实现九号遥控功能是一项需要专业知识和编程技能的任务。需要深入学习和实践才能掌握。希望以上简要概述可以为您提供一些指导。如需深入了解,请参考相关专业文献和指导资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q2nAmor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值