知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!
您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >
微信小程序?qū)崿F(xiàn)語音錄制,上傳,播放
發(fā)表時間:2021-1-5
發(fā)布人:葵宇科技
瀏覽次數(shù):164
記錄技術(shù),分享技術(shù),做個偉大的搬運工。
框架選用開發(fā)微信小程序,使用的是unapp。 為什么要選用這個,因為他比較成熟,之前用過mpvue,kbone都是特別的不太成熟。后來經(jīng)過各種選型選定了uniapp。
遇到的問題
- 錄音授權(quán)。
- 長按錄音,判斷手指是否劃出長按的區(qū)域
- 文件上傳。
- 多錄制語音播放。
初始化工作
- 定義全局錄音對象和audio對象,并且格式化自己想要的音頻格式
const recorderManager = uni.getRecorderManager(); // 創(chuàng)建錄音對象
const audioContext = wx.createInnerAudioContext(); // 創(chuàng)建audio對象
const options = {
duration: 600000, //指定錄音的時長,單位 ms,最大為10分鐘(600000),默認為1分鐘(60000)
sampleRate: 16000, //采樣率
numberOfChannels: 1, //錄音通道數(shù)
encodeBitRate: 96000, //編碼碼率
format: 'mp3', //音頻格式,有效值 aac/mp3 等
frameSize: 50 //指定幀大小,單位 KB
};
復(fù)制代碼
錄音授權(quán)
錄音收取主要從兩個方面考慮
- 申請授權(quán)用戶直接同意授權(quán)
- 用戶拒絕授權(quán)后,打開設(shè)置,用戶收到授權(quán)。
uni.authorize({
scope: 'scope.record',
success() {
// 用戶已經(jīng)同意授權(quán),可以進行錄音
},
fail() {
// 此處用戶授權(quán)失敗,需要打開設(shè)置,去手動授權(quán)。 在某些情況下openSetting無法打開
// 可以通過fail的方式,通過彈窗用戶打開設(shè)置。
uni.openSetting({
success: res => {
// 沒有授權(quán)的情況下,彈窗提示
if (!res.authSetting['scope.record']) {
//未設(shè)置錄音授權(quán)
uni.showModal({
title: '提示',
content: '您未授權(quán)錄音,功能將無法使用',
showCancel: false
});
} else {
// 第二次才成功授權(quán)
// 用戶已經(jīng)同意授權(quán),可以進行錄音
}
},
fail: function() {
uni.showModal({
title: '提示',
content: '您未授權(quán)錄音,功能將無法使用',
showCancel: false,
success: function(res) {
uni.openSetting();
}
});
}
});
}
});
復(fù)制代碼
官方api鏈接
接口調(diào)整鏈接
長按錄音 / 滑動區(qū)域 / 停止長按
uniapp中的方法
@longpress 長按(手指觸摸超過350ms)
@longtap 長按
@tap 點擊
@touchcancel 手指觸摸被打斷,如來電提醒,彈窗
@touchend 手指觸摸動作結(jié)束,如松開按鈕
@touchmove 手指觸摸后移動
@touchstart 手指觸摸動作開始
復(fù)制代碼
錄制操作
- 獲取當(dāng)前點擊元素距離頂部的距離
- 長按的同時,要開始計時,已經(jīng)授權(quán)的時候要開始錄制語音。
// 小程序中獲取當(dāng)前點擊元素的距離和其他的有所不同,以下是獲取的方法
const query = uni.createSelectorQuery().in(this);
query
.select('.record-button')
.boundingClientRect(data => {
// data 當(dāng)前元素的各個信息
})
.exec();
復(fù)制代碼
- 通過event獲取當(dāng)前各項信息
- 滑動超出的時候要進行停止錄音,并且要清空計時器。
- 滑回來的時候要繼續(xù)錄音,繼續(xù)定時器。
- 此處需要加個中間狀態(tài),通過監(jiān)聽來進行繼續(xù)錄制錄音和停止錄制語音
let touches = e.touches[0];
// 超出的時候
if (touches.pageY < this.reocrdLocation.top) {
clearInterval(this.timerInfo);
recorderManager.pause();
} else {
recorderManager.resume();
}
復(fù)制代碼
停止長按
- 判斷錄音時長太短的話,不進行上傳,
- 符合條件的進行上傳,并且清空定時器,停止錄制
recorderManager.stop();
// 監(jiān)聽停止事件
recorderManager.onStop(res => {
if (this.duration < 1) {
uni.showToast({
title: '錄制時間太短',
duration: 1000,
icon: 'none'
});
return;
}
// 符合條件的,推進數(shù)組。
this.voiceList.push({
size: res.fileSize, // 本地的進度
progress: -1,//-1 沒有上傳, -100 上傳失敗, 100 上傳成功, 0 ~ 100上傳中
path: res.tempFilePath, // 線上路徑
duration: this.duration // 錄音時長
});
// 核對上傳
this.checkUploadVoice();
});
clearInterval(this.timerInfo);
復(fù)制代碼
文件上傳
- 通過設(shè)置每個錄音的狀態(tài),來記錄各個狀態(tài)(-1 沒有上傳, -100 上傳失敗, 100 上傳成功, 0 ~ 100上傳中)。
- 上傳失敗可以實現(xiàn)重新上傳。所以上傳文件前,要進行核對文件(核對各個狀態(tài))。
let obj;
for (let i = 0; i < this.voiceList.length; i++) {
let item = this.voiceList[i];
if (item.progress == -1 || item.progress == -100) {
obj = await this.uploadFiles(item, i); // 等待文件上傳完成后,獲取信息
// 修改語音數(shù)組 通過set
this.$set(this.voiceList, i, {
name: item.name,
size: item.size,
progress: obj.progress,
path: obj.path, //
duration: item.duration,
nowPlay: false,
text: '',
translateStatus: false, // 此處記錄是否轉(zhuǎn)化為文字
});
this.duration = 0; // 文件上傳后,時間記錄要清0
}
}
// 上傳文件
uploadFiles(item, i) {
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: url, // 上傳圖片的地址
filePath: item.path, // 錄音后拿到的地址
name: 'file',
header: {
'Content-Type': 'multipart/form-data',
accept: 'application/json'
},
success: upRes => {
console.log(upRes);
let dataInfo = JSON.parse(upRes.data);
let { code, data } = dataInfo;
// 成功后要返回成功的信息
resolve({
path: data.fileUrl,
progress: 100
});
},
fail: function(err) {
// 上傳失敗的時候要記錄狀態(tài)
resolve({
path: '',
progress: -100
});
}
});
uploadTask.onProgressUpdate(res => {
// 此處獲取上傳的進度,并且實時展示
this.$set(this.voiceList, {
name: item.name,
size: item.size,
progress: res.progress,
path: item.path,
duration: item.duration
});
// console.log('上傳進度', res.progress);
// console.log('已經(jīng)上傳的數(shù)據(jù)長度', res.totalBytesSent);
// console.log(
// '預(yù)期需要上傳的數(shù)據(jù)總長度',
// res.totalBytesExpectedToSend
// );
});
});
},
復(fù)制代碼
多條錄音播放
- 播放的時候只保持一條正在播放(最主要的問題)
- 停止其他正在播放的語音
- 播放當(dāng)前點擊的語音
// 播放語音
async playVoice(item, index) {
uni.showLoading({
title: '錄音播放加載中'
});
// 同時點擊當(dāng)前的語音兩次,需要先把上一個停止到,再進行播放新的
if (item.nowPlay && this.nowPlayItem.nowPlay) {
this.stopVoice(item);
return;
}
// 兩條播放的語音不一樣, 停止上一條,改變播放的狀態(tài),然后播放當(dāng)前的
if (!item.nowPlay && this.nowPlayItem.nowPlay) {
let status = await this.stopVoice(item);
let obj = Object.assign({}, this.nowPlayItem.item, {
nowPlay: false
});
/**
// 記錄全局播放的音頻(停止上次點擊的音頻,播放新的點擊的音頻,兩次點擊的音頻不一樣)
nowPlayItem: {
index: -1, // index 為當(dāng)前播放的索引值
nowPlay: false, // 當(dāng)前是否有正在播放的語音
item: null
},
*/
this.$set(this.voiceList, this.nowPlayItem.index, obj);
}
audioContext.src = http://www.wxapp-union.com/item.path; // 播放的錄音地址
audioContext.play();
this.nowPlayItem.index = index;
this.nowPlayItem.item = item;
// 開始播放監(jiān)聽
audioContext.onPlay(res => {
uni.hideLoading();
console.log('play');
item.nowPlay = true;
this.nowPlayItem.nowPlay = true;
});
// 停止播放監(jiān)聽(當(dāng)前的播放是否停止)
audioContext.onPause(res => {
console.log('pause');
item.nowPlay = false;
this.nowPlayItem.nowPlay = false;
// 監(jiān)聽音頻,要和取消監(jiān)聽同時存在,
audioContext.offPlay();
audioContext.offPause();
audioContext.offStop();
audioContext.offEnded();
});
// 監(jiān)聽音頻自然播放至結(jié)束的事件,真機調(diào)試會存在問題,微信開發(fā)者工具這塊不會有問題
audioContext.onEnded(res => {
console.log('ended');
item.nowPlay = false;
this.nowPlayItem.nowPlay = false;
// 監(jiān)聽音頻,要和取消監(jiān)聽同時存在,
audioContext.offPlay();
audioContext.offPause();
audioContext.offStop();
audioContext.offEnded();
});
audioContext.onError(res => {
console.log('error');
// 播放音頻失敗的回調(diào)
console.log(res);
});
},
// 只有當(dāng)前的播放停止時,才進行下一個播放開始
stopVoice(item) {
return new Promise((resolve, reject) => {
audioContext.stop();
audioContext.onStop(res => {
// 播放音頻失敗的回調(diào)
this.nowPlayItem.nowPlay = false;
if (item) {
item.nowPlay = false;
}
audioContext.offPlay();
audioContext.offPause();
audioContext.offStop();
audioContext.offEnded();
resolve(true);
});
});
},
復(fù)制代碼
此處容易出錯的地方
- 音頻監(jiān)聽事件要和取消事件同時存在
- 改變語音播放狀態(tài)的時候,必須要等到上一條停止,才可以進行后續(xù)工作
總結(jié)
- 模擬器和真機的差別還是挺大的,真機上各個事件比模擬器會慢一點。
- 學(xué)海無涯,持之以恒。
相關(guān)案例查看更多
相關(guān)閱讀
- 云南網(wǎng)頁制作
- 小程序技術(shù)
- typescript
- 微信分銷
- 商標(biāo)
- 汽車報廢
- APP
- 云南小程序商城
- 昆明小程序代建
- 昆明小程序公司
- 云南網(wǎng)站建設(shè)
- 云南做網(wǎng)站
- 小程序定制開發(fā)
- 網(wǎng)絡(luò)公司排名
- 海南小程序制作公司
- 昆明軟件定制公司
- 迪慶小程序開發(fā)
- 模版消息
- 云南小程序代建
- 云南電商網(wǎng)站建設(shè)
- 云南小程序開發(fā)費用
- 網(wǎng)站搭建
- 安家微信小程序
- 排名
- 云南網(wǎng)站建設(shè)首選公司
- 報廢車管理
- 二叉樹
- 云南網(wǎng)站建設(shè)開發(fā)
- web教程
- 云南網(wǎng)站建設(shè)方法