【Android App】实现在线语音合成功能(使用云知声平台和WebSocket 超详细 附源码)

简介: 【Android App】实现在线语音合成功能(使用云知声平台和WebSocket 超详细 附源码)

需要源码和Jar包请点赞关注收藏后评论区留下QQ~~~

一、在线语音合成

虽然国产智能机大多集成了中文语音引擎,但是系统自带的语音工具无法满足商用要求,功能单一,所以势必引入第三方的语音引擎,依靠第三方提供的开发包统一支撑语音的交互操作

此处选用云知声引擎,对新生免费并且语音处理采用公开的WebSocket接口,无须引入额外的语音SDK,进入云知声网址后,在右上角找到AI开放平台,然后注册进入控制台创建应用即可

云知声官网

创建好后如下 要记住key和secret  后面要用v

云知声采用WebSocket接口交互,故而不管是语音合成还是语音识别,都需要定义WebSocket客户端的处理任务,云知声使用JSON字符串封装报文合成后的音频数据通过字节数组传回,具体合成过程如下

1:定义WebSocket客户端的语音合成任务

实现以下几个功能

1:在请求报文中填写原始文本 音频格式和采样率等合成参数 再把JSON字符串传给WebSocket服务器

2:服务器分批返回字节数组形式的音频流 客户端需要将这些数据依次追加到存储卡中

3:在合成过程中,服务器还会数次返回JSON格式的应答报文 可能不止一个,只有报文中的end字段为true时才表示合成结束

2:把语音任务关联到WebSocket服务器

此时要拼接完整的URL地址,包含之前在云知声平台的appkey和appsecret,填在SoundUtil这个类中

3:创建并启动语音合成任务

效果如下

合成结束后效果如下 点击右上角的播放可以收听由文字转换的语音

部分代码如下

需要源码请点赞关注收藏后评论区留下QQ~~~

Java类

package com.example.voice;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.voice.constant.SoundConstant;
import com.example.voice.task.TtsClientEndpoint;
import com.example.voice.util.DateUtil;
import com.example.voice.util.SoundUtil;
public class VoiceComposeActivity extends AppCompatActivity {
    private final static String TAG = "VoiceComposeActivity";
    private TextView tv_option; // 声明一个文本视图对象
    private EditText et_compose_text; // 声明一个编辑框对象
    private TextView tv_result; // 声明一个文本视图对象
    private String mComposeFilePath; // 合成语音的文件路径
    private MediaPlayer mMediaPlayer = new MediaPlayer(); // 媒体播放器
    private boolean isPlaying = false; // 是否正在播音
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_voice_compose);
        findViewById(R.id.iv_back).setOnClickListener(v -> finish());
        TextView tv_title = findViewById(R.id.tv_title);
        tv_title.setText("在线语音合成");
        tv_option = findViewById(R.id.tv_option);
        tv_option.setText("开始播放语音");
        tv_option.setVisibility(View.GONE);
        et_compose_text = findViewById(R.id.et_compose_text);
        tv_result = findViewById(R.id.tv_result);
        findViewById(R.id.btn_compose_voice).setOnClickListener(v -> {
            String text = et_compose_text.getText().toString();
            if (TextUtils.isEmpty(text)) {
                Toast.makeText(this, "请先输入待朗读的一段话", Toast.LENGTH_SHORT).show();
                return;
            }
            new Thread(() -> onlineCompose(text)).start(); // 启动在线合成语音的线程
        });
        tv_option.setOnClickListener(v -> {
            if (!isPlaying) { // 未在播音
                startPlay(); // 开始播音
            } else { // 正在播音
                stopPlay(); // 停止播音
            }
        });
    }
    // 在线合成语音
    private void onlineCompose(String text) {
        mComposeFilePath = String.format("%s/%s.mp3",
                getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
                DateUtil.getNowDateTime());
        // 创建语音合成任务,并指定语音监听器
        TtsClientEndpoint task = new TtsClientEndpoint(this, mComposeFilePath, text, arg -> {
            if (Boolean.TRUE.equals(arg[0])) {
                Toast.makeText(this, "语音合成结束", Toast.LENGTH_SHORT).show();
                tv_result.setText("音频文件位于"+arg[2]);
                tv_option.setVisibility(View.VISIBLE);
            }
        });
        SoundUtil.startSoundTask(SoundConstant.URL_TTS, task); // 启动语音合成任务
    }
    // 开始播音
    private void startPlay() {
        isPlaying = !isPlaying;
        tv_option.setText("停止播放语音");
        mMediaPlayer.reset(); // 重置媒体播放器
        // 设置媒体播放器的完成监听器
        mMediaPlayer.setOnCompletionListener(mp -> stopPlay());
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置音频流的类型为音乐
        try {
            mMediaPlayer.setDataSource(mComposeFilePath); // 设置媒体数据的文件路径
            mMediaPlayer.prepare(); // 媒体播放器准备就绪
            mMediaPlayer.start(); // 媒体播放器开始播放
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 停止播音
    private void stopPlay() {
        tv_option.setText("开始播放语音");
        if (mMediaPlayer.isPlaying() || isPlaying) { // 如果正在播放
            isPlaying = !isPlaying;
            mMediaPlayer.stop(); // 停止播放
            Toast.makeText(this, "语音播放结束", Toast.LENGTH_LONG).show();
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        stopPlay(); // 停止播音
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMediaPlayer.release(); // 释放媒体播放器
    }
}

SoundUtil类

package com.example.voice.util;
import android.util.Log;
import com.example.voice.constant.SoundConstant;
import java.net.URI;
import java.security.MessageDigest;
import javax.websocket.ContainerProvider;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
public class SoundUtil {
    private final static String TAG = "SoundUtil";
    // 启动语音处理任务(语音识别或者语音合成)
    public static void startSoundTask(String url, Object task) {
        long time = System.currentTimeMillis();
        StringBuilder paramBuilder = new StringBuilder();
        // 填写该应用在开放平台上申请的密钥和密码
        paramBuilder.append(SoundConstant.APP_KEY).append(time).
                append(SoundConstant.APP_SECRET);
        String sign = getSHA256Digest(paramBuilder.toString());
        StringBuilder param = new StringBuilder();
        param.append("appkey=azkk2kwv5f22m5z4iebchxsetodz3y677chtzniz").append(SoundConstant.APP_KEY).append("&")
                .append("time=").append(time).append("&")
                .append("sign=").append(sign).append("&").append("appsecret=6d6f4426e005e6b7f9a7fee2a9fdda44");
        String fullUrl = url + param.toString();
        Log.d(TAG, "fullUrl="+fullUrl);
        // 获取WebSocket容器
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        try {
            URI uri = new URI(fullUrl); // 创建一个URI对象
            // 连接WebSocket服务器,并关联语音处理任务获得连接会话
            Session session = container.connectToServer(task, uri);
            // 设置文本消息的最大缓存大小
            session.setMaxTextMessageBufferSize(1024 * 1024 * 10);
            // 设置二进制消息的最大缓存大小
            session.setMaxBinaryMessageBufferSize(1024 * 1024 * 10);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获得SHA摘要
    private static String getSHA256Digest(String data) {
        String digest = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] bytes = md.digest(data.getBytes("UTF-8"));
            digest = byte2hex(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return digest;
    }
    // 二进制转十六进制字符串
    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }
}

创作不易 觉得有帮助请 点赞关注收藏~~~

相关文章
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
110 1
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
140 0
安卓项目:app注册/登录界面设计
|
2月前
|
IDE Android开发 iOS开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
【9月更文挑战第27天】在移动应用开发的世界中,Android和iOS是两个主要的操作系统平台。每个系统都有其独特的开发环境、工具和用户群体。本文将深入探讨这两个平台的关键差异点,并分析这些差异如何影响应用的性能、用户体验和最终的市场表现。通过对比分析,我们将揭示选择正确的开发平台对于确保项目成功的重要作用。
|
18天前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码服务器环境配置及app功能
一对一直播源码阿里云服务器环境配置及要求
|
17天前
|
小程序 数据挖掘 UED
开发1个上门家政小程序APP系统,都有哪些功能?
在快节奏的现代生活中,家政服务已成为许多家庭的必需品。针对传统家政服务存在的问题,如服务质量不稳定、价格不透明等,我们历时两年开发了一套全新的上门家政系统。该系统通过完善信用体系、提供奖励机制、优化复购体验、多渠道推广和多样化盈利模式,解决了私单、复购、推广和盈利四大痛点,全面提升了服务质量和用户体验,旨在成为家政行业的领导者。
|
30天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
82 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
14天前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
2月前
|
移动开发 Android开发 数据安全/隐私保护
移动应用与系统的技术演进:从开发到操作系统的全景解析随着智能手机和平板电脑的普及,移动应用(App)已成为人们日常生活中不可或缺的一部分。无论是社交、娱乐、购物还是办公,移动应用都扮演着重要的角色。而支撑这些应用运行的,正是功能强大且复杂的移动操作系统。本文将深入探讨移动应用的开发过程及其背后的操作系统机制,揭示这一领域的技术演进。
本文旨在提供关于移动应用与系统技术的全面概述,涵盖移动应用的开发生命周期、主要移动操作系统的特点以及它们之间的竞争关系。我们将探讨如何高效地开发移动应用,并分析iOS和Android两大主流操作系统的技术优势与局限。同时,本文还将讨论跨平台解决方案的兴起及其对移动开发领域的影响。通过这篇技术性文章,读者将获得对移动应用开发及操作系统深层理解的钥匙。
|
2月前
|
监控 Android开发 iOS开发
深入探索安卓与iOS的系统架构差异:理解两大移动平台的技术根基在移动技术日新月异的今天,安卓和iOS作为市场上最为流行的两个操作系统,各自拥有独特的技术特性和庞大的用户基础。本文将深入探讨这两个平台的系统架构差异,揭示它们如何支撑起各自的生态系统,并影响着全球数亿用户的使用体验。
本文通过对比分析安卓和iOS的系统架构,揭示了这两个平台在设计理念、安全性、用户体验和技术生态上的根本区别。不同于常规的技术综述,本文以深入浅出的方式,带领读者理解这些差异是如何影响应用开发、用户选择和市场趋势的。通过梳理历史脉络和未来展望,本文旨在为开发者、用户以及行业分析师提供有价值的见解,帮助大家更好地把握移动技术发展的脉络。
92 6
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
161 2