Android平台RTMP推送|轻量级RTSP服务如何实现麦克风|扬声器声音采集切换

本文涉及的产品
视觉智能开放平台,分割抠图1万点
视觉智能开放平台,图像资源包5000点
视觉智能开放平台,视频资源包5000点
简介: Android平台扬声器播放声音的采集,在无纸化同屏等场景下,意义很大,早期低版本的Android设备,是没法直接采集扬声器audio的(从Android 10开始支持),所以,如果需要采集扬声器audio,需要先做系统版本判断,添加相应的权限。

技术背景

我们在做Android端同屏的时候,开发者希望可以高版本的Android系统上,在设备支持的前提下,可以采集到扬声器输出的audio,并支持和麦克风采集的audio相互切换,实现无纸化|智慧教室同屏不同audio模式的输出。Android系统出于安全和隐私的考虑,默认并不允许应用程序直接访问系统级别的音频输出。

从Android 10(API级别29)开始,Android引入了媒体投影API(MediaProjection),允许应用捕获屏幕内容以及音频。但是,直接捕获扬声器输出的音频并不是通过MediaProjection API直接实现的,而是通常与屏幕录制功能一起提供。

  • 启用屏幕录制权限:应用需要请求RECORD_AUDIOCAPTURE_AUDIO_OUTPUT权限,以及CAPTURE_VIDEO_OUTPUTCAPTURE_SECURE_VIDEO_OUTPUT(如果捕获安全内容)。
  • 使用MediaProjectionManager:创建一个MediaProjection会话,并引导用户通过系统UI授权屏幕录制。
  • 捕获音频:在录制屏幕时,音频也会同时被捕获。但是,这通常只适用于用户当前正在操作的应用的音频输出,而不是整个系统的音频。

技术实现

本文以大牛直播SDK的SmartServicePublisherV2这个demo为例,介绍下相关的技术实现。

image.gif 编辑

如果需要支持音频播放采集和麦克风采集,可以想把这两个选项打开,然后,通过右侧下拉框,推送过程中,实时切换数据源。

采集麦克风实现逻辑:

/*
 * NTStreamMediaProjectionEngineImpl.java
 * Author: daniusdk.com
 * WeChat: xinsheng120
 *
 * Copyright © 2014~2024 DaniuSDK. All rights reserved.
 */
@Override
public boolean start_audio_record(int sample_rate, int channels) {
    if (audio_record_.get() != null) {
        Log.e(TAG, "start_audio_record audio_record already exists");
        return false;
    }
    if (!check_record_audio_permission()) {
        Log.e(TAG, "start_audio_record RECORD_AUDIO permission is missing");
        return false;
    }
    NTAudioRecordV2 audio_record = new NTAudioRecordV2(get_application_context());
    // audio_record.IsMicSource(true);      //如音频采集声音过小,建议开启
    // audio_record.IsRemoteSubmixSource(true); // Anrdoid 10以下, 有些设备可能能用
   if (!audio_record.Start(sample_rate, channels)) {
       Log.e(TAG, "start_audio_record start failed");
       return false;
   }
    if (audio_record_callback_ != null)
        audio_record.AddCallback(audio_record_callback_);
    NTAudioRecordV2 old = audio_record_.getAndSet(audio_record);
    if (old != null) {
        if (audio_record_callback_ != null)
            old.RemoveCallback(audio_record_callback_);
        old.Stop();
    }
    Log.i(TAG, "start_audio_record ok, sample_rate:" + sample_rate + ", channels:" + channels);
    return true;
}
@Override
public boolean is_audio_record_running() {
    return audio_record_.get() != null;
}
@Override
public void stop_audio_record() {
    NTAudioRecordV2 old = audio_record_.getAndSet(null);
    if (old != null) {
        if (audio_record_callback_ != null)
            old.RemoveCallback(audio_record_callback_);
        old.Stop();
        Log.i(TAG, "call audio_record_.Stop.");
    }
}

image.gif

采集音频播放声音(扬声器)实现逻辑:

/*
 * NTStreamMediaProjectionEngineImpl.java
 * Author: daniusdk.com
 * WeChat: xinsheng120
 *
 * Copyright © 2014~2024 DaniuSDK. All rights reserved.
 */
@Override
public boolean start_audio_playback_capture(int sample_rate, int channels) {
    if (Build.VERSION.SDK_INT < 29) {
        Log.e(TAG, "start_audio_playback_capture Device SDK_INT:" + Build.VERSION.SDK_INT +" < 29(Android 10)");
        return false;
    }
    if (audio_playback_capture_.get() != null) {
        Log.e(TAG, "start_audio_playback_capture capture already exists");
        return false;
    }
    if (!check_record_audio_permission()) {
        Log.e(TAG, "start_audio_playback_capture RECORD_AUDIO permission is missing.");
        return false;
    }
    MediaProjection media_projection = get_media_projection();
    if (null == media_projection) {
        Log.e(TAG, "start_audio_playback_capture media_projection is null");
        return false;
    }
    NTAudioPlaybackCapture capture = new NTAudioPlaybackCapture();
    if (!capture.start(get_application_context(), media_projection, sample_rate, channels)) {
        capture.close();
        Log.e(TAG, "start_audio_playback_capture start failed");
        return false;
    }
    if (audio_playback_capture_callback_ != null)
        capture.register_callback(audio_playback_capture_callback_);
    NTAudioPlaybackCapture old = audio_playback_capture_.getAndSet(capture);
    if (old != null)
        old.close();
    Log.i(TAG, "start_audio_playback_capture ok, sample_rate:" + sample_rate + ", channels:" + channels);
    return true;
}
@Override
public boolean is_audio_playback_capture_running() {
    return audio_playback_capture_.get() != null;
}
@Override
public void stop_audio_playback_capture() {
    NTAudioPlaybackCapture old = audio_playback_capture_.getAndSet(null);
    if (old != null) {
        old.close();
        Log.i(TAG, "stop_audio_playback_capture capture.close.");
    }
}

image.gif

启动RTMP推送或轻量级RTSP服务过程中,切换采集扬声器或者麦克风:

@Override
public boolean set_audio_output_type(int type) {
    if (type < 0 || type > 2) {
        Log.e(TAG, "set_audio_output_type type:" + type + " error");
        return false;
    }
    Runnable r = new Runnable() {
        int type_;
        @Override
        public void run() {
            audio_output_type_ = this.type_;
            Log.i(TAG, "set_audio_output_type value:" + this.type_);
            if (stream_publisher_.is_publishing())
                switch_audio_output_type(audio_output_type_);
        }
        Runnable set(int type) {
            this.type_ = type;
            return this;
        }
    }.set(type);
    post_or_execute(r);
    return true;
}

image.gif

播放效果如下(Android采集屏幕和麦克风|扬声器audio,然后推送到RTMP服务和轻量级RTSP服务),扬声器audio采集,特别是视频播放模式下,比如无纸化同屏过程中,需要放个宣传片,或者一些视频材料,非常方便:

image.gif 编辑

总结

Android平台扬声器播放声音的采集,在无纸化同屏等场景下,意义很大,早期低版本的Android设备,是没法直接采集扬声器audio的(从Android 10开始支持),所以,如果需要采集扬声器audio,需要先做系统版本判断,添加相应的权限。如果需要实时切换扬声器或麦克风声音,可以参考上述实现逻辑,以上是大概的流程,感兴趣的开发者,可以单独跟我沟通讨论。

相关文章
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
109 1
|
2月前
|
IDE Android开发 iOS开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
【9月更文挑战第27天】在移动应用开发的世界中,Android和iOS是两个主要的操作系统平台。每个系统都有其独特的开发环境、工具和用户群体。本文将深入探讨这两个平台的关键差异点,并分析这些差异如何影响应用的性能、用户体验和最终的市场表现。通过对比分析,我们将揭示选择正确的开发平台对于确保项目成功的重要作用。
|
25天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
22 1
|
29天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
81 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
开发工具 Android开发 iOS开发
安卓与iOS开发环境对比:选择适合你的平台
【9月更文挑战第26天】在移动应用开发的广阔天地中,安卓和iOS是两大巨头。它们各自拥有独特的优势和挑战,影响着开发者的选择和决策。本文将深入探讨这两个平台的开发环境,帮助你理解它们的核心差异,并指导你根据个人或项目需求做出明智的选择。无论你是初学者还是资深开发者,了解这些平台的异同都至关重要。让我们一起探索,找到最适合你的那片开发天地。
|
2月前
|
Android开发 开发者
Android平台无纸化同屏如何实现实时录像功能
Android平台无纸化同屏,如果需要本地录像的话,实现难度不大,只要复用之前开发的录像模块的就可以,对我们来说,同屏采集这块,只是数据源不同而已,如果是自采集的其他数据,我们一样可以编码录像。
|
2月前
|
编解码 开发工具 Android开发
Android平台实现屏幕录制(屏幕投影)|音频播放采集|麦克风采集并推送RTMP或轻量级RTSP服务
Android平台屏幕采集、音频播放声音采集、麦克风采集编码打包推送到RTMP和轻量级RTSP服务的相关技术实现,做成高稳定低延迟的同屏系统,还需要有配套好的RTMP、RTSP直播播放器
|
Android开发 数据安全/隐私保护 开发工具
|
3天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
5天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。

热门文章

最新文章