• 关于安卓设备声音远程传输的解决方案


    本文首发于:行者AI

    近期本人在做安卓设备的云平台,设备云平台这个东西相信对大家而言并不陌生,常见的功能比如用来远程监控操作一部手机,上传文件啊,查看日志之类的。但是当你想用云手机看视频、玩游戏、听音乐的时候,就发现,现在市面上的云手机,没有一家是有声音传输功能的。

    在发现这个情况后,萌生了想要做出这个功能的想法,那具体该什么做呢?在做之前,我先进行了一个小调研,了解目前有没有现成的解决方案,看看能否给自己带来一些参考。

    经过了几天的研究,我先把大致的结果告诉各位。

    声音传输有限制,但仍能实现。

    1. 目前现有方案对比

    设备麦克风 第三方投屏软件 Sndcpy
    声音来源 手机麦克风 手机麦克风 应用流媒体自身数据
    效果 会受外界干扰 会干扰,但也有提供算法降噪 取决于音频数据本身
    应用限制 其他应用调用麦克风串流 其他应用调用麦克风串流 未授予权限的应用
    安卓版本 任意 任意 安卓10以上

    2. 方案选定

    其实不难看出来,第三方投屏软件用的也就是设备的麦克风,只是因为数据先经由软件客户端,在拿给音频播放前,自己多用算法处理进行了一次降噪(燃鹅算法降噪都是辣鸡)。可是大家有想过他的实用效果吗?想象一下,一般作为设备云平台的使用场景是什么样的:

    图1. 群控图片(素材来自网络)

    如此密集的设备,这样的场景,靠外放捕获声音,一个还好说,多来几个,那效果谁受得了?而且如果手机本身有应用需要使用麦克风,那效果也不言而喻。所以,使用设备麦克风这样的方案,作为平台来讲,肯定是不行的!

    既然用麦克风不行,那就代表没有别的路可走了吗?直觉告诉我当然不是。如果有一种方式,能直接对应用的媒体数据流进行捕获,而不是通过外放出来的声音进行录制,那这样的方式无疑会让效果大大提升!发现了这点的我,顺藤摸瓜,于是乎摸到了sndcpy这个开源项目 。

    3. 方案实施

    3.1 项目简介

    sndcpy github地址

    项目的介绍上有详细说明,这里我只做一个简短的概述就好:

    (1)只支持安卓10以上设备

    (2)跨系统平台可运行

    (3)可使用VLC对已连接设备进行听取

    针对第一点,本质上是针对有对应接口的sdk版本,在安卓应用的配置中,允许声音流媒体被监听的开关打开,这样的应用就能获取到声音。

    (例如qq音乐,然而经过试验,谷歌浏览器反而属于不行的那种)

    3.2 使用步骤

    (1)下载项目中已经build好的zip文件(如无adb,下载with-adb版本的,并配置环境,这里就不讲怎么配环境了);

    (2)连接手机设备,到解压目录下的./sndcpy,多设备情况后面带设备号;

    (3)在手机上确认允许;

    (4)下载安装vlc;

    (5)运行vlc,首次可能会遇到报错,但没关系,再来一次就好了。

    4. 进行集成

    使用是能使用了,但是作为云平台的项目而言,客户是要通过网页播放听到设备的,通过vlc才能听到的这种方式,明显不符合使用需求。而作为流媒体实时网络通信,我们自然该想到将其做成websocket的形式,而这也就需要实现现有的socket服务。

    然而,只要仔细看过这个项目的文件,你就会发现,我们想要的东西,其实拿来就能用。压缩包中一共有三个文件,其中的.bat文件,我们将其打开看下:

    
    #!/bin/bash
    set -e
    ADB=${ADB:-adb}
    VLC=${VLC:-vlc}
    SNDCPY_APK=${SNDCPY_APK:-sndcpy.apk}
    SNDCPY_PORT=${SNDCPY_PORT:-28200}
    
    serial=
    if [[ $# -ge 1 ]]
    then
        serial="-s $1"
        echo "Waiting for device $1..."
    else
        echo 'Waiting for device...'
    fi
    
    "$ADB" $serial wait-for-device
    "$ADB" $serial install -t -r -g "$SNDCPY_APK" ||
    {
        echo 'Uninstalling existing version first...'
        "$ADB" $serial uninstall com.rom1v.sndcpy
        "$ADB" $serial install -t -g "$SNDCPY_APK"
    }
    
    "$ADB" $serial forward tcp:$SNDCPY_PORT localabstract:sndcpy
    "$ADB" $serial shell am start com.rom1v.sndcpy/.MainActivity
    echo "Press Enter once audio capture is authorized on the device to start playing..."
    read dummy
    "$VLC" -Idummy --demux rawaud --network-caching=0 --play-and-exit tcp://localhost:"$SNDCPY_PORT"
    
    

    发现正是使用的adb命令开启的tcp服务进行传输。为了方便大家直接进行操作,这里我直接罗列命令和步骤,按照这个步骤操作,安卓端设备传输的问题就能解决:

    (1)将sndcpy.apk放到/data/local/tmp目录下,推荐使用adb命令 adb push sndcpy.apk /data/local/tmp

    (2)adb forward tcp:port(port自己定义一个,这个不影响) localabstract:sndcpy

    (3)adb shell am start com.rom1v.sndcpy/.MainActivity

    (4)本地启动一个socket,绑定最先port定义的端口,如果返回的数据不是空,恭喜你,成功了!
    基本的启动就是这样,而对于web项目而言,将socket做一次websocket的转发就能完成在网页端的播放了(当然,还需要前端本身支持这样格式的音频流传输处理)。

    就此,大功告成!


    PS:更多技术干货,快关注【公众号 | xingzhe_ai】,与行者一起讨论吧!

  • 相关阅读:
    抽象类使用细节
    super关键字
    JDK,JRE,JVM三者之间的爱恨情仇
    LinkedHashSet
    HashSet扩容成红黑树机制
    Set之HashSet
    finally关键字
    Hashcode方法
    equals方法和==的区别
    LinkedList
  • 原文地址:https://www.cnblogs.com/xingzheai/p/14745628.html
Copyright © 2020-2023  润新知