微信開發之錄音上傳、下載、轉碼

wechat

原文是在我自己博客中,小夥伴也可以點閱讀原文進行跳轉查看,還有好聽的背景音樂噢~

    一年的時間裏,前前後後都在搞微信開發的相關模塊,這不前一陣子,公司又開了個新項目,其中有一個就是類似於微信朋友圈的功能(我也不知道爲啥要開發微信已有的功能啊,淚奔...),其中包含上傳圖片、錄音、視頻等,由於微信端上傳圖片和視頻這塊也是頭一遭做,圖片採用了微信的相關插件,視頻嘛用的是百度的webupload插件,感覺也相當不錯,採用了分片上傳技術。今天這篇就主要介紹一下,錄音的相關功能。


簡單說明

微信錄音這塊,其實面對這項功能的時候,不用我多說,都知道要先去看開發文檔,查閱相關資料等準備工作;我先貼個地址,免得看我這篇文檔的時候再去查找網頁:微信公衆號開發-微信JS-SDK說明文檔。進入到這個頁面找到第5小節,音頻接口這裏,就是本篇要說的東西了。

微信錄音分爲如下幾個接口(這裏歸納一下,文檔裏有,詳細內容自己去看吧):

  1. 開始錄音接口
  2. 停止錄音接口
  3. 監聽錄音自動停止接口
  4. 播放語音接口
  5. 暫停播放接口
  6. 停止播放接口
  7. 監聽語音播放完畢接口
  8. 上傳語音接口
  9. 下載語音接口

看到以上,是不是覺得蠻多的,配合起來使用才提供了這麼一個完整(好像也並不怎麼完整,沒有提供方便的轉碼及下載本地機制)的錄音功能。好話說在前頭:你弄完了當你再去看這塊代碼的時候,發現還真他孃的亂啊。。。所以,我寫這篇記錄的原因就在這裏了,狗頭.png

還有一個就是接口權限(一張圖片來表述,圖片來源微信文檔...):

接口權限

上傳代碼梳理

本章會以文字和代碼的形式進行梳理,過程應該會蠻多的,不過看完之後直接拿去使用,問題也應該不大,如是說道。

JS-SDK庫的使用步驟,這裏就不過多介紹了,文檔裏也有,也是簡單整理下幾個所需步驟吧:

  1. 綁定域名
  2. 引入JS文件
  3. config接口注入權限驗證配置
  4. ready接口處理成功驗證
  5. error接口處理失敗驗證

config事件

我們直接從注入API列表說起,config接口有如下幾個屬性(不知道屬性是否合適,姑且叫爲屬性吧),

/**
 * 微信jssdk調用接口初始化
 */
wx.config({
    debug: true, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
    appId: '', // 必填,公衆號的唯一標識
    timestamp: , // 必填,生成簽名的時間戳
    nonceStr: '', // 必填,生成簽名的隨機串
    signature: '',// 必填,簽名
    jsApiList: [
        'startRecord', // 錄音開始api
        'stopRecord',  // 錄音結束api
        'uploadVoice', // 上傳錄音api
        'onVoiceRecordEnd', // 超過一分鐘自動停止api
        'playVoice', // 播放錄音api
        'pauseVoice', // 暫停錄音api
        'onVoicePlayEnd', // 監聽語音播放完畢api
    ]
});

代碼中的jsApiList就是錄音功能所用到的所有接口了。其他幾個屬性的值,就不介紹如何生成的了,調用jssdk的類庫,通過公衆號的appid和secret就能獲取到。嗯...還是貼下這部分的代碼吧:

// 引入jssdk庫
require_once APPPATH . 'libraries/weixin/jssdk.php';
// 傳入appid和secret實例化jssdk類
$JsSdk = new JSSDK('wxa318c6979e231ffa', '301d8f04a0f2ba3098135a162165c991');
// 得到相關時間戳和隨機字符串
$data['signPackage'] = $JsSdk->getSignPackage();
// 獲取當前頁面url
$data['signPackage']['url'] = explode('?', $data['signPackage']['url'])[0];

注意:調用JSSDK類的時候,會在項目根目錄下生成兩個文件access_token.phpjsapi_ticket.php,裏面放的是過期時間和token、ticket值。

ready事件

ready註冊錄音播放結束監聽事件:

wx.ready(function(){
    // 監聽事件一開始就加載
    wx.onVoicePlayEnd({
        success: function (res) {
            layer.msg('播放完畢'); // 這裏用了layer彈框
        }
    });
});

錄音事件

本小節主要是關於錄音事件的介紹,代碼行中的註釋應該寫的很清楚,不清楚的留言問吧:

// 聲明一個錄音數組 以存放錄音臨時ID
var voice = {
    localId: []
};

// 手指按下錄音鍵
$('#micb').on('touchstart', function(event){
    // 取消事件的默認動作
    event.preventDefault();
    // 賦值當前的錄音開始時間戳到全局變量
    START = new Date().getTime();

    recordTimer = setTimeout(function(){
        // 錄音開始
        wx.startRecord({
            success: function(){
                // 錄音不能超過一分鐘 超過一分鐘自動停止 並觸發該事件
                wx.onVoiceRecordEnd({
                    // 錄音時間超過一分鐘沒有停止的時候會執行 complete 回調
                    complete: function (res) {
                        // 給出提示
                        layer.msg('最多隻能錄製一分鐘', {icon:2, time:1000});
                        // 記錄錄音的臨時ID
                        voice.localId = res.localId;
                        uploadVoice();
                    }
                });
            },
            cancel: function () {
                alert('用戶拒絕授權錄音');
            }
        });
    },300);
});

// 鬆手結束錄音
$('#micb').on('touchend', function(event){
    event.preventDefault();
    // 獲取錄音停止時間戳
    END = new Date().getTime();
    // 獲取錄音總時長
    duration = END - START;
    // 如果小於300ms則視爲時間太短 拋出提示
    if(duration < 300){
        END   = 0;
        START = 0;
        layer.msg('時間太短', {icon:2, time:1000});
        //小於300ms,不錄音
        clearTimeout(recordTimer);
    }else{
        wx.stopRecord({
          success: function (res) {
            voice.localId = res.localId;
            // 上傳錄音
            uploadVoice();
          },
          fail: function (res) {
            alert(JSON.stringify(res));
          }
        });
    }
});

// 上傳錄音
function uploadVoice() {
    // 調用微信的上傳錄音接口把本地錄音先上傳到微信的服務器
    // 不過,微信只保留3天,而我們需要長期保存,我們需要把資源從微信服務器下載到自己的服務器
    wx.uploadVoice({
        localId: voice.localId, // 需要上傳的音頻的本地ID,由stopRecord接口獲得
        isShowProgressTips: 1, // 默認爲1,顯示進度提示
        success: function (res) {
            // 把錄音在微信服務器上的id(res.serverId)發送到自己的服務器供下載。
            $.ajax({
                url: 'down_file.php',
                type: 'post',
                data: {serverId: res.serverId},
                dataType: "json",
                success: function (data) {
                    if(data.status == 200) {
                        layer.msg('語音保存成功', {icon:1, time:2000});
                    }
                },
                error: function (xhr, errorType, error) {
                    console.log(error);
                }
            });
        }
    });
}

/**
 * 播放音頻
 */
function playVoice()
{
    wx.playVoice({
        localId: voice.localId // 需要播放的音頻的本地ID,由stopRecord接口獲得
    })
}

以上就是微信錄音在前端的JS代碼,接下來說明服務器(PHP)端下載錄音到本地的代碼,下載代碼具體在download_media()方法中,其他都是一些輔助方法:

下載

<?php

class Wechat
{
    /**
     * 獲取微信access_token
     * @return string access_token
     */
    public function getWechatAccessToken()
    {
        $token_url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential';
        $appid     = 'appid';
        $secret    = 'secret';
        $get_token_url = $token_url . '&appid=' . $appid . '&secret=' . $secret;
        $res           = file_get_contents ( $get_token_url );
        $res_arr       = json_decode ( $res, true ); 

        if($res_arr['access_token']) return $res_arr['access_token'];
        return false;
    }

    /**
     * 生成毫秒級時間戳
     */
    public function msectime()
    {
       list($msec, $sec) = explode(' ', microtime());
       return (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
    }


    /**
     * 隨機取出字符串
     * @param  int $strlen 字符串位數
     * @return string      
     */
    public function salt($strlen)
    {
        $str  = "abcdefghkmnprstuvwxyzABCDEFGHKMNPRSTUVWXYZ23456789";
        $salt = '';
        $_len = strlen($str)-1;
        for ($i = 0; $i < $strlen; $i++) {
            $salt .= $str[mt_rand(0,$_len)];
        }
        return $salt;
    }

    /**
     * 下載微信素材資源到本地
     * @param  url $url  素材地址
     * @return json       
     */
    public function download_media()
    {
        // 獲取微信服務器的錄音ID
        $media_id = $this->input->post('serverId');
        if ($media_id) {
            // 獲取access_token
            $access_tokens = $this->getWechatAccessToken();
            
            // 下載素材接口
            $down_media_url   = 'https://api.weixin.qq.com/cgi-bin/media/get';
            /**
             * 根據access_tokens獲取素材
             */
            $get_media_url = $down_media_url . '?access_token=' . $access_tokens . '&media_id=' . $media_id;

            // 獲取文件流
            $file_flow = file_get_contents($get_media_url);

            // 本地保存目錄
            $save_path = "resource/uploads/";

            if( !is_dir($save_path) ) {
                mkdir(iconv('UTF-8', 'GBK', $save_path), 0777, TRUE);
            }

            // 生成文件名
            $filename = $this->msectime() . $this->salt(6) . '.amr';

            // 寫入文件流到本地
            $flag     = file_put_contents($save_path . '/' . $filename, $file_flow);

            unset($file_flow);
            if($flag !== FALSE) {
                return $save_path . '/' . $filename;
            }else {
                return FALSE;
            }
        }
    }
}

由於微信保存錄音的格式.amr,所以下載的時候只能下載amr格式的音頻,強行下載成MP3格式的話,播放可能會出現一些問題,接下來就說下轉碼的幾種方式;

轉碼

第三方工具 FFmpeg

FFmpeg介紹

FFmpeg是一套可以用來記錄、轉換數字音頻、視頻,並能將其轉化爲流的開源計算機程序。FFmpeg在Linux平臺下開發,但它同樣也可以在其它操作系統環境中編譯運行,包括Windows、Mac OS X等。———來自百度的介紹。

下載

通過這個網址下載ffmpeg.exe程序 https://ffmpeg.zeranoe.com/bu...,選擇shared這個類型,如下圖:
捕獲.PNG

下載完成後,解壓在bin目錄可以看到ffmpeg.exe

ffmpeg.exe.PNG

轉碼

cmd命令行轉碼:
直接切換到ffmpeg.exe的目錄,在命令行輸入

ffmpeg.exe -i E:\wode\ffmpeg\amr.amr E:\wode\ffmpeg\arm.mp3

即可,就可以看到整個轉碼的過程。下圖所示:
cmd轉碼.PNG

php轉碼:
那麼如何利用php來調用exe軟件來進行轉碼呢?很方便的是php提供了相應的函數,execsystem,他們都可以調用cmd的命令,比如調用ffmpeg.exe來進行轉碼:

exec("E:\\wode\\ffmpeg\\bin\\ffmpeg.exe -i E:\\wode\\ffmpeg\\amr.amr E:\\wode\\ffmpeg\\exec.mp3");

就是這麼簡單了。當然ffmpeg也支持其他格式的轉碼,音頻、視頻等都可以。

PS:會把測試的amr文件貼在下面的資源節裏,有需要的小夥伴可以下載測試,因爲現在的amr格式的文件都挺難找的,別問我怎麼知道的....

第三方平臺 七牛雲

除了通過php外部命令調用軟件進行轉碼之外,還可以通過第三方平臺實現轉碼操作,這裏就舉例七牛雲,首先貼兩個鏈接:

  1. 七牛開發者SDK列表
  2. 七牛文件上傳說明

上面的的一個鏈接裏顯示的是七牛官方所有的SDK文檔列表,可以根據後端語言的不同進行選擇查看;第二個鏈接就是本小節要說的利用七牛雲上傳文件。下面來瞧一下代碼,也同樣封裝成類的形式:

<?php
use Qiniu\Auth;
use Qiniu\Storage\UploadManager;
use Qiniu\Storage\BucketManager;

class uploadQiniu
{
    public $qiniu = [
        'AccessKey'      => '', // 配置七牛AccessKey
        'SecretKey'      => '', // 配置七牛SecretKey
        'bucket'         => 'cxiansheng', // 七牛的存儲空間名,我的是cxiansheng
        'voice-pipeline' => 'cxiansheng', // 設置轉碼隊列名
        'voice-domain'   => 'http://***.com/' // 你的CDN加速域名 上傳文件成功後通過這個域名+文件名就可以訪問到相應的資源
    ];

    /**
     * 上傳微信錄音文件到七牛並轉碼mp3
     * @param  string $trans_ext  本地文件路徑
     */
    public function upload_qiniu($file_path)
    {
        // 獲取七牛auth對象
        $auth = new Auth($this->qiniu['AccessKey'], $this->qiniu['SecretKey']);

        // 定義轉碼後的mp3文件名
        $qiniu_filename = 'qiniu' . $this->msectime() . $this->salt(6) . '.mp3';

        // 指定上傳文件成功後的後續處理 這裏爲轉碼操作
        $savekey = \Qiniu\base64_urlSafeEncode($this->qiniu['bucket'] . ":" . $qiniu_filename);
        $fops    = 'avthumb/mp3/ab/128k/ar/44100/acodec/libmp3lame|saveas/' . $savekey;
        /**
         * 設置轉碼格式和轉碼隊列名
         */
        $policy   = [
            'persistentOps'      => $fops,
            'persistentPipeline' => $this->qiniu['voice-pipeline']
        ];
        /**
         * 設置上傳到七牛的原始amr臨時文件名
         * @var string
         */
        $qiniu_tmp_filename = 'originamrtmp.amr';

        // 獲取上傳token
        $uptoken = $auth->uploadToken($this->qiniu['bucket'], null, 3600, $policy);

        // 調用上傳類
        $uploadMgr = new UploadManager();
        // 調用 UploadManager 的 putFile 方法進行文件的上傳。
        list($ret, $err) = $uploadMgr->putFile($uptoken, $qiniu_tmp_filename, $file_path);

        // 資源管理類
        $bucketMgr = new BucketManager($auth);
        if($ret['key']) {
            // 刪除原始amr臨時文件
            $err = $bucketMgr->delete($this->qiniu['bucket'], $ret['key']);
            unlink($file_path); //刪除服務器上的amr文件

            // 返回在七牛上的資源路徑
            return $this->qiniu['voice-domain'] . $qiniu_filename;
        }else {
            return FALSE;
        }
    }
}

上面的代碼應該不用我做過多介紹,裏面的註釋每一步應該都寫得很清楚。

PS:在通過第三方轉碼的時候,調用api成功之後,由於要待轉碼的文件一般都會處於轉碼隊列中,可能還沒有立即轉碼成功我們想要的文件。所以不能根據轉碼過後的文件名去下載,需要等待一會兒,或者可以先把轉碼後的文件名保存在數據庫中,用定時任務去下載到本地。具體請看我在SF提問裏的回答--下載七牛雲mp3文件間歇性失敗

總結

至此,在微信開發中關於錄音這一塊兒的功能,就已經介紹完畢。如果有寫錯的地方,歡迎拍磚。同樣看完還不是很理解的朋友,也可以留言。
以上。

資源

  1. composer安裝PHP-FFmpeg
  2. ffmpeg-php擴展
  3. 微信jssdk錄音功能開發記錄
  4. amr格式文件

其他另外兩篇自己關於微信開發的總結推薦:

  1. 微信開發之微信公衆號支付
  2. 微信開發之微信登錄
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章