Android添加蓝牙音响功能

  • \system\media\audio\include\system
    • audio.h
  • \system\bt
    • Android.mk
    • audio_a2dp_hw\Android.mk
    • include\bt_target.h
  • \hardware\libhardware_legacy\audio
    • Android.mk
    • AudioPolicyManagerBase.cpp
  • \packages\apps\Bluetooth\src\com\android\bluetooth\a2dp
    • A2dpSinkStateMachine.java
    • AndroidManifest.xml
  • \frameworks\base
    • api\sytem-current.txt
    • api\current.txt
    • \media\java\android\media
      • AudioAttributes.java
      • AudioManager.java
      • AudioSystem.java
      • MediaRecorder.java
    • services/core/java/com/android/server/audio/AudioService.java
  • \frameworks\av\services\audiopolicy
    • enginedefault\src\Engine.cpp
    • audio_policy.conf

\system\media\audio\include\system

audio.h

添加AUDIO_SOURCE_BLUETOOTH_A2DP

typedef enum {AUDIO_SOURCE_DEFAULT             = 0,AUDIO_SOURCE_MIC                 = 1,AUDIO_SOURCE_VOICE_UPLINK        = 2,AUDIO_SOURCE_VOICE_DOWNLINK      = 3,AUDIO_SOURCE_VOICE_CALL          = 4,AUDIO_SOURCE_CAMCORDER           = 5,AUDIO_SOURCE_VOICE_RECOGNITION   = 6,AUDIO_SOURCE_VOICE_COMMUNICATION = 7,AUDIO_SOURCE_REMOTE_SUBMIX       = 8, /* Source for the mix to be presented remotely.      *//* An example of remote presentation is Wifi Display *//*  where a dongle attached to a TV can be used to   *//*  play the mix captured by this audio source.      */AUDIO_SOURCE_HDMIRX              = 9,AUDIO_SOURCE_BLUETOOTH_A2DP      = 10,AUDIO_SOURCE_CNT,AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,AUDIO_SOURCE_FM_TUNER            = 1998,AUDIO_SOURCE_HOTWORD             = 1999, /* A low-priority, preemptible audio source forfor background software hotword detection.Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.Used only internally to the framework. Not exposedat the audio HAL. */
} audio_source_t;

\system\bt

Android.mk

ifeq ($(BLUETOOTH_A2DP_SINK),true)bdroid_CFLAGS += -DA2DP_SINK
endif

audio_a2dp_hw\Android.mk

ifeq ($(BLUETOOTH_A2DP_SINK),true)
LOCAL_CFLAGS += -DA2DP_SINK
endif

include\bt_target.h

#ifndef BTA_AV_SINK_INCLUDED
#define BTA_AV_SINK_INCLUDED TRUE
#endif

\hardware\libhardware_legacy\audio

Android.mk

ifeq ($(BLUETOOTH_A2DP_SINK),true)
LOCAL_CFLAGS += -DBLUETOOTH_A2DP_SINK
endif

AudioPolicyManagerBase.cpp

audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
{uint32_t device = AUDIO_DEVICE_NONE;switch (inputSource) {case AUDIO_SOURCE_VOICE_UPLINK:if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {device = AUDIO_DEVICE_IN_VOICE_CALL;break;}// FALL THROUGHcase AUDIO_SOURCE_DEFAULT:case AUDIO_SOURCE_MIC:if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;break;}// FALL THROUGHcase AUDIO_SOURCE_VOICE_RECOGNITION:case AUDIO_SOURCE_HOTWORD:case AUDIO_SOURCE_VOICE_COMMUNICATION:if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {device = AUDIO_DEVICE_IN_WIRED_HEADSET;} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {device = AUDIO_DEVICE_IN_USB_DEVICE;} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_SOURCE_CAMCORDER:if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {device = AUDIO_DEVICE_IN_BACK_MIC;} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_SOURCE_VOICE_DOWNLINK:case AUDIO_SOURCE_VOICE_CALL:if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {device = AUDIO_DEVICE_IN_VOICE_CALL;}break;case AUDIO_SOURCE_REMOTE_SUBMIX:if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;}break;case AUDIO_SOURCE_HDMIRX:if (mAvailableInputDevices & AUDIO_DEVICE_IN_AUX_DIGITAL) {device = AUDIO_DEVICE_IN_AUX_DIGITAL;}break;//add begincase AUDIO_SOURCE_BLUETOOTH_A2DP:if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;      }break;//add enddefault:ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);break;}ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);return device;
}

\packages\apps\Bluetooth\src\com\android\bluetooth\a2dp

A2dpSinkStateMachine.java

import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder.AudioSource;final class A2dpSinkStateMachine extends StateMachine {private AudioRecord recorder;private AudioTrack player;private int recorder_buf_size;private int player_buf_size;private boolean mThreadExitFlag = false;private boolean isPlaying = false;

通过AudioRecord和AudioTrack播放蓝牙音频

    private A2dpSinkStateMachine(A2dpSinkService svc, Context context) {super("A2dpSinkStateMachine");recorder_buf_size = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);player_buf_size = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);}private void cleanAudioTrack(){audioPause();mThreadExitFlag = true;if (recorder != null) {recorder.release();recorder = null;}if (player != null) {player.release();player = null;}}private void initAudioTrack()    {        if (recorder == null) {            recorder = new AudioRecord(AudioSource.BLUETOOTH_A2DP, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT,  recorder_buf_size);        }        if (player == null) {            player = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, player_buf_size, AudioTrack.MODE_STREAM);        }    }private void audioPlay()    {        initAudioTrack();        if (isPlaying == false) {            isPlaying = true;            mThreadExitFlag = false;            new RecordThread().start();        }    }private void audioPause() {       if (isPlaying == true) {         isPlaying = false;          mThreadExitFlag = true;          recorder.stop();           player.stop();       }     }
    private class Disconnected extends State {@Overridepublic void enter() {log("Enter Disconnected: " + getCurrentMessage().what);if (isA2dpSinkEnabled()) {cleanAudioTrack();}}
        private void processAudioStateEvent(int state, BluetoothDevice device) {if (!mCurrentDevice.equals(device)) {loge("Audio State Device:" + device + "is different from ConnectedDevice:" +mCurrentDevice);return;}switch (state) {case AUDIO_STATE_STARTED:if (isA2dpSinkEnabled()) {audioPlay();}broadcastAudioState(device, BluetoothA2dpSink.STATE_PLAYING,BluetoothA2dpSink.STATE_NOT_PLAYING);break;case AUDIO_STATE_REMOTE_SUSPEND:case AUDIO_STATE_STOPPED:if (isA2dpSinkEnabled()) {audioPause();}broadcastAudioState(device, BluetoothA2dpSink.STATE_NOT_PLAYING,BluetoothA2dpSink.STATE_PLAYING);break;default:loge("Audio State Device: " + device + " bad state: " + state);break;}}}private static boolean isA2dpSinkEnabled() {    ParcelUuid[] uuids = BluetoothAdapter.getDefaultAdapter().getUuids();    return BluetoothUuid.isUuidPresent(uuids,BluetoothUuid.AudioSink); }
 class RecordThread  extends Thread{        @Override        public void run() {            byte[] buffer = new byte[recorder_buf_size];            recorder.startRecording();            player.play();            while(true) {                if (mThreadExitFlag == true) {                    break;                }                try {                    int res = recorder.read(buffer, 0, recorder_buf_size);                    if (res>0) {                        byte[] tmpBuf = new byte[res];                        System.arraycopy(buffer, 0, tmpBuf, 0, res);                        player.write(tmpBuf, 0, tmpBuf.length);                    }                } catch (Exception e) {                    e.printStackTrace();                    break;                }            }        }    }

AndroidManifest.xml

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

关于在哪取蓝牙过来的音频数据,怎么能让蓝牙进入音频数据过来的模式,这部分android 已经做好了。我们只需要配置一下 packages/apps/Bluetooth/res/values/config.xml 里

<resources><bool name="profile_supported_rtkbt">true</bool><bool name="profile_supported_a2dp">true</bool><bool name="profile_supported_a2dp_sink">true</bool>

\frameworks\base

api\sytem-current.txt

api\current.txt

  public class AudioManager {field public static final int DEVICE_IN_BLUETOOTH_A2DP = -2147352576; // 0x80020000
public final class MediaRecorder.AudioSource {field public static final int BLUETOOTH_A2DP = 10; // 0xa

\media\java\android\media

AudioAttributes.java

        @SystemApipublic Builder setCapturePreset(int preset) {switch (preset) {case MediaRecorder.AudioSource.DEFAULT:case MediaRecorder.AudioSource.MIC:case MediaRecorder.AudioSource.CAMCORDER:case MediaRecorder.AudioSource.VOICE_RECOGNITION:case MediaRecorder.AudioSource.VOICE_COMMUNICATION:case MediaRecorder.AudioSource.BLUETOOTH_A2DP:mSource = preset;break;default:Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");}return this;

AudioManager.java

    public boolean isBluetoothA2dpOn() {/*if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")== AudioSystem.DEVICE_STATE_UNAVAILABLE) {return false;} else {return true;}*/if (AudioSystem.isA2dpSinkEnabled()) {if (AudioSystem.getDeviceConnectionState(DEVICE_IN_BLUETOOTH_A2DP,"")== AudioSystem.DEVICE_STATE_UNAVAILABLE) {return false;} else {return true;}         } else { if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")== AudioSystem.DEVICE_STATE_UNAVAILABLE) {return false;} else {return true;}}}public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;public static final int DEVICE_IN_BLUETOOTH_A2DP = AudioSystem.DEVICE_IN_BLUETOOTH_A2DP;

AudioSystem.java

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothUuid;
import android.os.ParcelUuid;
import android.os.SystemProperties;public static    boolean isA2dpSinkEnabled(){String property = SystemProperties.get("device.bluetooth.ctrl");if(property.equals("true")){ParcelUuid[] uuids = BluetoothAdapter.getDefaultAdapter().getUuids();for (ParcelUuid uuid: uuids) {Log.e(TAG, "UUID: " + uuid.getUuid().toString());}return BluetoothUuid.isUuidPresent(uuids,BluetoothUuid.AudioSink);}else{return false;}}

MediaRecorder.java

 public static final int BLUETOOTH_A2DP = 10;public static final int getAudioSourceMax() {//return AudioSource.REMOTE_SUBMIX;if (AudioSystem.isA2dpSinkEnabled()) {return AudioSource.BLUETOOTH_A2DP;} else {return AudioSource.REMOTE_SUBMIX;}}

services/core/java/com/android/server/audio/AudioService.java

    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {// address is not used for now, but may be used when multiple a2dp devices are supportedsynchronized (mA2dpAvrcpLock) {mAvrcpAbsVolSupported = support;
/*sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_MUSIC], 0);sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_RING], 0);
*/if (AudioSystem.isA2dpSinkEnabled()) {sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_MUSIC], 0);sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_RING], 0);} else {sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_MUSIC], 0);sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,mStreamStates[AudioSystem.STREAM_RING], 0);}}}

\frameworks\av\services\audiopolicy

enginedefault\src\Engine.cpp

audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
{const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices();const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices();const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;uint32_t device = AUDIO_DEVICE_NONE;switch (inputSource) {case AUDIO_SOURCE_VOICE_UPLINK:if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {device = AUDIO_DEVICE_IN_VOICE_CALL;break;}break;case AUDIO_SOURCE_DEFAULT:device = AUDIO_DEVICE_IN_BUILTIN_MIC;break;//begincase AUDIO_SOURCE_BLUETOOTH_A2DP:if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;}break;

audio_policy.conf

修改audio_policy.conf配置

  a2dp {outputs {a2dp {sampling_rates 44100channel_masks AUDIO_CHANNEL_OUT_STEREOformats AUDIO_FORMAT_PCM_16_BITdevices AUDIO_DEVICE_OUT_ALL_A2DP}}inputs {a2dp {sampling_rates 44100channel_masks AUDIO_CHANNEL_IN_STEREOformats AUDIO_FORMAT_PCM_16_BITdevices AUDIO_DEVICE_IN_BLUETOOTH_A2DP}}}

Android添加蓝牙音响功能相关推荐

  1. android 连接蓝牙音响,Android 扫描附近的蓝牙设备并连接蓝牙音响的示例

    Android 扫描附近的蓝牙设备并连接蓝牙音响的示例 发布时间:2020-09-10 04:30:39 来源:脚本之家 阅读:111 作者:叶应是叶 写了一个可以扫描附近蓝牙设备的小Demo,可以查 ...

  2. android连接蓝牙音响

    public class BluetoothConnect {private DeviceReceiver devicecReceiver;List<BluetoothDevice> de ...

  3. Android 添加蓝牙遥控按键

    一. 蓝牙遥控器的原理 本文源码给予 amlogic 9.0 蓝牙遥控器的原理如下图 从流程上我们可以发现,我们遥控器的码值被转化了几次: HID码值–→Linux event–→ 根据Vendor. ...

  4. android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话

    继续研究hfp相关功能.蓝牙耳机可以控制手机接听.拒接.挂断电话,拨打电话等功能.本文主要分析下起这些操作的大致流程. 在系统应用Bluetooth中com_android_bluetooth.cpp ...

  5. Android Studio开发——蓝牙聊天功能

    Android Studio开发--蓝牙聊天功能 蓝牙工作流程 功能要求 实现要点 声明蓝牙权限 添加程序运行的状态描述文本及配色代码 布局文件 蓝牙会话的服务组件ChatService Activi ...

  6. Android Studio在类微信程序完成“蓝牙聊天功能”实现蓝牙通信

    Android Studio在类微信程序完成"蓝牙聊天功能"实现蓝牙通信 项目运行截图 通信原理 蓝牙权限 strings.xml tab01.xml 菜单文件option_men ...

  7. android 蓝牙锁应用开发实例(三)蓝牙相关功能实现【第一部分】

    本人水平有限,文章中如果出现什么不正确或者模糊的地方,还请各位小伙伴留下评论,多多指教 : ) 正式开始前的话 蓝牙开发梳理 整体思路 核心API BlueToothAdapter 简介 getDef ...

  8. 调用Android自带日历功能(日历列表单、添加一个日历事件)

    调用Android自带日历功能  觉得这篇文章不错,转载过来. 转载:http://blog.csdn.net/djy1992/article/details/9948393 Android手机配备有 ...

  9. Android添加拍照功能,Android开发实现拍照功能的方法实例解析

    本文实例讲述了Android开发实现拍照功能的方法.分享给大家供大家参考,具体如下: 解析: 1)判断是否有摄像头checkCameraHardware(this) 2)获得相机camera = Ca ...

  10. android仿微信发布动态功能,Android GridView扩展仿微信微博发图动态添加删除图片功能.pdf...

    Android GridView扩扩展展仿仿微微信信微微博博发发图图动动态态添添加加删删除除图图片片功功能能 这篇文章主要为大家详细介绍了Android GridView扩展仿微信微博发图动态添加删除 ...

最新文章

  1. 2022-2028年中国数字电视产业投资分析及前景预测报告(全卷)
  2. P2924 [USACO08DEC]大栅栏Largest Fence
  3. 为什么Python中整型不会溢出
  4. (Markdown图片居中)CSDN 验证通过
  5. swift 将图片资源打包成Bundle
  6. 本科毕设研究记录(一)————小样本综述
  7. VARCHART XGantt与活动互动教程指南
  8. kvaser怎么用?Kvaser 汽车CAN通讯协议总线分析仪新手入门常见问题解决方案教程
  9. python中找不到模块_安装完Python包然后找不到模块的解决步骤
  10. 【CCAI大咖秀】李德毅院士:机器人产业需做好交互认知
  11. 中国计算机科学家的艰苦奋斗,中科大校友结束中国无“芯”史摘得北京科技最高奖...
  12. 基础实验8-1.2:直捣黄龙
  13. 【django】HttpRequest对象的属性和路由补充
  14. 抖音不开直播的赚钱方式有哪些
  15. 蓝牙最新版本6.0_手机蓝牙连接汽车放歌。放30秒就没声音了是什么坏了?
  16. 修改 /etc/pam.d/login, linux 本地账号密码无法登陆,一直返回 登陆的login界面
  17. 为什么说内存比硬盘快??
  18. 轻酷宝学院:汽车4S店小程序在线开发教程
  19. 小脑神经网络——CMAC
  20. 微信小程序:全网独家小程序版本独立微信社群人脉

热门文章

  1. 在设备后台安装CAB而不让用户发觉
  2. react-redux中Connect方法
  3. idea spring boot 修改html等不重启即时生效
  4. 常见系统安全漏洞及解决方案
  5. hiveql 没有left()right()函数,可用substr()替代
  6. “ODM OEM OBM的区别”网址汇总
  7. python 头条新闻机器人_使用今日头条web版API实现的头条机器人
  8. 一个小把戏算法,获取大乐透,并且计算出最佳的结果(Qt C++ 和Android共用)
  9. Tensorflow中的数据对象Dataset.shuffle()、repeat()、batch() 等用法
  10. 深度学习中框架中reshape和transpose的区别