javascript原生移动云编程12 - 如何用手机录音和播放

用javascript在码实云平台上,可以在云里编写原生的移动应用。移动应用有时需要像微信那样用手机录音,把语音上传到云存储里,并且在应用里可以点击播放。这个功能码实平台提供了全套的实现,而实现的方式和手机的相机调用非常相似,也是把语音当做一个多媒体附件来处理。因此,如果你先熟悉下相机拍照那个教程的代码,对理解本应用实例会有很大的帮助。

本实例的代码里,有较多部分是用于录音播放的UI和控制。createRow函数比其他数据相关的教程里略长,Mash5.Tenant.File.SoundPlayer.create是码实平台SDK创建音频播放器的调用。事先用Mash5.Tenant.File.download从云存储里获取音频录音文件。代码里把页面的右上角按钮定制为加号的发布按钮,按钮的事件处理调用了Mash5.Tenant.File.uploadFromRecorder来录制语音。

Class.create(Mash5.Widget, {
    playImage: undefined,
    stopImage: undefined,
    
	initialize : function () {
	    var context = this.getContext();
	    
	    //获取播发图标
	    context.getResource({
		    id: "540920870cf2720cf9aa3fac",
		    callback: function(file) {
		        this.playImage = file;
		    }.bind(this)
		});
		//获取停止图标
	    context.getResource({
		    id: "540920870cf2720cf9aa3fae",
		    callback: function(file) {
		        this.stopImage = file;
		    }.bind(this)
		});

        //设置导航条右按钮为创建功能
		this.getCurrentPage().setRightNavButton({
			style: Mash5.UI.NavigationButtonStyle.ADD,
			listener: function () {
			    //创建参数
				var parameters = this.createAddParameters();
                Mash5.Tenant.File.uploadFromRecorder({
                    context: context,
                    onprogresschanged: parameters.onprogresschanged,//上传进度回调
                    setCancelListener: parameters.setCancelListener//设置取消的回调
                },
                parameters.onload);
			}.bind(this),
		});
		
		this.render();
	},

	render: function() {
	    var context = this.getContext();
	    
	    var container = Ti.UI.createView({
			width: Ti.UI.FILL,
			height: Ti.UI.FILL,
			layout:'vertical'
		});
		this.setContentView(container);
		
		var tipLabel = Ti.UI.createLabel({
			width: Ti.UI.FILL,
			height: Ti.UI.FILL,
			font: {
				fontSize: '16dip',
				fontFamily: 'Helvetica Neue'
			},
			color: '#404040',
			textAlign: 'center',
			text: '正在获取数据...'
		});
		container.add(tipLabel);
		
		//查询数据
		var params = {
			'method.name': 'mash5.task.queryFeeds',
			'method.version': 'Titanium',
			'method.optimize': 'fetchOne',
			'method.optimize.includeField.fieldName': '$format$' + JSON.stringify(['_id', 'name', 'Positions']),
			'page.nextTime': '9999999999999',
			'page.perPageSize': 1000,
			'query.bo.nameSpace': 'dev.bo.basic.luyinjiaocheng_1409883815008'
		};
		Mash5.Network.executeHTTPClientForAllResult(context, params, function (result) {
			var feeds = result.object && result.object.nextData;
			if (feeds.length > 0) {
			    //查询到录音
			    //去掉提示的View
				container.remove(tipLabel);
				//显示所有录音
				var tableView = Ti.UI.createTableView({
					width : Ti.UI.FILL,
					height : Ti.UI.FILL
				});
				container.add(tableView);
				var rows = [];
				for (var i = 0, len = feeds.length; i < len; i++) {
					var row = this.createRow(feeds[i]);
					rows.push(row);
				}
				tableView.setData(rows);
			} else {
				tipLabel.text = '没有数据';
			}
		}.bind(this));
	},
	
	createAddParameters: function() {
        var progressDialog = Mash5.UI.createProgressDialog();
        progressDialog.setProgress(0, "正在上传录音...");
        return {
            onprogresschanged: function(progress) {
                progressDialog.show();
                progressDialog.setProgress(progress, "正在上传录音...")
            },
            setCancelListener: function(listener) {
                progressDialog.setCancelListener(listener)
            },
            onload: function(r) {
                progressDialog.hide();
                setTimeout(function() {
                    progressDialog.hide()
                },
                600);
                if (r.success) {
                    var fileInfo = r.fileInfo;
                    this.addFeed(fileInfo);
                } else {
                    alert(r.message);
                }
            }.bind(this)
        }
    },
    addFeed: function(fileInfo) {
        var context = this.getContext();
        // 获取数据格式模板
        context.getBO({
			nameSpace: 'dev.bo.basic.luyinjiaocheng_1409883815008',
			callback: function (bo) {
                if(bo) {
                    bo.Fields[0].Value = fileInfo;
                    // 发布数据
                    var params = {
        				'method.name' : 'mash5.task.addFeed',
        				'method.version' : 'Titanium"',
        				'method.optimize' : 'fetchOne',
        				'method.optimize.includeField.fieldName' : '$format$' + JSON.stringify(['_id', 'name', 'Positions']),
        				'insert.appId' : context.getCurrentAppId(),
        				'insert.bo' : JSON.stringify(bo)
        			};
       			
        		Mash5.Network.executeHTTPClientForAllResult(context, params, function (result) {
        				if (!result.success || !result.object) {
        					alert('发布信息失败。');
        					return;
        				}
        				this.render();
        			}.bind(this));
                }
			}.bind(this)
		});
    },
    
    //显示一个录音文件
	createRow: function (feed) {
	    var context = this.getContext();
	    // 录音文件信息
	    var fileInfo = feed.bo.Fields[0].Value;

		var row = Ti.UI.createTableViewRow({
			width: '100%',
			height: Ti.UI.SIZE,
			selectionStyle : 0,
		});

        var container = Ti.UI.createView({
			width: Ti.UI.FILL,
			height: '60dip'
		});
		row.add(container);
				
		var horizontal = Ti.UI.createView({
			width: '90dip',
			height: '40dip',
			top: '10dip',
			left: '20dip',
			borderRadius: '5dip',
			borderWidth: '1.5dip',
			borderColor: '#c8d3d6'
		});
		// 播放按钮
		var playAndStopBtn = Ti.UI.createImageView({
			width: '30dip',
			height: '30dip',
			top: '5dip',
			left: '5dip',
			bubbleParent: false,
			canScale: false
		});
		if (!this.playImage) {
		     context.getResource({
    		    id: "540920870cf2720cf9aa3fac",
    		    callback: function(file) {
    		        this.playImage = file;
    		        playAndStopBtn.setImage(this.playImage);
    		    }.bind(this)
    		});
		} else {
		     playAndStopBtn.setImage(this.playImage);
		}
		
		horizontal.add(playAndStopBtn);
		// 时间显示
		var timeLabel = Ti.UI.createLabel({
			width: Ti.UI.SIZE,
			height: '30dip',
			font: {fontSize: '14dip'},
			color: '#000',
			top: '5dip',
			left: '40dip',
			text: '00:00'
		});
		var duration = fileInfo.milliSecond ? fileInfo.milliSecond: 0;
		timeLabel.setText(this.durationToString(duration));
		horizontal.add(timeLabel);
		
		var isPlay = false,
		player,
		timer;
		//播放按钮点击事件
		container.addEventListener('click', function () {
		    var context = this.getContext();
			if (!isPlay) {
				isPlay = true;
				// 调用SDK下载音频文件
				Mash5.Tenant.File.download({
					context: context,
					fileInfo: fileInfo,
					onprogresschanged: function(progress) {
					    //下载进度的事件progress是进度,取值范围ie0-1。
						if (!Mash5.UI.activityIndicator.isShow()) {
							Mash5.UI.activityIndicator.showModal('正在下载录音文件...');
						}
				Mash5.UI.activityIndicator.setMessage(Mash5.string.get('正在下载录音文件...') + Math.floor(progress * 100) + '%');
					}
				}, function(r) {
					Mash5.UI.activityIndicator.hideModal();
					if (r.success) {	
					    //调用SDK的音频播放创建播放对象。
						player = Mash5.Tenant.File.SoundPlayer.create(r.file);
						if (player) {
						    //计时器,显示播放进度。
							timer = setInterval(function () {
								duration -= 1000;
								if (duration < 0) {
									duration = 0;
								}
							timeLabel.setText(this.durationToString(duration));
							}.bind(this), 1000);
							//播放按钮变成停止
							if (!this.stopImage) {
                    		     context.getResource({
                        		    id: "540920870cf2720cf9aa3fae",
                        		    callback: function(file) {
                        		        this.stopImage = file;
                        		       playAndStopBtn.setImage(this.stopImage);
                        		    }.bind(this)
                        		});
                    		} else {
                    		    playAndStopBtn.setImage(this.stopImage);
                    		}
							// 调用播放方法
							player.play();
							// 播放完的事件处理
							player.addEventListener('complete', function () {
								clearInterval(timer);
								timer = null;
								//播放完清理播放对象
								player.release();
								player = null;
								//播放完,按钮恢复播放的样式
								if (!this.playImage) {
                        		     context.getResource({
                            		    id: "540920870cf2720cf9aa3fac",
                            		    callback: function(file) {
                            		        this.playImage = file;
                            		      playAndStopBtn.setImage(this.playImage);
                            		    }.bind(this)
                            		});
                        		} else {                        		 playAndStopBtn.setImage(this.playImage);
                        		}
								duration = fileInfo.milliSecond ? fileInfo.milliSecond: 0;
							timeLabel.setText(this.durationToString(duration));
								isPlay = false;
							}.bind(this));
						}
					}
				}.bind(this));
			} else {
				if (!player) return;
				 //调用停止播放的方法
				player.stop();
				//清理播放对象
				player.release();
				player = null;
				if (timer) {
					clearInterval(timer);
					timer = null;
				}
				if (!this.playImage) {
        		     context.getResource({
            		    id: "540920870cf2720cf9aa3fac",
            		    callback: function(file) {
            		        this.playImage = file;
            		        playAndStopBtn.setImage(this.playImage);
            		    }.bind(this)
            		});
        		} else {
        		    playAndStopBtn.setImage(this.playImage);
        		}
				duration = fileInfo.milliSecond ? fileInfo.milliSecond: 0;
				timeLabel.setText(this.durationToString(duration));
				isPlay = false;
			}
		}.bind(this));
		container.add(horizontal);
		return row;
	},
	
	//毫秒数转成"分钟:秒"的格式的文本
	durationToString: function(duration) {
	    if (duration) {
			var minutes,
			seconds;
			if (duration >= 60000) {
				minutes = Math.floor(duration / 60000);
				if (minutes <= 9) {
					minutes = '0' + minutes.toString();
				}
			} else {
				minutes = '00';
			}
			seconds = Math.floor(duration / 1000) % 60;
			if (seconds <= 9) {
				seconds = '0' + seconds.toString();
			}
			return minutes.toString() + ':' + seconds.toString();
		} else {
			return '00:00';
		}
	}
})


Html5网页纯JavaScript录制MP3音频 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Html5网页JavaScript录制MP3音频</title> <meta charset="utf-8" /> </head> <body> Html5网页JavaScript录制MP3音频 录制 停止 上传 调试信息: [removed][removed] [removed] var recorder = new MP3Recorder({ debug:true, funOk: function () { btnStart.disabled = false; log('初始化成功'); }, funCancel: function (msg) { log(msg); recorder = null; } }); var mp3Blob; function funStart(button) { btnStart.disabled = true; btnStop.disabled = false; btnUpload.disabled = true; log('录音开始...'); recorder.start(); } function funStop(button) { recorder.stop(); btnStart.disabled = false; btnStop.disabled = true; btnUpload.disabled = false; log('录音结束,MP3导出中...'); recorder.getMp3Blob(function (blob) { log('MP3导出成功'); mp3Blob = blob; var url = URL.createObjectURL(mp3Blob); var div = document.createElement('div'); var au = document.createElement('audio'); var hf = document.createElement('a'); au.controls = true; au.src = url; hf.href = url; hf.download = new Date().toISOString() + '.mp3'; hf[removed] = hf.download; div.appendChild(au); div.appendChild(hf); recordingslist.appendChild(div); }); } function log(str) { recordingslist[removed] += str + ''; } function funUpload() { var fd = new FormData(); var mp3Name = encodeURIComponent('audio_recording_' + new Date().getTime() + '.mp3'); fd.append('mp3Name', mp3Name); fd.append('file', mp3Blob); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { recordingslist[removed] += '上传成功:' + mp3Name + ''; } }; xhr.open('POST', 'upload.ashx'); xhr.send(fd); } [removed] </body> </html> [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 (function (exports) { var MP3Recorder = function (config) { var recorder = this; config = config || {}; config.sampleRate = config.sampleRate || 44100; config.bitRate = config.bitRate || 128; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; if (navigator.getUserMedia) { navigator.getUserMedia({ audio: true }, function (stream) { var context = new AudioContext(), microphone = context.createMediaStreamSource(stream), processor = context.createScriptProcessor(16384, 1, 1),//bufferSize大小,输入channel数,输出channel数 mp3ReceiveSuccess, currentErrorCallback; config.sampleRate = context.sampleRate; processor.onaudioprocess = function (event) { //边录音边转换 var array = event.inputBuffer.getChannelData(0); realTimeWorker.postMessage({ cmd: 'encode', buf: array }); }; var realTimeWorker = new Worker('js/worker-realtime.js'); realTimeWorker.onmessage = function (e) { switch (e.data.cmd) { case 'init': log('初始化成功'); if (config.funOk) { config.funOk(); } break; case 'end': log('MP3大小:', e.data.buf.length); if (mp3ReceiveSuccess) { mp3ReceiveSuccess(new Blob(e.data.buf, { type: 'audio/mp3' })); } break; case 'error': log('错误信息:' + e.data.error); if (currentErrorCallback) { currentErrorCallback(e.data.error); } break; default: log('未知信息:', e.data); } }; recorder.getMp3Blob = function (onSuccess, onError) { currentErrorCallback = onError; mp3ReceiveSuccess = onSuccess; realTimeWorker.postMessage({ cmd: 'finish' }); }; recorder.start = function () { if (processor && microphone) { microphone.connect(processor); processor.connect(context.destination); log('开始录音'); } } recorder.stop = function () { if (processor && microphone) { microphone.disconnect(); processor.disconnect(); log('录音结束'); } } realTimeWorker.postMessage({ cmd: 'init', config: { sampleRate: config.sampleRate, bitRate: config.bitRate } }); }, function (error) { var msg; switch (error.code || error.name) { case 'PERMISSION_DENIED': case 'PermissionDeniedError': msg = '用户拒绝访问麦客风'; break; case 'NOT_SUPPORTED_ERROR': case 'NotSupportedError': msg = '浏览器不支持麦客风'; break; case 'MANDATORY_UNSATISFIED_ERROR': case 'MandatoryUnsatisfiedError': msg = '找不到麦客风设备'; break; default: msg = '无法打开麦克风,异常信息:' + (error.code || error.name); break; } if (config.funCancel) { config.funCancel(msg); } }); } else { if (config.funCancel) { config.funCancel('当前浏览器不支持录音功能'); } } function log(str) { if (config.debug) { console.log(str); } } } exports.MP3Recorder = MP3Recorder; })(window);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值