• WebAPI之访问连接媒体输入设备



    提示:以下是本篇文章正文内容,Java系列学习将会持续更新

    一、Web API 接口文档

    1.Navigator 接口表示用户代理的状态和标识。它允许脚本查询它和注册自己进行一些活动。
    Navigator

    2.mediaDevices 是 Navigator 只读属性,返回一个 MediaDevices 对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享。
    Navigator.mediaDevices

    3.MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可,媒体输入会产生一个媒体流(MediaStream),里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道、一个音频轨道,也可能是其它轨道类型。
    MediaDevices.getUserMedia()

    语法:

    // 指定请求的媒体类型(音频、视频)
    var constraints = { audio: true, video: true };
    // 它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象
    var promise = navigator.mediaDevices.getUserMedia(constraints);
    
    • 1
    • 2
    • 3
    • 4

    4.Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。
    使用 Promise

    语法:

    // 绑定回调函数
    promise.then(成功时调用的函数)
    	   .catch(失败时调用的函数)
    
    • 1
    • 2
    • 3

    5.MediaRecorder 是 MediaStream Recording API 提供的用来进行媒体轻松录制的接口,他需要通过调用 MediaRecorder() 构造方法进行实例化。
    MediaRecorder

    事件处理:

    // 该事件可用于获取录制的媒体资源
    MediaRecorder.ondataavailable
    // 用来处理 start 事件,该事件在媒体开始录制时触发
    MediaRecorder.onstart
    // 用来处理 stop 事件,该事件会在媒体录制结束时
    MediaRecorder.onstop
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    回到目录…

    二、采集音频

    2-1 record.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用户中心title>
    head>
    <body>
        <input type="text" id="title">
        <button id="stop">停止录制button>
        
        <audio controls>audio>
        <script src="./js/record.js">script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2-2 record.js

    // 发送 Ajax 请求
    function upload(title, content) {
        var xhr = new XMLHttpRequest()
        // 由于我们要把声音放在请求体中发送,所以必须使用 post 方法
        // 这里是 ajax 发起的请求,所以,后续要怎么处理完全是 js 决定的
        // 所以,这里就不使用 *.do 这种 URL 了
        xhr.open('post', `/studio/track/record.json?title=${title}`)
        xhr.onload = function() {
            console.log(this.status)
            console.log(this.responseText)
        }
        xhr.send(content)
    }
    
    // 为了让 js 代码可以在所有资源都加载完成后才去执行,就入口代码放在 window 的 load 事件处理中
    window.onload = function() {
        // 执行这个方法的时候,说明所有资源都被加载好了
    
        if(!navigator.mediaDevices.getUserMedia) {
            alert("该浏览器不支持媒体访问,请更换浏览器!")
            return
        }
    
        var constraints = { audio: true }
        var promise = navigator.mediaDevices.getUserMedia(constraints)
    
        // stream 的类型就是 MediaStream (媒体流)
        // 里面有从麦克风采集到的声音
        function onSuccess(stream) {
            alert('用户授权成功')
    
            var mediaRecorder = new MediaRecorder(stream)
            // 当开始录制后,这个方法会被调用
            mediaRecorder.onstart = function () {
                console.log('开始录制')
            }
    
            // 放置过程中录制下来的声音数据
            var data = []
            // 当数据可用时,会被调用
            mediaRecorder.ondataavailable = function(evt) {
                console.log('数据可用')
                console.log(evt)
                // evt.data 是一个 Blob 类型的,表示录制下来的声音片段的对象
                data.push(evt.data)
            }
            // 当停止录制后(一切完成),这个方法会被调用
            mediaRecorder.onstop = function() {
                console.log('停止录制')
                console.log(data)
                // 将一组数据,组成一个统一的数据
                var title = document.querySelector('#title').value.trim()
                var type = "audio/ogg; codecs=opus"
                var blob = new Blob(data, {
                    // 类型认为是死规定
                    type: type
                })
                // 将数据生成一个方便播放的 URL
                var url = URL.createObjectURL(blob)
                console.log(url)
    
                // 找到 audio 元素,修改 src 属性,让页面上的
                // 音频播放器可以播放我们录制下来的声音
                var oAudio = document.querySelector('audio')
                oAudio.src = url
    
                upload(title, blob)
            }
    
            document.querySelector('#stop').onclick = function() {
                mediaRecorder.stop()
            }
    
            // 开始录制,每1s生成一次数据
            mediaRecorder.start(1000)
        }
    
        function onError(error) {
            alert('授权过程中出现了错误: ' + error)
        }
    
        promise.then(onSuccess).catch(onError)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    回到目录…

    2-3 后端响应

    ObjectMapper使用详细介绍

    @WebServlet("/studio/track/record.json")
    public class RecordJsonServlet extends HttpServlet {
        private final ObjectMapper objectMapper = new ObjectMapper();
        private final TrackRepo trackRepo = new TrackRepo();
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            String title = req.getParameter("title");
            String type = req.getHeader("Content-Type");
            Log.println("title: " + title);
            Log.println("type: " + type);
    
            UserVO currentUser = null;
            HttpSession session = req.getSession(false);
            if (session != null) {
                currentUser = (UserVO) session.getAttribute("currentUser");
            }
    
    
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("application/json");
            PrintWriter writer = resp.getWriter();
            if (currentUser == null) {
                Log.println("用户未登录");
                HashMap<String, Boolean> result = new HashMap<>();
                result.put("result", false);
                String json = objectMapper.writeValueAsString(result);
                Log.println(json);
                writer.println(json);
                return;
            }
    
            trackRepo.insert(currentUser.uid, title, type, req.getInputStream());
            Log.println("将数据保存到数据库表中");
    
            HashMap<String, Boolean> result = new HashMap<>();
            result.put("result", true);
            String json = objectMapper.writeValueAsString(result);
            Log.println(json);
            writer.println(json);
    
            // 完整的音频数据放在 InputStream(请求体)
    //        ServletInputStream is = req.getInputStream();
    //        try (OutputStream os = new FileOutputStream("D:\\upload" + title + ".ogg")) {
    //            byte[] buf = new byte[4096];
    //            while (true) {
    //                int n = is.read(buf);
    //                Log.println("读到了: " + n);
    //                if (n == -1) {
    //                    break;
    //                }
    //                os.write(buf, 0, n);
    //            }
    //            os.flush();
    //        }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    2-4 执行结果

    1. 允许访问连接
      在这里插入图片描述
    2. 授权成功
      在这里插入图片描述
    3. 录制音频
      在这里插入图片描述

    回到目录…


    总结:
    提示:这里对文章进行总结:
    以上就是今天的学习内容,本文是WebAPI的学习,实现了一个上传音频的小应用,如何访问连接媒体输入设备,如何通过Ajax发出请求,后端做出响应处理音频数据。之后的学习内容将持续更新!!!

  • 相关阅读:
    竞赛选题 基于视觉的身份证识别系统
    Python-自动化测试面试
    [java]深度剖析面向对象编程
    必须收藏!没有经验的程序员该怎么找工作?
    冥想第五百九十四天
    项目(智慧教室)第一部分:cubemx配置,工程文件的移植,触摸屏的检测,项目bug说明
    HackTheBox-Starting Point--Tier 0---Preignition
    Chrome添加扩展程序
    Java学习笔记4.6.3 格式化 - DateTimeFomatter类
    RegExp 对象
  • 原文地址:https://blog.csdn.net/qq15035899256/article/details/126359715