WeChat mini program

更新时间:
复制 MD 格式

This topic describes how to use the WeChat mini program software development kit (SDK) for Alibaba Cloud Voice Service. It covers how to install the SDK and provides code samples.

Prerequisites

Before you use the SDK, read the API reference. For more information, see API reference.

Download and install

  1. Download and install the SDK.

    You can download the SDK code from Github or download the alibabacloud-nls-wx-sdk-master.zip file directly.

  2. Import the SDK.

    Copy the downloaded code to a folder in your project. Then, import the SDK using `require` and specifying the folder path.

Get a token

getToken

This method obtains a token and caches it using the AKID (AccessKey ID) and AKKEY (AccessKey Secret) as keys. If the cached token expires, the method automatically refreshes the token. For more information about the caching mechanism, see the Data Caching topic in the WeChat Mini Program documentation.

  • Parameters: None.

  • Return value: A string that represents the token.

getTokenInner

This method directly retrieves a token without using the caching mechanism. This method is suitable for custom caching.

  • Parameters: None.

  • Return value: A string that represents the token.

Important

The server denies frequent calls to this API.

Key interfaces and parameters

To implement speech synthesis, use the SpeechSynthesizer class. You can write the code by following these steps. Steps 2 and 3 are interchangeable.

  1. Create a SpeechSynthesizer instance and provide the speech synthesis endpoint and authentication information.

  2. Set speech synthesis properties, such as the voice, sample rate, and audio format. You can create a properties object or modify the default properties object that is returned by the defaultStartParams method of the SpeechSynthesizer instance.

  3. Implement the on callback function of the SpeechSynthesizer instance. This function uses the observer pattern. The server notifies the client by invoking the on callback function when a connection is established, speech is synthesized, or an exception occurs.

  4. Call the start function of the SpeechSynthesizer instance to begin speech synthesis.

1. SpeechSynthesizer class

The SpeechSynthesizer class is used for speech synthesis.

The following table describes the parameters of the SpeechSynthesizer constructor.

Parameter

Type

Description

config

Object

The connection configuration object.

The following table describes the `config` parameters.

Parameter

Type

Description

url

String

The speech synthesis endpoint. The default value is wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1.

Configure an endpoint as needed. For more information, see Endpoints.

token

String

The access token. For more information, see Overview of how to obtain a token.

appkey

String

The AppKey of the project.

Example:

let tts = new SpeechSynthesizer({
    url: app.globalData.URL,
    appkey:app.globalData.APPKEY,
    token:this.data.token
})

2. Set speech synthesis properties such as voice, sample rate, and audio format

You can set properties based on the default properties object that is returned by the defaultStartParams method of the SpeechSynthesizer instance, or you can define a custom properties object. This properties object must be passed when you call the start function of the SpeechSynthesizer instance.

Parameters:

Parameter

Type

Required

Description

text

String

Yes

The text to synthesize. The text must be UTF-8 encoded and cannot exceed 300 characters. Add spaces between English letters.

Note

To use multi-emotion content for a voice, add the ssml-emotion tag to the text. For more information, see <emotion>.

voice

String

No

The voice. The default value is xiaoyun.

format

String

No

The audio coding format. Supported formats are .pcm, .wav, and .mp3. The default value is pcm.

sample_rate

Integer

No

The audio sampling rate. The default value is 16000 Hz.

volume

Integer

No

The volume. The value range is 0 to 100. The default value is 50.

speech_rate

Integer

No

The speech rate. The value range is -500 to 500. The default value is 0.

The values [-500, 0, 500] correspond to a speed multiplier range of [0.5, 1.0, 2.0].

  • -500 indicates 0.5 times the default speech rate.

  • 0 indicates 1.0 times the default speech rate. The 1.0x speed is the default synthesis speed of the model. The speed varies slightly for each voice, at about four characters per second.

  • 500 indicates 2.0 times the default speech rate.

The calculation method is as follows:

  • 0.8x speed: (1 - 1/0.8) / 0.002 = -125

  • 1.2x speed: (1 - 1/1.2) / 0.001 = 166

Note

  • For speeds less than 1.0x, use a coefficient of 0.002.

  • For speeds greater than 1.0x, use a coefficient of 0.001.

The actual algorithm result is an approximation.

pitch_rate

Integer

No

The pitch. The value range is -500 to 500. The default value is 0.

enable_subtitle

Boolean

No

Enables word-level timestamps. For more information about how to use this feature, see Introduction to the speech synthesis timestamp feature.

Set properties based on the default properties returned by defaultStartParams

The defaultStartParams function returns an object:

{
  voice: voice, // The value of voice is the parameter passed when the function is called
  format: "wav",
  sample_rate: 16000,
  volume: 50,
  speech_rate: 0,
  pitch_rate: 0,
  enable_subtitle: false
}

You can reset this object. For example:

let param = tts.defaultStartParams();
// The text to synthesize
param.text = "Looking up, I see the bright moon. Bowing my head, I think of my hometown.";
// The voice
param.voice = "aixia";
// The pitch. The range is -500 to 500. This parameter is optional. The default value is 0.
// param.pitch_rate = 100;
// The speech rate. The range is -500 to 500. The default value is 0.
// param.speech_rate = 100;
// Set the encoding format of the returned audio.
// param.format = "wav";
// Set the sample rate of the returned audio.
// param.sample_rate = 16000;
// Specifies whether to enable word-level timestamps.
// param.enable_subtitle = true;

Custom properties object

let param = {};
// The text to synthesize
param.text = line;
// The voice
param.voice = "aixia";
// The pitch. The range is -500 to 500. This parameter is optional. The default value is 0.
// param.pitch_rate = 100;
// The speech rate. The range is -500 to 500. The default value is 0.
// param.speech_rate = 100;
// Set the encoding format of the returned audio.
// param.format = "wav";
// Set the sample rate of the returned audio.
// param.sample_rate = 16000;
// Specifies whether to enable word-level timestamps.
// param.enable_subtitle = true;

3. Callback function on

The source code of the on function is as follows:

on(which, handler)

After a speech synthesis task starts, the server invokes this callback function to send information about the synthesis process to the client.

Parameter

Type

Description

which

String

The event name.

handler

Function

The callback function.

The which parameter specifies one of the following events:

Event name

Event description

Number of callback function parameters

Callback function parameter description

meta

Caption callback.

1

String type. The caption information.

data

Synthesized audio callback.

1

Buffer type. The synthesized audio data.

completed

Speech synthesis is complete.

1

String type. The completion message.

closed

Connection is closed.

0

None.

failed

Error.

1

String type. The error message.

Example:

let tts = new SpeechSynthesizer({
    url: app.globalData.URL,
    appkey:app.globalData.APPKEY,
    token:this.data.token
})

tts.on("meta", (msg)=>{
  console.log("Client recv metainfo:", msg)
})

tts.on("data", (msg)=>{
  console.log(`recv size: ${msg.length}`)
  console.log(dumpFile.write(msg, "binary"))
})

tts.on("completed", (msg)=>{
  console.log("Client recv completed:", msg)
})

tts.on("closed", () => {
  console.log("Client recv closed")
})

tts.on("failed", (msg)=>{
  console.log("Client recv failed:", msg)
})

4. Start task: start

The start function starts speech synthesis based on the information in the provided param. The server returns the synthesis results and other information by invoking the on callback function.

async start(param)

Parameters:

Parameter

Type

Description

param

Object

The speech synthesis parameters.

Return value: A Promise object that contains exception information if an error occurs.

Code sample

The following code sample is for reference only. The code uses the built-in recording feature of WeChat mini programs. When you use the code, you must consider the limitations of WeChat mini programs, the frontend page design, and your specific business requirements.

// pages/tts/tts.js
const app = getApp()

const AKID = "Your AKID"
const AKKEY = "Your AKKEY"
const SpeechSynthesizer = require("../../utils/tts")
const formatTime = require("../../utils/util").formatTime
const sleep = require("../../utils/util").sleep
const getToken = require("../../utils/token").getToken
const fs = wx.getFileSystemManager()
Page({

    /**
     * Initial data of the page
     */
    data: {
        ttsStart: false, 
        ttsText: ""
    },

    /**
     * Lifecycle function--Called when the page is loaded
     */
    onLoad: async function (options) {
        try {
            this.data.token = await getToken(AKID, AKKEY)
        } catch (e) {
            console.log("error on get token:", JSON.stringify(e))
            return
        }

        let tts = new SpeechSynthesizer({
            url: app.globalData.URL,
            appkey:app.globalData.APPKEY,
            token:this.data.token
        })
        
        tts.on("meta", (msg)=>{
            console.log("Client recv metainfo:", msg)
        })
    
        tts.on("data", (msg)=>{
            console.log(`recv size: ${msg.byteLength}`)
            //console.log(dumpFile.write(msg, "binary"))
            if (this.data.saveFile) {
                try {
                  fs.appendFileSync(
                      this.data.saveFile,
                      msg,
                      "binary"
                  )
                  console.log(`append ${msg.byteLength}`)
                } catch (e) {
                  console.error(e)
                }
            } else {
                console.log("save file empty")
            }
        })
    
        tts.on("completed", async (msg)=>{
            console.log("Client recv completed:", msg)
            await sleep(500)
            fs.close({
                fd : this.data.saveFd,
                success: (res)=> {
                    let ctx = wx.createInnerAudioContext()
                    ctx.autoplay = true
                    ctx.src = this.data.saveFile
                    ctx.onPlay(() => {
                        console.log('start playing..')
                    })
                    ctx.onError((res) => {
                        console.log(res.errMsg)
                        console.log(res.errCode)
                        fs.unlink({
                            filePath: this.data.saveFile,
                            success: (res)=>{
                                console.log(`remove ${this.data.saveFile} done`)
                                this.data.saveFile = null
                                this.data.saveFd = null
                            },
                            failed: (res)=>{
                                console.log("remove failed:" + res.errMsg)
                            }
                        })
                    })
                    ctx.onEnded((res)=>{
                        console.log("play done...")
                        fs.unlink({
                            filePath: this.data.saveFile,
                            success: (res)=>{
                                console.log(`remove ${this.data.saveFile} done`)
                                this.data.saveFile = null
                                this.data.saveFd = null
                            },
                            failed: (res)=>{
                                console.log("remove failed:" + res.errMsg)
                            }
                        })
                    })
                },
                fail : (res)=>{
                    console.log("saved file error:" + res.errMsg)
                }
            })
        })
    
        tts.on("closed", () => {
            console.log("Client recv closed")
        })
    
        tts.on("failed", (msg)=>{
            console.log("Client recv failed:", msg)
        })

        this.data.tts = tts
    },

    /**
     * Lifecycle function--Called when the page is first rendered
     */
    onReady: function () {

    },

    /**
     * Lifecycle function--Called when the page is displayed
     */
    onShow: function () {

    },

    /**
     * Lifecycle function--Called when the page is hidden
     */
    onHide: function () {

    },

    /**
     * Lifecycle function--Called when the page is uninstalled
     */
    onUnload: function () {

    },

    /**
     * Page-related event handler function--Listens for user pull-down actions
     */
    onPullDownRefresh: function () {

    },

    /**
     * Handler function for the page pull-up and bottom-reaching event
     */
    onReachBottom: function () {

    },

    /**
     * Called when the user clicks the share button in the upper-right corner
     */
    onShareAppMessage: function () {

    },
    textInput: function(e) {
        this.setData({
            ttsText:e.detail.value
        })
    },
    onTtsStart: function() {
        if (!this.data.ttsText || !this.data.tts) {
            console.log("text empty")
            wx.showToast({
                title: "Text is empty",
                icon: "error",
                duration: 1000,
                mask: true
              })
            return
        }
        if (this.data.ttsStart) {
            wx.showToast({
                title: "Synthesizing. Please wait.",
                icon: "error",
                duration: 1000,
                mask: true
              })
            return
        } else {
            this.data.ttsStart = true
        }
        console.log("try to synthesize:" + this.data.ttsText)
        let save = formatTime(new Date()) + ".wav"
        let savePath = wx.env.USER_DATA_PATH + "/" + save
        console.log(`save to ${savePath}`)
        fs.open({
            filePath:savePath,
            flag : "a+",
            success: async (res)=> {
                console.log(`open ${savePath} done`)
                this.data.saveFd = res.fd
                this.data.saveFile = savePath
                let param = this.data.tts.defaultStartParams()
                param.text = this.data.ttsText
                param.voice = "aixia"
                try {
                    await this.data.tts.start(param)
                    console.log("tts done")
                    this.data.ttsStart = false
                } catch(e) {
                    console.log("tts start error:" + e)
                }
            },
            fail: (res)=> {
                console.log(`open ${savePath} failed: ${res.errMsg}`)
            }
        })
    }
})