java如何调用本地扬声器
各位看官可以关注博主个人博客,了解更多信息。
作者:Surpasser
链接地址:https://surpass.org.cn
前言
博主的毕设系统在做一个餐厅的点餐管理系统,在记性移动端页面开发的时候突发奇想做一个呼叫服务员,扬声器发声的一个功能类似于:“工作人员请注意,桌号8001顾客正在寻求帮助!”。
实现方式
接下来就对这个小功能进行分析和实现。先写一个Demo。
首先,我们需要一个dll作为辅助。这里解释一下dll的含义(DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用百程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个度完整的可执行文件,它们被分割成一些相知对独立的动态链接库,即DLL文件,放置于道系统中。当我们执行某一个程序时,相应的版DLL文件就会被调用。一个应用程序可使用权多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件)。
需要把
jacob-1.17-M2-x64.dll复制到C:\Windows\System32\目录下。我们也能看到目录下有很多的.dll文件。这里的文件大家自己百度下,很好找的。
使用maven项目导入坐标。
<!-- https://mvnrepository.com/artifact/net.sf.jacob-project/jacob -->
<dependency>
<groupId>net.sf.jacob-project</groupId>
<artifactId>jacob</artifactId>
<version>1.14.3</version>
</dependency>
测试类代码。
/**
* 文字转语音测试 jdk bin文件中需要导入jacob-1.17-M2-x64.dll
* 注意导包哈
* @date: 2020年2月25日 上午10:05:21
*/
public class Jacobtest { public static void main(String[] args) {
textToSpeech("工作人员请注意,桌号8001顾客正在寻求帮助!!");
} /**
* 语音转文字并播放
*
* @param text
*/
public static void textToSpeech(String text) {
ActiveXComponent ax = null;
try {
ax = new ActiveXComponent("Sapi.SpVoice"); // 运行时输出语音内容
Dispatch spVoice = ax.getObject();
// 音量 0-100
ax.setProperty("Volume", new Variant(100));
// 语音朗读速度 -10 到 +10
ax.setProperty("Rate", new Variant(0));
// 执行朗读
Dispatch.call(spVoice, "Speak", new Variant(text)); /* // 下面是构建文件流把生成语音文件 ax = new ActiveXComponent("Sapi.SpFileStream");
Dispatch spFileStream = ax.getObject(); ax = new ActiveXComponent("Sapi.SpAudioFormat");
Dispatch spAudioFormat = ax.getObject(); // 设置音频流格式
Dispatch.put(spAudioFormat, "Type", new Variant(22));
// 设置文件输出流格式
Dispatch.putRef(spFileStream, "Format", spAudioFormat);
// 调用输出 文件流打开方法,创建一个.wav文件
Dispatch.call(spFileStream, "Open", new Variant("./text.wav"), new Variant(3), new Variant(true));
// 设置声音对象的音频输出流为输出文件对象
Dispatch.putRef(spVoice, "AudioOutputStream", spFileStream);
// 设置音量 0到100
Dispatch.put(spVoice, "Volume", new Variant(100));
// 设置朗读速度
Dispatch.put(spVoice, "Rate", new Variant(-2));
// 开始朗读
Dispatch.call(spVoice, "Speak", new Variant(text)); // 关闭输出文件
Dispatch.call(spFileStream, "Close");
Dispatch.putRef(spVoice, "AudioOutputStream", null); spAudioFormat.safeRelease();
spFileStream.safeRelease();*/
spVoice.safeRelease();
ax.safeRelease(); } catch (Exception e) {
e.printStackTrace();
}
}
}
从测试类可以看出,这个方法既可以发声还能输出后缀为
.wav的文件,这是一个标准的多媒体文件。上述代码注释很清晰,就不解释了,自己看哈。测试成功,现在集成到自己的项目中。
另述
这里说到了调用扬声器发声,不放还可以想一下如何调用麦克风收音。
public class EngineeCore {
    String filePath = "E:\\voice\\voice_cache.wav";
    AudioFormat audioFormat;
    TargetDataLine targetDataLine;
    boolean flag = true;
	private void stopRecognize() {
        flag = false;
        targetDataLine.stop();
        targetDataLine.close();
    }
    private AudioFormat getAudioFormat() {
        float sampleRate = 16000;
        // 8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;
        // 8,16
        int channels = 1;
        // 1,2
        boolean signed = true;
        // true,false
        boolean bigEndian = false;
        // true,false
        return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
    }// end getAudioFormat
    private void startRecognize() {
        try {
            // 获得指定的音频格式
            audioFormat = getAudioFormat();
            DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
            targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
            // Create a thread to capture the microphone
            // data into an audio file and start the
            // thread running. It will run until the
            // Stop button is clicked. This method
            // will return after starting the thread.
            flag = true;
            new CaptureThread().start();
        } catch (Exception e) {
            e.printStackTrace();
        } // end catch
    }// end captureAudio method
    class CaptureThread extends Thread {
        public void run() {
            AudioFileFormat.Type fileType = null;
            File audioFile = new File(filePath);
            fileType = AudioFileFormat.Type.WAVE;
            //声音录入的权值
            int weight = 2;
            //判断是否停止的计数
            int downSum = 0;
            ByteArrayInputStream bais = null;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            AudioInputStream ais = null;
            try {
                targetDataLine.open(audioFormat);
                targetDataLine.start();
                byte[] fragment = new byte[1024];
                ais = new AudioInputStream(targetDataLine);
                while (flag) {
                    targetDataLine.read(fragment, 0, fragment.length);
                    //当数组末位大于weight时开始存储字节(有声音传入),一旦开始不再需要判断末位
                    if (Math.abs(fragment[fragment.length-1]) > weight || baos.size() > 0) {
                        baos.write(fragment);
                        System.out.println("守卫:"+fragment[0]+",末尾:"+fragment[fragment.length-1]+",lenght"+fragment.length);
                        //判断语音是否停止
                        if(Math.abs(fragment[fragment.length-1])<=weight){
                            downSum++;
                        }else{
                            System.out.println("重置奇数");
                            downSum=0;
                        }
               //计数超过20说明此段时间没有声音传入(值也可更改)
                        if(downSum>20){
                            System.out.println("停止录入");
                            break;
                        }
                    }
                }
                //取得录音输入流
                audioFormat = getAudioFormat();
                byte audioData[] = baos.toByteArray();
                bais = new ByteArrayInputStream(audioData);
                ais = new AudioInputStream(bais, audioFormat, audioData.length / audioFormat.getFrameSize());
                //定义最终保存的文件名
                System.out.println("开始生成语音文件");
                AudioSystem.write(ais, AudioFileFormat.Type.WAVE, audioFile);
                downSum = 0;
                stopRecognize();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭流
                try {
                    ais.close();
                    bais.close();
                    baos.reset();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }// end run
    }// end inner class CaptureThread
这个测试没测试,偷个懒找的“哈哈”。
还有一点是Java操作语音文件.wav先不要研究了 :laugh and cry:,这里涉及到了语音识别,但是有百度那么些api,有兴趣的试试吧!
好了,在这里就结束了
更新
博主把自己的毕设项目打包放到自己的服务器上,这个扬声器出现了新的问题。
本来所有的基础都是在本地运行的,通过调用本地dll文件实现扬声器发声,现在部署到centOS上将会失去这个dll的支持,目前所存在的问题是如何不使用dll文件实现这个功能,中间借助了
.wav后缀的音视频文件。
- 如何在Linux上生成
 .wav的文件。- 如何获取这个文件并输出。(解释一下,用餐顾客点击手机网页的菜单,然后再餐厅的主机来播放这个声音)
 - 如何在输出主机不进行任何操作就能播放这个声音或者能够恢复之前的工作状态。
 
现在的临时解决办法是本地跑一个呼叫服务的接口,当需要这个功能的时候远程服务器调用本地跑的接口,进而实现餐厅主机发声。
这个和上面描述的并无差别,不一样的是存在了两台主机的调用(当然两台主机都应该链接网络,能够互相通信)
先写到这了,当有解决办法的时候再更新吧!
java如何调用本地扬声器的更多相关文章
- java中调用本地动态链接库(*.DLL)的两种方式详解和not found library、打包成jar,war包dll无法加载等等问题解决办法
		
我们经常会遇到需要java调用c++的案例,这里就java调用DLL本地动态链接库两种方式,和加载过程中遇到的问题进行详细介绍 1.通过System.loadLibrary("dll名称,不 ...
 - Windows下Java如何调用本地获取mac地址
		
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...
 - JAVA方法和本地方法(转载)
		
转载自:http://blog.sina.com.cn/s/blog_5b9b4abe01016zw0.html JAVA中有两种方法:JAVA方法和本地方法 JAVA方法是由JAVA编写的,编译 ...
 - JNI编程(二) —— 让C++和Java相互调用(1)
		
自己在外面偷偷的算了下,又有将近两个月没更新过blog了.趁着今天有兴致,来更新JNI编程的第二篇文章.在第一篇里,大概介绍了JNI的特点.用途和优劣.并且做一个最简单的JNI的例子,不过说实话那个例 ...
 - java方法和本地方法
		
java中的方法有两种,java方法和本地方法. java方法:是由java语言编写,编译成字节码,存储在class文件中的.java方法是与平台无关的. 本地方法:本地方法是由其他语言(如C.C++ ...
 - java jni 调用c语言函数
		
今日在hibernate源代码中遇到了native关键词,甚是陌生,就查了点资料,对native是什么东西有了那么一点了解,并做一小记. native关键字说明其修饰的方法是一个原生态方法,方法对应的 ...
 - java调用本地方法的时候报错 could not find the main class:xx.program will exit
		
如图所示,当在java调用本地方法的时候报错 我的解决办法是把dll文件放到System.out.println(System.getProperty("java.library.path& ...
 - Android使用JNI(从java调用本地函数)
		
当编写一个混合有本地C代码和Java的应用程序时,需要使用Java本地接口(JNI)作为连接桥梁.JNI作为一个软件层和API,允许使用本地代码调用Java对象的方法,同时也允许在Java方法中调用本 ...
 - [转载]java调用本地dos命令
		
在社区看到java调用本地dos命令的代码,特贴出来 String command = "ipconfig"; Runtime run = Runtime.getRuntime() ...
 
随机推荐
- List的主要实现类
			
//ArrayList:List的主要实现类 /* * List中相对于Collection,新增加的方法 * void add(int index, Object ele):在指定的索引位置inde ...
 - 《Selenium自动化测试实战:基于Python》之 Python与Selenium环境的搭建
			
第2章 Python与Selenium环境的搭建 购买链接: 京东:https://item.jd.com/13123910.html 当当:http://product.dangdang.co ...
 - IPFS挖矿靠谱吗?
			
IPFS是一个旨在创建持久且分布式存储和共享文件的网络传输协议,前景广阔且实用意义大,为区块链行业提供了一种新的可能.而IPFS挖矿挖出的FIL,则是在IPFS技术的基础上,对维护IPFS网络的用户的 ...
 - 2017-2018 ACM-ICPC Northern Eurasia(A.Archery Tournament)
			
题目链接:https://vjudge.net/problem/Gym-101630A 题意: n个事件,t=1 代表增加一个圆心为(x,y),半径为 abs(y)的靶子,t=2,代表射击的坐标为(x ...
 - tips 【总结】
			
需求 移入a标签把对应的详情显示出来并且根据位置判断,当前详情是否超出父级可视区范围,如果超出就定位的距离方向应该正好在父级可视区范围内 需求分析: 需要用到: offsetLeft 获取外边框到 ...
 - 12、MyBatis教程之缓存
			
13.缓存 简介 1.什么是缓存 [ Cache ]? 存在内存中的临时数据. 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高 ...
 - 设计vue3的请求实体工厂
			
设计一个vue3的请求实体工厂 目录 设计一个vue3的请求实体工厂 描述 实现 构建一个基础请求方法 创建具体请求的方法 下面是对请求的声明文件 下面是请求的定义 generateRequest对请 ...
 - MySQL数据库与python交互
			
1.安装引入模块 安装mysql模块 pip install PyMySQL; 文件中引入模块 import pymysql 2.认识Connection对象 用于建立与数据库的连接 创建对象:调用c ...
 - EfficientNet & EfficientDet 论文解读
			
概述 总体而言,这两篇论文都在追求一件事,那就是它们名字中都有的 efficient.只是两篇文章的侧重点不一样,EfficientNet 主要时研究如何平衡模型的深度 (depth).宽度 (wid ...
 - 系统编程-信号-信号发送kill、raise、alarm
			
信号发送 kill 和 raise函数 kill函数参数详解: 实验1 raise和kill 的使用 #include <stdio.h> #include <signal.h> ...