Android SDK

介绍

iFLYOS 提供了开源的 Android SDK 用于快速接入,封装了 IVS API 的交互实现。厂商既可以直接使用 Android SDK,也可以在它的基础上做二次开发。

Android SDK 介绍

开发环境要求

  • Git
  • Android Studio 3.1.2 或以上
  • 能够正常访问 jCenter、Google Maven 的网络连接
  • 一部 Android 4.4 或以上的开发设备(或以平板电脑代替)

快速上手

下载源码:

git clone https://github.com/iFLYOS-OPEN/SDK-Android

使用 Android Studio 打开同步下来的 SDK-Android 工程。首次打开需要等待 Gradle 联网下载一些依赖库,可能需要较长时间,需要保持网络畅通。

连上开发设备,运行 app 模块。这就是一个最基础的 iFLYOS 设备端实现。

模块说明

SDK-Android 项目中的 app 是带屏设备实现示例,app module 源码中包含了下列几个模块:

  • {package}/impl - 各个设备能力实现,详见设备能力开发
  • {package}/EngineService - 语音服务引擎的主服务,你可以参照该服务中注册引擎的方式实现自己的语音引擎服务

SDK 包含 sdk模块端能力实现模块授权能力实现模块

SDK 的 aar 文件可以在 这里 直接下载。SDK 的主要代码通过我们的 Linux SDK 与 Java 层的绑定来实现,Linux SDK 管理各部分服务和解析工作,Java 层做具体功能的应用层实现。

设备能力开发

SDK 默认提供了部分基础设备能力参考实现。你也可以根据需要自己替换或修改一些实现以符合你具体的硬件要求。下文将介绍一个设备能力模块的实现过程。

示例模块讲解

设备接入约定中包含不同的音频通道,在 SDK 中表现为 AudioChannel 的子类。每一个 AudioChannel 中都包含一个 MediaPlayer 用于播放控制,一个 Speaker 用于音量控制以及一个 Speaker.Type 表示音量类型。

public abstract class AudioChannel extends PlatformInterface {
    private MediaPlayer m_mediaPlayer;
    private Speaker m_speaker;
    private Type m_type;

    public AudioChannel(MediaPlayer mediaPlayer, Speaker speaker, Type type) {
        this.m_mediaPlayer = mediaPlayer;
        this.m_speaker = speaker;
        this.m_type = type;
    }
}

SDK 中的 AudioPlayer, SpeechSynthesizer, AlertsHandler 都是 AudioChannel 的子类实现。

举例

下面介绍一个基础的 MediaPlayer 模块应当如何实现

MediaPlayer 的基础播放控制包含以下内容

public abstract class MediaPlayer extends PlatformInterface {
    public MediaPlayer() {}

    // 加载附件中的流数据
    public boolean prepare(boolean isOpusDong) { return false; }

    // 加载指定的 URL
    public boolean prepare(String url) { return false; }

    // 开始播放
    public boolean play() { return false; }

    // 停止播放
    public boolean stop() { return false; }

    // 暂停播放
    public boolean pause() { return false; }

    // 继续播放
    public boolean resume() { return false; }

    // 获取当前播放位置
    public long getPosition() { return 0L; }

    // 设置当前播放位置
    public boolean setPosition(long position) { return false; }
}

复写相关的方法后,如果方法的返回值为布尔值,则返回 true 表示操作正常进行,否则返回 false。SDK 中在接收到相关的指令后,会对指令中的 payload 解析出具体的数据用于播放控制,因此自定义该模块时只要将具体的播放控制操作实现即可。

由于设备能力约定了播放器有相关的状态变化时,也应当有相关的 Plackback 事件上报,据此,Demo 中的 MediaPlayerHandler 提供了一个基于 ExoPlayer 的实现,并在其中的 PlayerEventListener 中处理了相关的 Playback 事件上报。

录音硬件接入

IVS Android SDK 默认通过 SpeechRecognizerHandler)来实现录音功能。

模块通过建立基于 Android AudioRecord API 的对象来执行录音操作。


private boolean startRecording() {
    ......
    mAudioInput.startRecording();
    ......
    // Read recorded audio samples and pass to engine
    mExecutor.submit(mReader = new AudioReader()); // Submit the audio reader thread
}
private class AudioReader implements Runnable {

    private boolean mRunning = true;
    private byte[] mBuffer = new byte[640];

    void cancel() {
        mRunning = false;
    }

    boolean isRunning() {
        return mRunning;
    }

    @Override
    public void run() {
        int size;

        while (mRunning) {
            size = mAudioInput.read(mBuffer, 0, mBuffer.length);
            if (size >= 320 && mRunning) {
                write(mBuffer, size); // Write audio samples to engine
            }
        }
    }
}

在线程中不断调用 SpeechRecognizerwrite(byte[] data, long size) 方法,将录音数据持续传输到 SDK 内。

默认的录音实现中,我们为你实现了一个通用的唤醒模块,可以通过 「嘿,小飞」「小飞小飞」 等方式唤醒。

  • 如果想要取消唤醒功能,在SpeechRecognizerHandler的构造函数中,wakeWordSupported以及wakeWordEnabled参数传入 false 即可。
  • 如果你需要从刚开始启动引擎就开始录音,但不需要我们内置的唤醒功能的话,复写 wakewordDetected 返回 false 即可,表示不处理内置唤醒模块的唤醒事件。

如果你的设备采用了专有的录音方案(如多麦克风降噪),也可以通过复写模块中执行读录音线程相关(AudioReader)的代码,就可以很方便地将你的录音方案对接到 SDK 中。

部分功能介绍

绑定授权

运行 Demo 的第一步需要为 SDK 进行授权。进行授权需要调用 app module 中的授权模块。主要代码位于 com.iflytek.cyber.iot.show.core.impl.AuthProvider 包名下,下面介绍应当如何使用授权功能。

1. 启动授权

EngineService 服务会处理 EngineService.ACTION_LOGIN,触发 AuthProvider 开始登陆操作,申请 user_code

2. 处理授权 URL

在 Demo 中,将授权 URL 转换为一个二维码图片展示在界面中,通过 iFLYOS 配套 APP SDK 即可打开对应的授权页面。

二维码界面对应的类为 PairFragment

首先,需要注册对应的 Observer,可以通过直接调用 activity.addObserver(...) 来注册,注册后所有的事件会传递到对应的 Observer 中。

然后,在调用登录操作之后,会发送 typeLoggerHandler.CBL_CODE 的事件,并且在其中携带相关的参数。(示例代码:跳转到 GitHub)通过 verification_uriuser_code 参数,生成对应的 URL,传入配套 APP SDK 的对应接口即可(Android 接口说明iOS 接口说明)。

3. 授权完成回调

授权完成后,可以接收到 typeLoggerHandler.AUTH_LOG 的事件,获得其中的 auth_state 字段为 AuthState.REFRESHED 时,表示授权完成。(参考实现

界面交互、或按键触发状态变更

根据设备能力API的部分要求,设备的一些状态改变(音量、播放暂停等)需要向服务端上报事件通知更改,故接入 SDK 时我们预先实现了上报事件的各个逻辑,但是你在接入 SDK 的时候,应当通过调用我们的接口来对设备部分状态进行更改。例如

改变音量

改变音量需要触发到 MediaPlayerHandler 中的 SpeakerHandlerlocalVolumeSet 来通知音量变更,调用之后会触发 SpeakerHandler 中的 setVolume 函数,进行对应的音量变更,且 SDK 会上报新的音量,通知服务端设备发生了音量变更。

EngineService 封装了音量变更的对应操作,通过 EngineService.ACTION_UPDATE_VOLUME 可以触发对应操作

静音/取消静音

与改变音量类似,对应的操作可以通过 EngineService.ACTION_UPDATE_MUTE 触发。

接入常见问题

问:打开 Android Studio 项目网络失败?

答:需要能够正常访问 jCenter、Google Maven 的网络连接。

问:网络确实连上了,但是绑定帐号提示「网络异常,请重试。」

答:请检查设备的时间是否正确。不正确的时间会导致与服务端的 HTTPS 通讯失败。

问:二维码显示正常,但是绑定设备提示「无效应用。」

答:ShowCore 中内置的 Client Id 是仅作为测试用的,如果此 Id 失效,请在参考控制台管理设备介绍获取你创建的自定义设备的 Client Id,进行替换,并完成如下操作:

  1. 在设备接入控制台-设备能力页,打开【有屏配网】能力。
  2. 在设备接入控制台-测试调试页,填写你绑定设备时使用的手机号。

问:如何更换自己创建的设备 clientId

答:在 app/build.gradle 文件中,定义了所要使用的 clientId,参考此处的代码更换你所想使用的 clientId 即可。

iFLYOS文档中心