天天看點

做一個電商直播App,跟上這波雙十一

又快到一年一度的雙十一了。淘寶直播一姐曾在去年雙十一,一個人賣出了3.3億的銷售額,創造了行業的銷售神話。近兩年,很多電商平台開始關注起直播互動電商,希望在直播中,也可以增加互動,例如在直播過程中,抛出限量優惠商品,實時發送搶購的消息給觀衆。于是我們做了一個簡單的Demo。

Demo大緻的整體想法如下:以視訊直播為主的互動模型基礎上,結合語音轉寫功能進行設計,為主播擺脫Windows端繁瑣操作,實作快速發題的功能。主播通過語音輸入題目(問答題,答案隻有是和否),确認後将題目文本發送給所有房間内的觀衆,觀衆收到題目後App主動彈框給觀衆選擇結果。

1.1 功能拆解:

  • 隻有主播有釋出題目入口。
  • 需要ASR(Automatic Speech Recognition-語音識别)功能,有online實時翻譯和本地offline翻譯兩個方案。
  • ASR結果需要主播确認。
  • ASR結果主播确認後需要通知給所有非主播使用者。
  • 非主播使用者收到題目資訊時需要主動彈窗,給使用者選擇結果。

1.2 方案确定:

  • 為了確定ASR的準确性選擇了online實時翻譯,通過比對最終選擇搜狗知音開放平台。
  • 題目資訊也是文本類型,可以借用群聊實時消息通道,給題目資訊前面加上特殊字元,非主播使用者收到消息時判斷是否是以特殊字元開始,如果是remove特殊字元并彈窗顯示題目資訊。特殊字元定義時可以考慮到擴充性,以後其它類似功能也可以通過該方案來實作。

2.1 視訊直播DEMO

一個簡單的視訊直播Demo按以下幾個步驟就可以實作了,可以找幾個Android裝置run一下看看效果,還是相當easy滴。

Step1 SDK內建

SDK還好支援maven依賴,在build.gradle的dependencies子產品中加一行就行:

dependencies {
...
implementation 'io.agora.rtc:full-sdk:2.8.1'
}
複制代碼
           

Step2 直播引擎建立

聲網SDK有個重要的類RtcEngine,負責直播功能管理,提供了上/下線、狀态監聽、音/視訊設定等比較豐富的Api,碰到問題時,首先查這個類就對了。建立引擎時APP_ID參數為聲網開發平台建立的應用id。

private RtcEngine mRtcEngine;
try {
    mRtcEngine = RtcEngine.create(context, LiveDefine.APP_ID,
mRtcEventHandler);
    mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
    mRtcEngine.enableAudio(); // 開啟音頻功能
    mRtcEngine.enableVideo(); // 開啟視訊功能
} catch (Exception e) {
    e.printStackTrace();
}
複制代碼
           

Step3 直播View關聯

角色有主播和觀衆區分,關聯View時有些許差別。ANCHOR_UID為主播使用者id,主播端關聯View時為自己的使用者id,觀衆端關聯view時為觀看的主播的使用者id。使用者系統需要應用自己管理,聲網SDK不提供使用者管理。

SurfaceView surface = RtcEngine.CreateRendererView(this);
// 主播端View關聯
mRtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
mRtcEngine.enableLocalAudio(true); // 主播端需要打開本地音頻
mRtcEngine.setupLocalVideo(new VideoCanvas(surface,
VideoCanvas.RENDER_MODE_HIDDEN, ANCHOR_UID)); // 主播端設定的是本地video
mRtcEngine.startPreview();  //主播需要開啟視訊預覽
 
// 觀衆端View關聯
mRtcEngine.setClientRole(Constants.CLIENT_ROLE_AUDIENCE);
mRtcEngine.enableLocalAudio(false); // 觀衆端不需要打開本地音頻
mRtcEngine.setupRemoteVideo(new VideoCanvas(surface,
VideoCanvas.RENDER_MODE_HIDDEN, ANCHOR_UID)); // 觀衆端設定的是遠端即主播video
複制代碼
           

Step4 加入房間

加入房間時第一個參數token為目前登入賬戶對應的token,應用自己管理,測試時可從傳空。第二個參數為頻道id,也是由應用自己管理的。第三個參數為頻道名稱。最後一個參數為目前登入的賬戶id

mRtcEngine.joinChannel("", CHANNEL_ID, "CHANNEL_NAME", uid);
複制代碼
           

Step5 離開房間

// 主播端離開
mRtcEngine.setupLocalVideo(null);
mRtcEngine.stopPreview();
mRtcEngine.leaveChannel();
// 觀衆端離開
mRtcEngine.setupRemoteVideo(null);
mRtcEngine.leaveChannel();
複制代碼
           

2.2 消息功能

直播房間消息功能可以說是相對基礎而簡單的了,我們選用的是聲網實時資訊SDK,這是一個獨立的工具類SDK,聲網将實時消息功能解耦出來,可以給各個場景提供消息支援。群聊實時消息可參考如下步驟:

Step1 依賴配置

dependencies {
...
implementation 'io.agora.rtm:rtm-sdk:1.0.1'
}
複制代碼
           

Step2 消息引擎建立

// APP_ID同視訊互動SDK保持一緻即可
private RtmClient mRtmClient;
mRtmClient = RtmClient.createInstance(context, LiveDefine.APP_ID, listener);
複制代碼
           

Step3 房間消息初始化

建立一個消息頻道前需要調一次登入操作,第一個參數為應用賬戶token,第二個參數為賬戶辨別。

mRtmClient.login("", userId,
new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        Log.d(TAG, "rtmClient login success");
    }
    @Override
    public void onFailure(ErrorInfo errorInfo) {
        Log.d(TAG, "rtmClient login fail : " + errorInfo);
    }
});
複制代碼
           

建立消息頻道,CHANNEL_ID是一個辨別,可以和直播頻道不一緻,但是建議保持一緻:

RtmChannel mRtmChannel;
 
RtmChannelListener rtmListener = new RtmChannelListener(){
    @Override
    public void onMessageReceived(RtmMessage var1, RtmChannelMember var2){
        // 收到消息,自己發送的消息也會有該方法回調,可以通過RtmChannelMember判斷發送消息的人是不是自己,如果是不處理本次消息即可。
    }
    
    @Override
    public void onMemberJoined(RtmChannelMember var1){
        // 有使用者加入,可用來做使用者上線消息處理
    }
 
    @Override
    public void onMemberLeft(RtmChannelMember var1){
          // 有使用者離開,可用來做使用者離線消息處理
    }
};
mRtmChannel = mRtmClient.createChannel(CHANNEL_ID,
rtmListener );;
複制代碼
           

Step4 發送消息

RtmMessage rtmMessage = mRtmClient.createMessage();
rtmMessage.setText(msg);
mRtmChannel.sendMessage(rtmMessage, callback);
複制代碼
           

Step5 退出消息頻道

可在退出直播房間時,調用該方法。

mRtmChannel.release();
複制代碼
           

2.3 線上語音翻譯

首先也是需要注冊賬戶并建立應用,詳見搜狗知音文檔中心,實作可參考如下步驟:

Step1 初始化

調用init方法初始化

// 以下資訊從知音平台申請獲得
private static final String BASE_URL = "api.zhiyin.sogou.com";
private static final String APP_ID = "";
private static final String APP_KEY = "";
private SogoSpeech mSogouSpeech;
private DefaultAudioSource mAudioSource;
private OnSogouAsrListener mListener;
 
public void init(Context context) {
    ZhiyinInitInfo.Builder builder = new ZhiyinInitInfo.Builder();
    ZhiyinInitInfo initInfo = builder.setBaseUrl(BASE_URL).setUuid(UUID).setAppid(APP_ID).setAppkey(APP_KEY).create();
    SogoSpeech.initZhiyinInfo(context, initInfo);
 
    SogoSpeechSettings settings = SogoSpeechSettings.shareInstance();
    settings.setProperty(SpeechConstants.Parameter.ASR_ONLINE_AUDIO_CODING_INT,
1);
    settings.setProperty(SpeechConstants.Parameter.ASR_ONLINE_VAD_ENABLE_BOOLEAN,
false); 
    settings.setProperty(SpeechConstants.Parameter.ASR_ONLINE_VAD_LONGMODE_BOOLEAN,
true); // 長時間ASR
    settings.setProperty(Parameter.ASR_ONLINE_LANGUAGE_STRING,
ASRLanguageCode.CHINESE); // 也支援英文ASR ASRLanguageCode.ENGLIS
 
    mSogouSpeech = new SogoSpeech(context);
    mSogouSpeech.registerListener(mSpeechEventListener);
 
    mAudioSource = new DefaultAudioSource(new AudioRecordDataProviderFactory(context));
    mAudioSource.addAudioSourceListener(mAudioSourceListener);
}
 
private EventListener mSpeechEventListener = new EventListener() {
    @Override
    public void onEvent(String eventName, String param, byte[] data, int offset, int length, Object extra) {
        if (TextUtils.equals(SpeechConstants.Message.MSG_ASR_ONLINE_LAST_RESULT,
eventName)) {
            if (null != mListener) {
                mListener.onSogouAsrResult(param);
            }
            stopTransform();
        }
    }
 
    @Override
    public void onError(String errorDomain, int errorCode, String errorDescription, Object extra) {
        // 9002 使用者主動取消
        if (9002 != errorCode && null != mListener) {
            mListener.onSogouAsrResult("");
        }
        stopTransform();
    }
};
 
private IAudioSourceListener mAudioSourceListener = new IAudioSourceListener() {
    @Override
    public void onBegin(IAudioSource iAudioSource) {
        Log.d(TAG, "AudioSource onBegin");
        mSogouSpeech.send(SpeechConstants.Command.ASR_ONLINE_START, "", null, 0, 0);
    }
 
    @Override
    public void onNewData(IAudioSource audioSource, Object dataArray, long packIndex, long sampleIndex, int flag) {
        final short[] data = (short[]) dataArray;
        mSogouSpeech.send(SpeechConstants.Command.ASR_ONLINE_RECOGIZE, "", data, (int) packIndex, 0);
    }
 
    @Override
    public void onEnd(IAudioSource audioSource, int status, Exception e, long sampleCount) {
        Log.d(TAG, "AudioSource onEnd");
        mSogouSpeech.send(SpeechConstants.Command.ASR_ONLINE_STOP, "", null, 0, 0);
    }
};
 
public interface OnSogouAsrListener {
    void onSogouAsrResult(String result);
}
           

Step2 開始語音識别

public void startTransform(OnSogouAsrListener listener) {
    mListener = listener;
    mSogouSpeech.send(SpeechConstants.Command.ASR_ONLINE_CREATE,
null, null, 0, 0);
    new Thread(mAudioSource, "audioRecordSource").start();
}
           

Step3 停止語音識别

正常情況下不需要調用該方法,在EventListener 回調中已經調用過該方法了,為了確定狀态正常也可以在退出房間時手動調用一次。

public void stopTransform() {
    mListener 
= null;
    if (null != mAudioSource) {
        mAudioSource.stop();
    }
}
           

最後秀一下Demo 實作的效果。

(1)主播端直播發題(語音轉文字):

做一個電商直播App,跟上這波雙十一

(2)觀衆端答題

做一個電商直播App,跟上這波雙十一

(3)主播端收獲答案

做一個電商直播App,跟上這波雙十一

今年年初我花一個月的時間收錄整理了一套知識體系,如果有想法深入的系統化的去學習的,可以私信我【安卓】,我會把我收錄整理的資料都送給大家,幫助大家更快的進階。

做一個電商直播App,跟上這波雙十一

繼續閱讀