Android Accessibility 服务实时音频处理

2024-04-22

有人可以为我提供 Android 辅助功能服务实时音频处理的示例代码吗?我需要处理通话音频。但不知道如何实现这一点。请分享您对此的想法

请找到下面的清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mycalltest">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">

        <service
            android:name=".MyAccessibilityService"
            android:label="@string/accessibility_service_label"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>

            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config" />
        </service>


        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

请找到以下辅助功能 xml:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeWindowContentChanged|typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="100"
    android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
    android:canRetrieveWindowContent="true"
    />

PFB 服务:

import android.accessibilityservice.AccessibilityService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;

import android.media.MediaRecorder;
import android.os.Build;

import android.util.Log;
import android.view.accessibility.AccessibilityEvent;

import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class MyAccessibilityService extends AccessibilityService {
    private static final String TAG="MyAccessibilityService";

    private Context context;
    public static final String CHANNEL_ID = "MyAccessibilityService";

    MediaRecorder mRecorder;
    private boolean isStarted;
    byte buffer[] = new byte[8916];

    private MediaSaver mediaSaver;
    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onCreate() {
        super.onCreate();

        Log.d(TAG,"MyAccessibilityService Salesken Started ...");
        context=this;

        startForegroundService();
    }




    private void startForegroundService() {
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("recording Service")
                .setContentText("Start")
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1, notification);

    }
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Recording Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            String action = intent.getAction();

            switch (action) {
                case SaleskenIntent.START_RECORDING:
                    Log.d(TAG,"Start Recording");

                    //startRecorder();
                    String contact = intent.getStringExtra("contact");
                    startRecording(contact);

                    break;
                case SaleskenIntent.STOP_RECORDING:

                    Log.d(TAG,"Stop Recording");

                    stopRecording();
                    break;
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }





    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {

    }

    @Override
    public void onInterrupt() {

    }




    @Override
    public void onDestroy() {
        super.onDestroy();

    }

        public void startRecording(String contact) {
            try {

                String timestamp = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss", Locale.US).format(new Date());
                String fileName =timestamp+".3gp";
                mediaSaver = new MediaSaver(context).setParentDirectoryName("Accessibility").
                        setFileNameKeepOriginalExtension(fileName).
                        setExternal(MediaSaver.isExternalStorageReadable());
                //String selectedPath = Environment.getExternalStorageDirectory() + "/Testing";
                //String selectedPath = Environment.getExternalStorageDirectory().getAbsolutePath() +"/Android/data/" + packageName + "/system_sound";



                mRecorder = new MediaRecorder();
                mRecorder.reset();

                //android.permission.MODIFY_AUDIO_SETTINGS
                AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); //turn on speaker
                if (mAudioManager != null) {
                    mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); //MODE_IN_COMMUNICATION | MODE_IN_CALL
                    // mAudioManager.setSpeakerphoneOn(true);
                    // mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0); // increase Volume
                    hasWiredHeadset(mAudioManager);
                }

                //android.permission.RECORD_AUDIO
                String manufacturer = Build.MANUFACTURER;
                Log.d(TAG, manufacturer);
           /* if (manufacturer.toLowerCase().contains("samsung")) {
                mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
            } else {
                mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
            }*/
            /*
            VOICE_CALL is the actual call data being sent in a call, up and down (so your side and their side). VOICE_COMMUNICATION is just the microphone, but with codecs and echo cancellation turned on for good voice quality.
            */
                mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); //MIC | VOICE_COMMUNICATION (Android 10 release) | VOICE_RECOGNITION | (VOICE_CALL = VOICE_UPLINK + VOICE_DOWNLINK)
                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //THREE_GPP | MPEG_4
                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //AMR_NB | AAC
                mRecorder.setOutputFile(mediaSaver.pathFile().getAbsolutePath());
                mRecorder.prepare();
                mRecorder.start();
                isStarted = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void stopRecording() {
            if (isStarted && mRecorder != null) {
                mRecorder.stop();
                mRecorder.reset(); // You can reuse the object by going back to setAudioSource() step
                mRecorder.release();
                mRecorder = null;
                isStarted = false;
            }
        }

        // To detect the connected other device like headphone, wifi headphone, usb headphone etc
        private boolean hasWiredHeadset(AudioManager mAudioManager) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return mAudioManager.isWiredHeadsetOn();
            } else {
                final AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
                for (AudioDeviceInfo device : devices) {
                    final int type = device.getType();
                    if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
                        Log.d(TAG, "hasWiredHeadset: found wired headset");
                        return true;
                    } else if (type == AudioDeviceInfo.TYPE_USB_DEVICE) {
                        Log.d(TAG, "hasWiredHeadset: found USB audio device");
                        return true;
                    } else if (type == AudioDeviceInfo.TYPE_TELEPHONY) {
                        Log.d(TAG, "hasWiredHeadset: found audio signals over the telephony network");
                        return true;
                    }
                }
                return false;
            }
        }




    }

您需要更改音频源输入。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Accessibility 服务实时音频处理 的相关文章

随机推荐

  • 如何在错误的 API url 上返回 404? (ASP.NET 核心 + SPA)

    我需要在错误的 api 调用上返回 404 以便我可以在客户端 Angular 5 上为用户创建正确的响应 目前后端返回状态码200和index html 这会导致前端出现json解析错误 我使用 ASP NET Core 2 1 和 An
  • 如何在 JavaScript 中解析文本中的单词?

    在文本页面中 我想检查每个单词 当时阅读每个单词的最佳方式是什么 找到被空格包围的单词很容易 但是一旦你开始解析文本中的单词 它就会变得复杂 是否有一些已经构建的东西可以解析正则表达式或其他方法中的单词 而不是定义我自己的从文本中解析单词的
  • 您应该将应用程序属性放在 rebar erlang 应用程序中的什么位置?

    新手问题 我编写了第一个基于 rebar 的 erlang 应用程序 我想配置一些基本属性 例如服务器主机等 放置它们的最佳位置在哪里以及如何将它们加载到应用程序中 接下来的步骤是发布版本并在其中创建节点 节点在独立的 Erlang VM
  • 有人有使用私有 Launchpad 实例的经验吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有人已经在自己的服务器上安装并运行启动板了吗 我想要建议 因为我在网上找不到任何建议 此外 官方团队还对拥有自己的启动板发表了可怕的言论 他们还
  • 将google云函数连接到oracle数据库

    有谁知道如何将谷歌云函数 Python 连接到Oracle数据库 我尝试在云函数中导入cx Oracle库 但它显示一个错误 函数加载错误 DPI 1047 无法加载 Oracle 客户端库 libclntsh so 无法打开共享对象文件
  • 使用多个管道从 Python 执行 Shell 脚本

    我想在 python 脚本中执行以下 Shell 命令 dom myserver cat etc xen myserver cfg grep limited cut d f2 tr d 我有这个 dom myserver limit sub
  • 如何设置 GMT 日期的时、分、秒

    我有日期对象 我想从我的日期中清除小时 分钟和秒 请帮助我如何在 Javascript 中执行此操作 我做错了吗 var date Date Fri 26 Sep 2014 18 30 00 GMT date setHours 0 date
  • 如何模拟 AngularJS 指令的控制器

    给定一个具有外部控制器的指令 directive d1 function return controller d1controller restrict E link function scope element attributes co
  • 为什么长整型和小数之间的等于不可交换?

    我在 linqpad 中运行以下代码 long x long MaxValue decimal y x x Dump y Dump x y Dump y x Dump Object Equals x y Dump Object Equals
  • PyMongo find() 使用 $or 和 $regex 进行查询

    有一个 MongoDB 文档集合 其中包含有关书籍的信息 我需要使用以下标准查找文档 header包含子串 OR author包含子串 在 mongo shell 中 我使用这个查询效果很好 db books find or author
  • 在linux上编译一个基本的OpenCV + Cuda程序

    我过去在linux上使用过opencv 但没有使用过cuda 几个月来我一直在与以下编译错误作斗争 在尝试了许多解决方案后 我放弃并使用 Windows 不过 我真的很想在 Linux 上工作 这是我用来编译 opencv gpu 网站上给
  • 将 css 添加到 Magento 模板文件的 head 中

    我想在 magento 中的模板 phtml 文件的标签内添加一个 CSS 文件 是否可以 这样做是有原因的 CSS 文件名是动态的 所以直到模板执行时我才知道 可以这样做吗 要在加载布局之后 渲染布局之前从控制器添加 CSS 文件 您需要
  • 如何在 matplotlib 上以对数刻度可视化值?

    我的值差异非常小 例如 0 000001 我想以对数尺度可视化它们 我想知道如何在 matplotlib 中做到这一点 多谢 http matplotlib sourceforge net api pyplot api html matpl
  • “parse”在交互和非交互模式下的行为不同

    我认为这可能是一个错误parse 但想检查一下是否还有其他人有更好的主意 在交互模式 RStudio 下 以下代码可以正常工作 txt lt c c integer 3L 1 3 c integer 1 3 1L TRUE c intege
  • 用颤动绘制虚线弧

    Flutter 有没有办法画虚线弧 目前我正在使用 canvas drawArc 但我不知道如何获得正确的结果 canvas drawArc rectangle startAngle fullArcRadius false Paint co
  • 带有 pfx 文件的 Azure https

    我正在尝试创建一个https我的天蓝色服务的端点 我被给予了p7b我转换成的文件cer文件 来自cer我能够用几行 c 转换为pfx var cert new X509Certificate2 certpath var bytes cert
  • 返回 clickhouse 数组作为列

    Clickhouse 是否可以将包含一对数组的结果转换为列 形成这个结果 f1 f2 f3 a 1 2 3 x y z b 4 5 6 x y z to f1 x y z a 1 2 3 b 4 5 6 这个想法是不必为每行重复标题值 就我
  • Webpack - 如何捆绑/需要文件夹(子文件夹)的所有文件

    我想看看是否有更短的方式来运行 webpack 包 以及为什么我的加载器不起作用 这是我的代码 module exports context path join dirname dist entry ES6bundle js jQuery
  • JS 库来模拟 Internet Explorer?

    Webkit中有一些JS库可以模拟IE吗 例如 IE8不支持border radius目前 可能在 IE10 上 所以我运行一个 JS 库来检查我是否正在使用border radius然后将其删除以制作类似于IE的视觉 我知道这是一个疯狂的
  • Android Accessibility 服务实时音频处理

    有人可以为我提供 Android 辅助功能服务实时音频处理的示例代码吗 我需要处理通话音频 但不知道如何实现这一点 请分享您对此的想法 请找到下面的清单