# NLS Python SDK说明



本文介绍如何使用阿里云智能语音服务提供的Python SDK,包括SDK的安装方法及SDK代码示例。

> 说明
>
> * 当前版本:0.0.1,支持python3



## 安装

解压SDK压缩包后进入SDK根目录使用如下命令安装SDK依赖:

> python -m pip install -r requirements.txt

依赖安装完成后使用如下命令安装SDK:

> python -m pip install .

> 注意:
>
> 上述命令需要在SDK根目录中执行

安装完成后通过以下代码可以导入SDK:

> #!/bin/python
>
> import nls



## 多线程和多并发

根据Python官方文档:

> **CPython implementation detail:** 在 CPython 中,由于存在 [全局解释器锁](https://docs.python.org/zh-cn/3/glossary.html#term-global-interpreter-lock),同一时刻只有一个线程可以执行 Python 代码(虽然某些性能导向的库可能会去除此限制)。 如果你想让你的应用更好地利用多核心计算机的计算资源,推荐你使用 [`multiprocessing`](https://docs.python.org/zh-cn/3/library/multiprocessing.html#module-multiprocessing) 或 [`concurrent.futures.ProcessPoolExecutor`](https://docs.python.org/zh-cn/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor)。 但是,如果你想要同时运行多个 I/O 密集型任务,则多线程仍然是一个合适的模型。

如果单解释器有太多线程,那么线程间切换的消耗会非常客观,有可能会导致SDK出现错误,不建议超过200线程的使用,如果有必要使用multiprocessing技术或者手动使用脚本创建多个解释器



## 一句话识别

一句话识别对应的类为NlsSpeechRecognizer,其核心方法如下:

### 1. 初始化(\_\_init\_\_)

参数说明:

| 参数              | 类型     | 参数说明                                                     |
| ----------------- | -------- | ------------------------------------------------------------ |
| url               | str      | 网关websocket url,默认为wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1 |
| akid              | str      | 账号access id,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| aksecret          | str      | 账号access secret key,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| token             | str      | 访问token,参考开发指南—获取Token及获取Token协议说明相关内容 |
| on_start          | function | 当一句话识别就绪时的回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_result_changed | function | 当一句话识别返回中间结果时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_completed      | function | 当一句话识别返回最终识别结果时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_error          | function | 当SDK或云端出现错误时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_close          | function | 当和云端连接断开时回调,回调参数有一个——用户自定义参数,见后续callback_args参数说明 |
| callback_args     | list     | 用户自定义参数列表,里面的内容会pack成list传递给各个回调的最后一个参数 |

返回值:

无

### 2. start

> 同步开始一句话识别,该方法会阻塞当前线程直到一句话识别就绪(on_start回调返回)

参数说明:

| 参数                              | 类型 | 参数说明                                                     |
| --------------------------------- | ---- | ------------------------------------------------------------ |
| aformat                           | str  | 要识别音频格式,支持pcm,opus,opu,默认pcm,**SDK不会自动将pcm编码成opus或opu,如果需要使用opus或opu,需要用户自行编码** |
| sample_rate                       | int  | 识别音频采样率,默认16000                                    |
| ch                                | int  | 音频通道数,默认为1,不需要提供                              |
| enable_intermediate_result        | bool | 是否返回中间结果,默认False                                  |
| enable_punctuation_prediction    | bool | 是否进行识别结果标点预测,默认False                          |
| enable_inverse_text_normalization | bool | 是否进行ITN,默认False                                       |
| timeout                           | int  | 阻塞超时,默认10秒                                           |
| ping_interval                     | int  | ping包发送间隔,默认8,不需要可以设置为0或None               |
| ping_timeout                      | int  | 是否检查pong包超时,默认为None,None为不检查pong包超时       |
| ex                                | dict | 用户提供的额外参数,该字典内容会以key:value形式合并进请求的payload段中,具体可用参数见一句话语音识别接口说明 |

返回值:

bool类型,False为失败,True为成功

### 3. stop

> 停止一句话识别,并同步等待on_completed回调结束

参数说明:

| 参数    | 类型 | 参数说明           |
| ------- | ---- | ------------------ |
| timeout | int  | 阻塞超时,默认10秒 |

返回值:

bool类型,False为失败,True为成功

### 4. shutdown

> 强行关闭当前请求,重复调用无副作用

参数说明:

无

返回值:

无

### 5. send_audio

> 发送二进制音频数据,发送数据的格式需要和start中的aformat对应

参数说明:

| 参数     | 类型  | 参数说明                                                     |
| -------- | ----- | ------------------------------------------------------------ |
| pcm_data | bytes | 要发送的二进制音频数据,格式需要和上一次start中的aformat相对应。**SDK不会自动将pcm编码成opus或opu,如果需要使用opus或opu,需要用户自行编码** |

返回值:

bool类型,False为失败,True为成功



### 代码示例:

```python
import time
import threading
import sys

import nls


URL="wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1"
AKID="Your AKID"
AKKEY="Your AKSECRET"
APPKEY="Your APPKEY"

#以下代码会根据音频文件内容反复进行一句话识别
class TestSr:
    def __init__(self, tid, test_file):
        self.__th = threading.Thread(target=self.__test_run)
        self.__id = tid
        self.__test_file = test_file
   
    def loadfile(self, filename):
        with open(filename, "rb") as f:
            self.__data = f.read()
    
    def start(self):
        self.loadfile(self.__test_file)
        self.__th.start()

    def test_on_start(self, message, *args):
        print("test_on_start:{}".format(message))

    def test_on_error(self, message, *args):
        print("on_error args=>{}".format(args))

    def test_on_close(self, *args):
        print("on_close: args=>{}".format(args))

    def test_on_result_chg(self, message, *args):
        print("test_on_chg:{}".format(message))

    def test_on_completed(self, message, *args):
        print("on_completed:args=>{} message=>{}".format(args, message))


    def __test_run(self):
        print("thread:{} start..".format(self.__id))
        
        sr = nls.NlsSpeechRecognizer(
                    url=URL,
                    akid=AKID,
                    aksecret=AKKEY,
                    appkey=APPKEY,
                    on_start=self.test_on_start,
                    on_result_changed=self.test_on_result_chg,
                    on_completed=self.test_on_completed,
                    on_error=self.test_on_error,
                    on_close=self.test_on_close,
                    callback_args=[self.__id]
                )
        while True:
            print("{}: session start".format(self.__id))
            r = sr.start(aformat="pcm", ex={"hello":123})
           
            self.__slices = zip(*(iter(self.__data),) * 640)
            for i in self.__slices:
                sr.send_audio(bytes(i))
                time.sleep(0.01)

            r = sr.stop()
            print("{}: sr stopped:{}".format(self.__id, r))
            time.sleep(1)

def multiruntest(num=500):
    for i in range(0, num):
        name = "thread" + str(i)
        t = TestSr(name, "tests/test1.pcm")
        t.start()

nls.enableTrace(True)
multiruntest(1)



```



## 实时语音识别

实时语音识别对应的类为NlsSpeechTranscriber,其核心方法如下:

### 1. 初始化(\_\_init\_\_)

参数说明:

| 参数              | 类型     | 参数说明                                                     |
| ----------------- | -------- | ------------------------------------------------------------ |
| url               | str      | 网关websocket url,默认为wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1 |
| akid              | str      | 账号access id,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| aksecret          | str      | 账号access secret key,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| token             | str      | 访问token,参考开发指南—获取Token及获取Token协议说明相关内容 |
| on_start          | function | 当实时识别就绪时的回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_sentence_begin | function | 当实时识别一句话开始时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_sentence_end   | function | 当实时识别一句话结束时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_result_changed | function | 当实时识别返回中间结果时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_completed      | function | 当实时识别返回最终识别结果时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_error          | function | 当SDK或云端出现错误时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_close          | function | 当和云端连接断开时回调,回调参数有一个——用户自定义参数,见后续callback_args参数说明 |
| callback_args     | list     | 用户自定义参数列表,里面的内容会pack成list传递给各个回调的最后一个参数 |

返回值:

无

### 2. start

> 同步开始实时识别,该方法会阻塞当前线程直到实时识别就绪(on_start回调返回)

参数说明:

| 参数                              | 类型 | 参数说明                                                     |
| --------------------------------- | ---- | ------------------------------------------------------------ |
| aformat                           | str  | 要识别音频格式,支持pcm,opus,opu,默认pcm,**SDK不会自动将pcm编码成opus或opu,如果需要使用opus或opu,需要用户自行编码** |
| sample_rate                       | int  | 识别音频采样率,默认16000                                    |
| ch                                | int  | 音频通道数,默认为1,不需要提供                              |
| enable_intermediate_result        | bool | 是否返回中间结果,默认False                                  |
| enable_punctuation_prediction    | bool | 是否进行识别结果标点预测,默认False                          |
| enable_inverse_text_normalization | bool | 是否进行ITN,默认False                                       |
| timeout                           | int  | 阻塞超时,默认10秒                                           |
| ping_interval                     | int  | ping包发送间隔,默认8,不需要可以设置为0或None               |
| ping_timeout                      | int  | 是否检查pong包超时,默认为None,None为不检查pong包超时       |
| ex                                | dict | 用户提供的额外参数,该字典内容会以key:value形式合并进请求的payload段中,具体可用参数见实时语音识别接口说明 |

返回值:

bool类型,False为失败,True为成功

### 3. stop

> 停止实时识别,并同步等待on_completed回调结束

参数说明:

| 参数    | 类型 | 参数说明           |
| ------- | ---- | ------------------ |
| timeout | int  | 阻塞超时,默认10秒 |

返回值:

bool类型,False为失败,True为成功

### 4. shutdown

> 强行关闭当前请求,重复调用无副作用

参数说明:

无

返回值:

无

### 5. send_audio

> 发送二进制音频数据,发送数据的格式需要和start中的aformat对应

参数说明:

| 参数     | 类型  | 参数说明                                                     |
| -------- | ----- | ------------------------------------------------------------ |
| pcm_data | bytes | 要发送的二进制音频数据,格式需要和上一次start中的aformat相对应。**SDK不会自动将pcm编码成opus或opu,如果需要使用opus或opu,需要用户自行编码** |

返回值:

bool类型,False为失败,True为成功

### 6. ctrl

> 发送控制命令,先阅读实时语音识别接口说明

参数说明:

| 参数 | 类型 | 参数说明                                                     |
| ---- | ---- | ------------------------------------------------------------ |
| ex   | dict | 自定义控制命令,该字典内容会以key:value形式合并进请求的payload段中 |

返回值:

bool类型,False为失败,True为成功



### 代码示例

```python
import time
import threading
import sys

import nls


URL="wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1"
AKID="Your AKID"
AKKEY="Your AKSECRET"
APPKEY="Your APPKEY"

#以下代码会根据音频文件内容反复进行实时识别(文件转写)
class TestSt:
    def __init__(self, tid, test_file):
        self.__th = threading.Thread(target=self.__test_run)
        self.__id = tid
        self.__test_file = test_file
   
    def loadfile(self, filename):
        with open(filename, "rb") as f:
            self.__data = f.read()
    
    def start(self):
        self.loadfile(self.__test_file)
        self.__th.start()

    def test_on_sentence_begin(self, message, *args):
        print("test_on_sentence_begin:{}".format(message))

    def test_on_sentence_end(self, message, *args):
        print("test_on_sentence_end:{}".format(message))

    def test_on_start(self, message, *args):
        print("test_on_start:{}".format(message))

    def test_on_error(self, message, *args):
        print("on_error args=>{}".format(args))

    def test_on_close(self, *args):
        print("on_close: args=>{}".format(args))

    def test_on_result_chg(self, message, *args):
        print("test_on_chg:{}".format(message))

    def test_on_completed(self, message, *args):
        print("on_completed:args=>{} message=>{}".format(args, message))


    def __test_run(self):
        print("thread:{} start..".format(self.__id))
        sr = nls.NlsSpeechTranscriber(
                    url=URL,
                    akid=AKID,
                    aksecret=AKKEY,
                    appkey=APPKEY,
                    on_sentence_begin=self.test_on_sentence_begin,
                    on_sentence_end=self.test_on_sentence_end,
                    on_start=self.test_on_start,
                    on_result_changed=self.test_on_result_chg,
                    on_completed=self.test_on_completed,
                    on_error=self.test_on_error,
                    on_close=self.test_on_close,
                    callback_args=[self.__id]
                )
        while True:
            print("{}: session start".format(self.__id))
            r = sr.start(aformat="pcm",
                    enable_intermediate_result=True,
                    enable_punctuation_prediction=True,
                    enable_inverse_text_normalization=True)

            self.__slices = zip(*(iter(self.__data),) * 640)
            for i in self.__slices:
                sr.send_audio(bytes(i))
                time.sleep(0.01)

            sr.ctrl(ex={"test":"tttt"})
            time.sleep(1)

            r = sr.stop()
            print("{}: sr stopped:{}".format(self.__id, r))
            time.sleep(1)

def multiruntest(num=500):
    for i in range(0, num):
        name = "thread" + str(i)
        t = TestSt(name, "tests/test1.pcm")
        t.start()

nls.enableTrace(True)
multiruntest(1)

```



## 语音合成

语音合成对应的类为NlsSpeechSynthesizer,其核心方法如下:

### 1. 初始化(\_\_init\_\_)

参数说明:

| 参数          | 类型     | 参数说明                                                     |
| ------------- | -------- | ------------------------------------------------------------ |
| url           | str      | 网关websocket url,默认为wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1 |
| akid          | str      | 账号access id,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| aksecret      | str      | 账号access secret key,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| token         | str      | 访问token,参考开发指南—获取Token及获取Token协议说明相关内容 |
| on_metainfo   | function | 如果start中通过ex参数传递enable_subtitle,则会返回对应字幕信息,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_data       | function | 当存在合成数据后回调,回调参数有两个,一个是对应start方法aformat的二进制音频数据,一个是用户自定义参数,见后续callback_args参数说明 |
| on_completed  | function | 当合成完毕时候回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_error      | function | 当SDK或云端出现错误时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_close      | function | 当和云端连接断开时回调,回调参数有一个——用户自定义参数,见后续callback_args参数说明 |
| callback_args | list     | 用户自定义参数列表,里面的内容会pack成list传递给各个回调的最后一个参数 |

返回值:

无

### 2. start

> 同步开始语音合成,如果wait_complete为True(默认)则会阻塞直到所有音频合成完毕(on_completed返回之后)返回,否则会立即返回

参数说明:

| 参数              | 类型 | 参数说明                                                     |
| ----------------- | ---- | ------------------------------------------------------------ |
| text              | str  | 要合成的文字                                                 |
| aformat           | str  | 合成出来音频的格式,默认为"pcm"                              |
| voice             | str  | 发音人,默认为”xiaoyun“                                      |
| sample_rate       | int  | 识别音频采样率,默认16000                                    |
| volume            | int  | 音量大小,0~100,默认为50                                    |
| speech_rate       | int  | 语速,-500~500,默认为0                                      |
| pitch_rate        | int  | 语调,-500~500,默认为0                                      |
| wait_complete     | bool | 是否阻塞到合成完成                                           |
| start_timeout     | int  | 和云端连接建立超时,默认10秒                                 |
| completed_timeout | int  | 从连接建立到合成完成超时,默认60秒                           |
| ping_interval                     | int  | ping包发送间隔,默认8,不需要可以设置为0或None               |
| ping_timeout                      | int  | 是否检查pong包超时,默认为None,None为不检查pong包超时       |
| ex                | dict | 用户提供的额外参数,该字典内容会以key:value形式合并进请求的payload段中,具体可用参数见实时语音识别接口说明 |

返回值:

bool类型,False为失败,True为成功

### 3. shutdown

> 强行关闭当前请求,重复调用无副作用

参数说明:

无

返回值:

无

### 代码示例:

```python
import time
import threading
import sys

import nls

URL="wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1"
AKID="Your AKID"
AKKEY="Your AKSECRET"
APPKEY="Your APPKEY"



TEXT='大壮正想去摘取花瓣,谁知阿丽和阿强突然内讧,阿丽拿去手枪向树干边的阿强射击,两声枪响,阿强直接倒入水中'

#以下代码会根据上述TEXT文本反复进行语音合成
class TestTts:
    def __init__(self, tid, test_file):
        self.__th = threading.Thread(target=self.__test_run)
        self.__id = tid
        self.__test_file = test_file
   
    def start(self, text):
        self.__text = text
        self.__f = open(self.__test_file, "wb")
        self.__th.start()
    
    def test_on_metainfo(self, message, *args):
        print("on_metainfo message=>{}".format(message))  

    def test_on_error(self, message, *args):
        print("on_error args=>{}".format(args))

    def test_on_close(self, *args):
        print("on_close: args=>{}".format(args))
        try:
            self.__f.close()
        except Exception as e:
            print("close file failed since:", e)

    def test_on_data(self, data, *args):
        try:
            self.__f.write(data)
        except Exception as e:
            print("write data failed:", e)

    def test_on_completed(self, message, *args):
        print("on_completed:args=>{} message=>{}".format(args, message))


    def __test_run(self):
        print("thread:{} start..".format(self.__id))
        tts = nls.NlsSpeechSynthesizer(
                    url=URL,
                    akid=AKID,
                    aksecret=AKKEY,
                    appkey=APPKEY,
                    on_metainfo=self.test_on_metainfo,
                    on_data=self.test_on_data,
                    on_completed=self.test_on_completed,
                    on_error=self.test_on_error,
                    on_close=self.test_on_close,
                    callback_args=[self.__id]
                )

        while True:
            print("{}: session start".format(self.__id))
            r = tts.start(self.__text, voice="ailun")
            print("{}: tts done with result:{}".format(self.__id, r))
            time.sleep(1)

def multiruntest(num=500):
    for i in range(0, num):
        name = "thread" + str(i)
        t = TestTts(name, "tests/test_tts.pcm")
        t.start(TEXT)

nls.enableTrace(True)
multiruntest(1)

```



## 高级用法——使用CommonProto实现任意接口

nls包下面的NlsCommonProto对象可以用来实现智能语音交互的任意接口,其核心方法如下:

### 1. 初始化(\_\_init\_\_)

参数说明:

| 参数          | 类型     | 参数说明                                                     |
| ------------- | -------- | ------------------------------------------------------------ |
| url           | str      | 网关websocket url,默认为wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1 |
| akid          | str      | 账号access id,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| aksecret      | str      | 账号access secret key,默认为None,如果需要获取token,则需要提供,如果已有token,则不需要提供 |
| token         | str      | 访问token,参考开发指南—获取Token及获取Token协议说明相关内容 |
| on_open       | function | 当和云端建连完成后回调,回调参数有一个——用户自定义参数,见后续callback_args参数说明 |
| on_error      | function | 当SDK或云端出现错误时回调,回调参数有两个,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| on_close      | function | 当和云端连接断开时回调,回调参数有一个——用户自定义参数,见后续callback_args参数说明 |
| on_data       | function | 当云端返回二进制数据时回调,回调参数有两个,一个是二进制数据,一个是用户自定义参数,见后续callback_args参数说明 |
| user_callback | dict     | 用户自定义回调字典,key为str类型,value为function类型,当SDK收到云端应答后,会根据应答内部header字段下面name字段来索引该字典,如果对应item存在则会回调对应function。该回调包括两个参数,一个是json形式的字符串,一个是用户自定义参数,见后续callback_args参数说明 |
| callback_args | list     | 用户自定义参数列表,里面的内容会pack成list传递给各个回调的最后一个参数 |

返回值:

无

### 2. start

> **异步**和云端建连并发起一次请求

参数说明:

| 参数    | 类型 | 参数说明                                 |
| ------- | ---- | ---------------------------------------- |
| name    | str  | 对应header字段中的name,用于指明请求类型 |
| payload | dict | 请求中的payload,默认为{}                |
| context | dict | 请求中的context,默认为{}                |
| ping_interval                     | int  | ping包发送间隔,默认8,不需要可以设置为0或None               |
| ping_timeout                      | int  | 是否检查pong包超时,默认为None,None为不检查pong包超时       |

返回值:

bool类型,False为失败,True为成功

### 3. shutdown

> 强行关闭当前请求,重复调用无副作用

参数说明:

无

返回值:

无

### 4. send_text

> 发送文本请求

参数说明:

| 参数    | 类型 | 参数说明                                 |
| ------- | ---- | ---------------------------------------- |
| name    | str  | 对应header字段中的name,用于指明请求类型 |
| payload | dict | 请求中的payload,默认为{}                |
| context | dict | 请求中的context,默认为{}                |

返回值:

bool类型,False为失败,True为成功

### 5. send_binary

> 发送二进制数据

参数说明:

| 参数     | 类型  | 参数说明           |
| -------- | ----- | ------------------ |
| pcm_data | bytes | 要发送的二进频数据 |

返回值:

bool类型,False为失败,True为成功



### 示例代码:

```python
import time
import threading
import sys

import nls

URL="wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1"
AKID="Your AKID"
AKKEY="Your AKSECRET"
APPKEY="Your APPKEY"

#以下代码会通过文件反复进行一句话识别
class TestSrCommon:
    def __init__(self, tid, test_file):
        self.__th = threading.Thread(target=self.__test_run)
        self.__id = tid
        self.__test_file = test_file
   
    def loadfile(self, filename):
        with open(filename, "rb") as f:
            self.__data = f.read()
    
    def start(self):
        self.loadfile(self.__test_file)
        self.__th.start()

    def test_on_open(self, *args):
        print("test_on_start")

    def test_on_start(self, message, *args):
        print("test_on_start:{}".format(message))

    def test_on_data(self, data, *args):
        pass

    def test_on_error(self, message, *args):
        print("on_error args=>{}".format(args))

    def test_on_close(self, *args):
        print("on_close: args=>{}".format(args))

    def test_on_result_chg(self, message, *args):
        print("test_on_chg:{}".format(message))

    def test_on_completed(self, message, *args):
        print("on_completed:args=>{} message=>{}".format(args, message))
        self.__sr.shutdown() 

    def __test_run(self):
        print("thread:{} start..".format(self.__id))
        callbacks = {
                "RecognitionStarted":self.test_on_start,
                "RecognitionResultChanged":self.test_on_result_chg,
                "RecognitionCompleted":self.test_on_completed
                }
        self.__sr = nls.NlsCommonProto(
                    url=URL,
                    akid=AKID,
                    aksecret=AKKEY,
                    appkey=APPKEY,
                    namespace="SpeechRecognizer",
                    on_open=self.test_on_open,
                    on_data=self.test_on_data,
                    on_error=self.test_on_error,
                    on_close=self.test_on_close,
                    user_callback=callbacks,
                    callback_args=[self.__id]
                )

        while True:
            print("{}: session start".format(self.__id))
            r = self.__sr.start(name="StartRecognition",
                    payload={
                        "format":"pcm",
                        "sample_rate":16000
                        }
                    )
            if not r:
                print("start failed")
                break
            time.sleep(1)
           
            self.__slices = zip(*(iter(self.__data),) * 640)
            for i in self.__slices:
                self.__sr.send_binary(bytes(i))
                time.sleep(0.01)

            self.__sr.send_text(name="StopRecognition") 
            time.sleep(1)

def multiruntest(num=500):
    for i in range(0, num):
        name = "thread" + str(i)
        t = TestSrCommon(name, "tests/test1.pcm")
        t.start()

nls.enableTrace(True)
multiruntest(1)

```