USB audio调试

2023-10-29

androidstudio打印的信息有如下:

07-12 08:27:17.660 2284-2284/? I/AudioFlinger: loadHwModule() Loaded a2dp audio interface from A2DP Audio HW HAL (audio) handle 7
07-12 08:27:17.660 2284-2284/? I/AudioFlinger: loadHwModule() Loaded usb audio interface from USB audio HW HAL (audio) handle 8
07-12 08:27:17.660 2284-2284/? I/r_submix: adev_open(name=audio_hw_if)
其中的第二行信息就是usb声卡的打印的一条信息。

"frameworks/av/services/audioflinger/AudioFlinger.cpp" 3024 lines --52%--

1573 // loadHwModule_l() must be called with AudioFlinger::mLock held
1574 audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
1575 {
1576     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
1577         if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
1578             ALOGW("loadHwModule() module %s already loaded", name);
1579             return mAudioHwDevs.keyAt(i);
1580         }
1581     }
...

1643     audio_module_handle_t handle = nextUniqueId();
1644     mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
1645 
1646     ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
1647           name, dev->common.module->name, dev->common.module->id, handle);
1648 
1649     return handle;
1650 
1651 }
这条信息的内容是AudioFlinger打印出来的信息。调用的hardware目录下的工具。

<hardware/libhardware/modules/usbaudio/audio_hal.c>
1074 static struct hw_module_methods_t hal_module_methods = {
1075     .open = adev_open,
1076 };
1077 
1078 struct audio_module HAL_MODULE_INFO_SYM = {
1079     .common = {
1080         .tag = HARDWARE_MODULE_TAG,
1081         .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
1082         .hal_api_version = HARDWARE_HAL_API_VERSION,
1083         .id = AUDIO_HARDWARE_MODULE_ID,
1084         .name = "USB audio HW HAL",
1085         .author = "The Android Open Source Project",
1086         .methods = &hal_module_methods,
1087     },
1088 };
打印的信息都在common这个结构体可以找到出处。

id的定义如下:

libhardware/include/hardware/audio.h:39:#define AUDIO_HARDWARE_MODULE_ID "audio"
libhardware/include/hardware/audio.h:44:#define AUDIO_HARDWARE_INTERFACE "audio_hw_if" 
这个open函数如下:



policy文件作用:

gsc@gsc-250:/media/gsc/31269c00-69bd-4eed-814e-bade5758e213/7420_ext/frameworks$ grep -nr "AUDIO_POLICY_CONFIG_FILE"
av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp:2748:        if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
av/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h:26:#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"


1037 static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
1038 {
1039     if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
1040         return -EINVAL;
1041 
1042     struct audio_device *adev = calloc(1, sizeof(struct audio_device));
1043     if (!adev)
1044         return -ENOMEM;
1045 
1046     profile_init(&adev->out_profile, PCM_OUT);
1047     profile_init(&adev->in_profile, PCM_IN);
1048 
1049     adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
1050     adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1051     adev->hw_device.common.module = (struct hw_module_t *)module;
1052     adev->hw_device.common.close = adev_close;
1053 
1054     adev->hw_device.init_check = adev_init_check;
1055     adev->hw_device.set_voice_volume = adev_set_voice_volume;
1056     adev->hw_device.set_master_volume = adev_set_master_volume;
1057     adev->hw_device.set_mode = adev_set_mode;
1058     adev->hw_device.set_mic_mute = adev_set_mic_mute;
1059     adev->hw_device.get_mic_mute = adev_get_mic_mute;
1060     adev->hw_device.set_parameters = adev_set_parameters;
1061     adev->hw_device.get_parameters = adev_get_parameters;
1062     adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
1063     adev->hw_device.open_output_stream = adev_open_output_stream;
1064     adev->hw_device.close_output_stream = adev_close_output_stream;
1065     adev->hw_device.open_input_stream = adev_open_input_stream;
1066     adev->hw_device.close_input_stream = adev_close_input_stream;
1067     adev->hw_device.dump = adev_dump;
1068 
1069     *device = &adev->hw_device.common;
1070 
1071     return 0;
1072 }

该函数提供了其它操作硬件设备的函数。

out_profile定义于<system/media/alsa_utils/include/alsa_device_profile.h>文件。

typedef struct  {
    int card;
    int device;
    int direction; /* PCM_OUT or PCM_IN */

    enum pcm_format formats[MAX_PROFILE_FORMATS];

    unsigned sample_rates[MAX_PROFILE_SAMPLE_RATES];

    unsigned channel_counts[MAX_PROFILE_CHANNEL_COUNTS];

    bool is_valid;

    /* read from the hardware device */
    struct pcm_config default_config;

    unsigned min_period_size;
    unsigned max_period_size;

    unsigned min_channel_count;
    unsigned max_channel_count;
} alsa_device_profile;

在USB的Audio HAL层比较关键的两个函数是adev_open_output_stream和adev_open_input_stream,它们分别对应输出和输入流打开操作。

472 static int adev_open_output_stream(struct audio_hw_device *dev,
 473                                    audio_io_handle_t handle,
 474                                    audio_devices_t devices,
 475                                    audio_output_flags_t flags,
 476                                    struct audio_config *config,
 477                                    struct audio_stream_out **stream_out,
 478                                    const char *address /*__unused*/)
 479 {
 480     ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
 481           handle, devices, flags, address);
 482 
 483     struct audio_device *adev = (struct audio_device *)dev;
 484 
 485     struct stream_out *out;
 486 
 487     out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
 488     if (!out)
 489         return -ENOMEM;
 490 
 491     /* setup function pointers */
 492     out->stream.common.get_sample_rate = out_get_sample_rate;
 493     out->stream.common.set_sample_rate = out_set_sample_rate;
 494     out->stream.common.get_buffer_size = out_get_buffer_size;
 495     out->stream.common.get_channels = out_get_channels;
 496     out->stream.common.get_format = out_get_format;
 497     out->stream.common.set_format = out_set_format;
 498     out->stream.common.standby = out_standby;
 499     out->stream.common.dump = out_dump;
 500     out->stream.common.set_parameters = out_set_parameters;
 501     out->stream.common.get_parameters = out_get_parameters;
 502     out->stream.common.add_audio_effect = out_add_audio_effect;
 503     out->stream.common.remove_audio_effect = out_remove_audio_effect;
 504     out->stream.get_latency = out_get_latency;
 505     out->stream.set_volume = out_set_volume;
 506     out->stream.write = out_write;
 507     out->stream.get_render_position = out_get_render_position;
 508     out->stream.get_presentation_position = out_get_presentation_position;
 509     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
 510 
 511     pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
 512     pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
 513 
 514     out->dev = adev;
 515     pthread_mutex_lock(&adev->lock);
 516     out->profile = &adev->out_profile;
 517 
 518     // build this to hand to the alsa_device_proxy
 519     struct pcm_config proxy_config;
 520     memset(&proxy_config, 0, sizeof(proxy_config));
 521 
 522     /* Pull out the card/device pair */
 523     parse_card_device_params(address, &(out->profile->card), &(out->profile->device));
...
 526 
 527     profile_read_device_info(out->profile);
 528 
 529     pthread_mutex_unlock(&adev->lock);
 530 
 531     int ret = 0;
 532 
 533     /* Rate */
 534     if (config->sample_rate == 0) {
 535         proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
 536     } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
 537         proxy_config.rate = config->sample_rate;
 538     } else {
539         proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
 540         ret = -EINVAL;
 541     }
 542 
 543     /* Format */
 544     if (config->format == AUDIO_FORMAT_DEFAULT) {
 545         proxy_config.format = profile_get_default_format(out->profile);
 546         config->format = audio_format_from_pcm_format(proxy_config.format);
 547     } else {
 548         enum pcm_format fmt = pcm_format_from_audio_format(config->format);
 549         if (profile_is_format_valid(out->profile, fmt)) {
 550             proxy_config.format = fmt;
 551         } else {
 552             proxy_config.format = profile_get_default_format(out->profile);
 553             config->format = audio_format_from_pcm_format(proxy_config.format);
 554             ret = -EINVAL;
 555         }
 556     }
 557 
 558     /* Channels */
 559     unsigned proposed_channel_count = 0;
 560     if (k_force_channels) {
 561         proposed_channel_count = k_force_channels;
 562     } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
 563         proposed_channel_count =  profile_get_default_channel_count(out->profile);
 564     }
 565     if (proposed_channel_count != 0) {
 566         if (proposed_channel_count <= FCC_2) {
 567             // use channel position mask for mono and stereo
 568             config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
 569         } else {
 570             // use channel index mask for multichannel
 571             config->channel_mask =
 572                     audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
 573         }
 574         out->hal_channel_count = proposed_channel_count;
 575     } else {
 576         out->hal_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
 577     }
 578     /* we can expose any channel mask, and emulate internally based on channel count. */
 579     out->hal_channel_mask = config->channel_mask;
 580 
 581     /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
 582      * and we emulate any channel count discrepancies in out_write(). */
 583     proxy_config.channels = proposed_channel_count;
 584 
 585     proxy_prepare(&out->proxy, out->profile, &proxy_config);
 586 
 587     /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
 588     ret = 0;
 589 
 590     out->conversion_buffer = NULL;
 591     out->conversion_buffer_size = 0;
 592 
 593     out->standby = true;
 594 
 595     *stream_out = &out->stream;
 596 
 597     return ret;
...
 603 }                                                                                 
这个函数的整体流程还是比较好理解的,首先为创建的output stream关联一些函数操作集合,操作集包括了采样率/通道数/声音格式等这些信息。并且out_write会调用ALSA接口pcm_write写pcm数据。pcm_config

<external/tinyalsa/include/asoundlib.h> 
88 /* Configuration for a stream */
 89 struct pcm_config {
 90     unsigned int channels;
 91     unsigned int rate;
 92     unsigned int period_size;
 93     unsigned int period_count;
 94     enum pcm_format format;
 95 
 96     /* Values to use for the ALSA start, stop and silence thresholds, and
 97      * silence size.  Setting any one of these values to 0 will cause the
 98      * default tinyalsa values to be used instead.
 99      * Tinyalsa defaults are as follows.
100      *
101      * start_threshold   : period_count * period_size
102      * stop_threshold    : period_count * period_size
103      * silence_threshold : 0
104      * silence_size      : 0
105      */
106     unsigned int start_threshold;
107     unsigned int stop_threshold;
108     unsigned int silence_threshold;
109     unsigned int silence_size;
110 
111     /* Minimum number of frames available before pcm_mmap_write() will actually
112      * write into the kernel buffer. Only used if the stream is opened in mmap mode
113      * (pcm_open() called with PCM_MMAP flag set).   Use 0 for default.
114      */
115     int avail_min;
116 };

如果在初始化出问题,这个函数是需要跟踪。

ndroid 的USB支持已经由谷歌支持的很好了,基本上只需要开启内核的usb,如下图所示:

其所在的路径如下:

make ARCH=arm64 menuconfig

Device Drivers--->
         [*] Sound card support--->
                   [*] Advanced Linux Sound Architecture ---->
                             [*] USB sound devices------------->
                                       [*] USB Audio/MIDI driver        
配置上述的选项后,则在/dev/snd目录会有声卡信息,并且使用tinyplay能够播放wav类型的音乐。接下来就是安卓层的设置了。

如果该系统有外接codec,则对于安卓6.0上层只需要开启USB host即可,但是如果只有usb这么一个声卡,则有些麻烦,因为audio policy会涉及到选择output stream的问题,output stream是有audio_policy.conf文件来指定的,主要来说就是配置文件中的primary和usb这两个声卡的信息填写方法。

usb host的使能方式是:

"device.mk" 587 lines --66%-- 
391 PRODUCT_COPY_FILES += \
392     frameworks/native/data/etc/android.hardware.usb.host.xml:system/etc/permissions/android.hardware.usb.host.xml \
393     frameworks/native/data/etc/android.hardware.camera.xml:system/etc/permissions/android.hardware.camera.xml \
394     frameworks/native/data/etc/android.hardware.camera.front.xml:system/etc/permissions/android.hardware.camera.front.xml \
395     frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml     \
396     frameworks/native/data/etc/android.hardware.camera.autofocus.xml:system/etc/permissions/android.hardware.camera.autofocus.xml \
392行添加usb host权限文件即可,该文件实际上只有一行。device.mk是对应android根目录的device下具体型号设备的device.mk文件。

接着将该文件push到系统中reboot即可生效:

adb push frameworks/native/data/etc/android.hardware.usb.host.xml /system/etc/permissions/

USB的audio设备有两种类型一种是usb device一种是usb accessory,这两种设备的区别在于7420侧的usb所扮演的角色不同。如果7420做host,则其要和一个能做slave的设备连接,则在conf文件中,这样的设备被称为usb device,反之被称为usb accessory。其源码中的定义和说明位置如下:

 604     /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
 605     AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
 606     /* USB host mode: your Android device is a USB host and the dock is a USB device */
 607     AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000,
 608     AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
 609     /* Telephony voice TX path */
 610     AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000,
"system/media/audio/include/system/audio.h" 1446 lines --38%--   
所以在audio_policy.conf文件根据需要配置usb声卡信息;

  usb {
    outputs {
      #usb_accessory {
       # sampling_rates 48000
       # channel_masks AUDIO_CHANNEL_OUT_STEREO
       # formats AUDIO_FORMAT_PCM_16_BIT
       # devices AUDIO_DEVICE_OUT_USB_ACCESSORY
      #}
      usb_device {
        sampling_rates 48000
        channel_masks AUDIO_CHANNEL_OUT_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_USB_DEVICE
      }
    }
  }
在audio_policy.conf文件中还有global_configuration字段,该字段的可以按如下方式填写:
global_configuration {
  #attached_output_devices AUDIO_DEVICE_OUT_USB_ACCESSORY
  #default_output_device   AUDIO_DEVICE_OUT_USB_ACCESSORY
  attached_output_devices AUDIO_DEVICE_OUT_USB_DEVICE
  default_output_device   AUDIO_DEVICE_OUT_USB_DEVICE
  #attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
}

在调试过程中发现了如下错误:

01-01 16:16:14.220 V/AudioPolicyService( 3954): inserting command: 3 at index 0, num commands 0
01-01 16:16:14.220 V/AudioPolicyService( 3954): AudioCommandThread() processing set parameters string card=0;connect=16384;device=0, io 0
01-01 16:16:14.220 V/AudioFlinger( 3954): setParameters(): io 0, keyvalue card=0;connect=16384;device=0, calling pid 3954
01-01 16:16:14.220 V/AudioPolicyService( 3954): AudioCommandThread() going to sleep
01-01 16:16:14.220 V/APM::AudioPolicyManager( 3954): checkOutputForStrategy() strategy 1, moving from output 4 to output 6
01-01 16:16:14.220 V/AudioFlinger( 3954): invalidateStream() stream 0
01-01 16:16:14.220 V/AudioFlinger( 3954): invalidateStream() stream 6
01-01 16:16:14.220 F/APM::AudioPolicyManager( 3954): const TYPE& android::SortedVector<TYPE>::operator[](size_t) const [with TYPE = int; size_t = unsigned int]: index=0 out of range (0)
01-01 16:16:14.220 F/libc    ( 3954): Fatal signal 6 (SIGABRT), code -6 in tid 3954 (mediaserver)
01-01 16:16:14.320 F/DEBUG   ( 2287): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-01 16:16:14.330 W/NativeCrashListener( 2595): Couldn't find ProcessRecord for pid 3954
01-01 16:16:14.320 F/DEBUG   ( 2287): Build fingerprint: 'Android/full_phoenix/phoenix:6.0.1/MMB29T/gsc06080916:eng/dev-keys'
01-01 16:16:14.320 F/DEBUG   ( 2287): Revision: '0'
01-01 16:16:14.320 F/DEBUG   ( 2287): ABI: 'arm'
01-01 16:16:14.320 F/DEBUG   ( 2287): pid: 3954, tid: 3954, name: mediaserver  >>> /system/bin/mediaserver <<<
01-01 16:16:14.320 F/DEBUG   ( 2287): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
01-01 16:16:14.330 F/DEBUG   ( 2287): Abort message: 'const TYPE& android::SortedVector<TYPE>::operator[](size_t) const [with TYPE = int; size_t = unsigned int]: index=0 out of range (0)'
01-01 16:16:14.340 E/DEBUG   ( 2287): AM write failed: Broken pipe
01-01 16:16:14.340 F/DEBUG   ( 2287):     r0 00000000  r1 00000f72  r2 00000006  r3 f72f6b94
01-01 16:16:14.340 F/DEBUG   ( 2287):     r4 f72f6b9c  r5 f72f6b4c  r6 00000000  r7 0000010c
01-01 16:16:14.340 F/DEBUG   ( 2287):     r8 00000000  r9 f63f8014  sl ffbfbea4  fp f63ce750
01-01 16:16:14.350 F/DEBUG   ( 2287):     ip 00000006  sp ffbfb9f0  lr f6dc528d  pc f6dc767c  cpsr 400f0010
01-01 16:16:14.360 F/DEBUG   ( 2287): 
01-01 16:16:14.360 F/DEBUG   ( 2287): backtrace:
01-01 16:16:14.370 F/DEBUG   ( 2287):     #00 pc 0004267c  /system/lib/libc.so (tgkill+12)
01-01 16:16:14.370 F/DEBUG   ( 2287):     #01 pc 00040289  /system/lib/libc.so (pthread_kill+32)
01-01 16:16:14.370 F/DEBUG   ( 2287):     #02 pc 0001c9d3  /system/lib/libc.so (raise+10)
01-01 16:16:14.370 F/DEBUG   ( 2287):     #03 pc 00019c51  /system/lib/libc.so (__libc_android_abort+34)
01-01 16:16:14.370 F/DEBUG   ( 2287):     #04 pc 000174ac  /system/lib/libc.so (abort+4)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #05 pc 00008173  /system/lib/libcutils.so (__android_log_assert+86)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #06 pc 00014d75  /system/lib/libaudiopolicymanagerdefault.so
01-01 16:16:14.380 F/DEBUG   ( 2287):     #07 pc 0001bb95  /system/lib/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::checkOutputForStrategy(android::routing_strategy)+268)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #08 pc 0001bd81  /system/lib/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::checkOutputForAllStrategies()+56)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #09 pc 0001c3c5  /system/lib/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(unsigned int, audio_policy_dev_state_t, char const*, char const*)+1548)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #10 pc 000097df  /system/lib/libaudiopolicyservice.so
01-01 16:16:14.380 F/DEBUG   ( 2287):     #11 pc 0008a981  /system/lib/libmedia.so (android::BnAudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+1164)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #12 pc 00019999  /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+60)
01-01 16:16:14.380 F/DEBUG   ( 2287):     #13 pc 0001ecf9  /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+560)
01-01 16:16:14.390 F/DEBUG   ( 2287):     #14 pc 0001ee51  /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+64)
01-01 16:16:14.390 F/DEBUG   ( 2287):     #15 pc 0001eeb5  /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+48)
01-01 16:16:14.390 F/DEBUG   ( 2287):     #16 pc 00001bbb  /system/bin/mediaserver
01-01 16:16:14.390 F/DEBUG   ( 2287):     #17 pc 00017359  /system/lib/libc.so (__libc_init+44)
01-01 16:16:14.390 F/DEBUG   ( 2287):     #18 pc 00001e0c  /system/bin/mediaserver
01-01 16:16:14.520 E/SurfaceFlinger( 2146): ro.sf.lcd_density must be defined as a build property
这时定位问题就变的比较重要了。

gsc@gsc-250:/media/gsc/31269c00-69bd-4eed-814e-bade5758e213/7420_ext$ prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-addr2line -f -e out/target/product/phoenix/symbols/system/lib/libaudiopolicymanagerdefault.so 0001bb95
_ZN7android18AudioPolicyManager22checkOutputForStrategyENS_16routing_strategyE
/media/gsc/31269c00-69bd-4eed-814e-bade5758e213/7420_ext/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp:3835 (discriminator 1)

临时动态推库调试:

 1906  . build/envsetup.sh 
 1907  lunch
 1908  mmm frameworks/av/services/audiopolicy/
 1909  adb remount
 1910  adb push out/target/product/phoenix/system/lib/libaudiopolicymanagerdefault.so /system/lib/
 1911  adb push out/target/product/phoenix/system/lib64/libaudiopolicymanagerdefault.so /system/lib64/
 1912  adb push out/target/product/phoenix/system/lib64/libaudiopolicyservice.so /system/lib64/
 1913  adb push out/target/product/phoenix/system/lib/libaudiopolicyservice.so /system/lib/
 1926  mmm frameworks/av/services/audiopolicy/
 1927  adb remount
 1928  adb push out/target/product/phoenix/system/lib64/libaudiopolicyenginedefault.so /system/lib64/
 1929  adb push out/target/product/phoenix/system/lib/libaudiopolicyenginedefault.so /system/lib/

 1954  mmm frameworks/av/services/audiopolicy/enginedefault/
 1955  adb push audio_policy.conf /system/etc/
 1956  adb push out/target/product/phoenix/system/lib64/libaudiopolicyenginedefault.so /system/lib64/
 1957  adb push out/target/product/phoenix/system/lib/libaudiopolicyenginedefault.so /system/lib/

 1960  mmm hardware/libhardware/modules/usbaudio/
 1961  mmm frameworks/av/services/audiopolicy/
 1962  adb remount
 1963  adb push out/target/product/phoenix/system/lib/hw/audio.usb.default.so /system/lib/
 1964  adb push out/target/product/phoenix/system/lib64/hw/audio.usb.default.so /system/lib64/hw/
 1965  adb push out/target/product/phoenix/system/lib/hw/audio.usb.default.so /system/lib/hw/
 1966  adb push out/target/product/phoenix/system/lib/libaudiopolicymanagerdefault.so /system/lib/
 1967  adb push out/target/product/phoenix/system/lib64/libaudiopolicymanagerdefault.so /system/lib64/
 1968  adb reboot
 1969  mmm hardware/libhardware/modules/usbaudio/
 1970  adb remount
 1971  adb push out/target/product/phoenix/system/lib/hw/audio.usb.default.so /system/lib/hw/
 1972  adb push out/target/product/phoenix/system/lib64/hw/audio.usb.default.so /system/lib64/hw/
 1973  adb reboot

一点有用的代码分析

class AudioPolicyManager:<frameworks/av/services/audiopolicy/manager/default/AudioPolicyManager.h>

     class AudioPolicyInterface: <frameworks/av/services/audiopolicy/AudioPolicyInterface.h>

    class AudioPolicyManagerObserver

    

AudioPolicyService创建:
<frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp>
在所有实际的操作前其会调用void AudioPolicyService::onFirstRef()
该函数调用了hardware层一些函数,也引用了hardware层一些函数,其定义在如下的函数中。
./hardware/libhardware/include/hardware/hardware.h

84行,未定义USE_LEGACY_AUDIO_POLICY,执行else语句分支。
114行~115行:

mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);

<AudioPolicyService.h>

AudioPolicyInterface *mAudioPolicyManager;
AudioPolicyClient *mAudioPolicyClient;

<frameworks/av/services/audiopolicy/AudioPolicyInterface.h>
336~337行如下代码:

​extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface);

上述函数的实现位置是

<./frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp>

 21 extern "C" AudioPolicyInterface* createAudioPolicyManager(
 22         AudioPolicyClientInterface *clientInterface)
 23 {
 24     return new AudioPolicyManager(clientInterface);
 25 }​​

AudioPolicyManager函数定义在<frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp>

 2712 AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
2713     :
2714 #ifdef AUDIO_POLICY_TEST
2715     Thread(false),
2716 #endif //AUDIO_POLICY_TEST
2717     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
2718     mA2dpSuspended(false),
2719     mSpeakerDrcEnabled(false),
2720     mAudioPortGeneration(1),
2721     mBeaconMuteRefCount(0),
2722     mBeaconPlayingRefCount(0),
2723     mBeaconMuted(false),
2724     mTtsOutputAvailable(false)
2725 {
2726     audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
2727     if (!engineInstance) {
2728         ALOGE("%s:  Could not get an instance of policy engine", __FUNCTION__);
2729         return;
2730     }
2731     // Retrieve the Policy Manager Interface
2732     mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
2733     if (mEngine == NULL) {
2734         ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
2735         return;
2736     }
2737     mEngine->setObserver(this);
2738     status_t status = mEngine->initCheck();
2739     ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
2740 
2741     mUidCached = getuid();
2742     mpClientInterface = clientInterface;
2743 
2744     mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
2745     if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
2746                  mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
2747                  mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
2748         if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
2749                                   mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
2750                                   mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
2751             ALOGE("could not load audio policy configuration file, setting defaults");
2752             defaultAudioPolicyConfig();
2753         }
2754     }
2755     // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
2756 
2757     // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
2758     mEngine->initializeVolumeCurves(mSpeakerDrcEnabled);
2759 
2760     // open all output streams needed to access attached devices
2761     audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
2762     audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
2763     for (size_t i = 0; i < mHwModules.size(); i++) {
2764         mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
2765         if (mHwModules[i]->mHandle == 0) {
2766             ALOGW("could not open HW module %s", mHwModules[i]->mName);
2767             continue;
2768         }
2769         // open all output streams needed to access attached devices
2770         // except for direct output streams that are only opened when they are actually
2771         // required by an app.
2772         // This also validates mAvailableOutputDevices list
2773         for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
2774         {
2775             const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
。。。
2813             status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(),
2814                                                             &output,
2815                                                             &config,
2816                                                             &outputDesc->mDevice,
2817                                                             String8(""),
2818                                                             &outputDesc->mLatency,
2819                                                             outputDesc->mFlags);
2820 
2821             if (status != NO_ERROR) {
2822                 ALOGW("Cannot open output stream for device %08x on hw module %s",
2823                       outputDesc->mDevice,
2824                       mHwModules[i]->mName);
2825             } else {
2826                 outputDesc->mSamplingRate = config.sample_rate;
2827                 outputDesc->mChannelMask = config.channel_mask;
2828                 outputDesc->mFormat = config.format;
2829 
2830                 for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
2831                     audio_devices_t type = outProfile->mSupportedDevices[k]->type();
2832                     ssize_t index =
2833                             mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
2834                     // give a valid ID to an attached device once confirmed it is reachable
2835                     if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
2836                         mAvailableOutputDevices[index]->attach(mHwModules[i]);
2837                     }
2838                 }
2839                 if (mPrimaryOutput == 0 &&
2840                         outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
2841                     mPrimaryOutput = outputDesc;
2842                 }
2843                 addOutput(output, outputDesc);

2844                 setOutputDevice(outputDesc,
2845                                 outputDesc->mDevice,
2846                                 true);
2847             }
2848         }
2849         // open input streams needed to access attached devices to validate
2850         // mAvailableInputDevices list
2851         for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
2852         {
2853             const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
2854 
2855             if (inProfile->mSupportedDevices.isEmpty()) {
2856                 ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
2857                 continue;
2858             }
2859             // chose first device present in mSupportedDevices also part of
2860             // inputDeviceTypes
2861             audio_devices_t profileType = AUDIO_DEVICE_NONE;
2862             for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
2863                 profileType = inProfile->mSupportedDevices[k]->type();
2864                 if (profileType & inputDeviceTypes) {
2865                     break;
2866                 }
2867             }
2868             if ((profileType & inputDeviceTypes) == 0) {
2869                 continue;
2870             }
2871             sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
2872 
2873             inputDesc->mInputSource = AUDIO_SOURCE_MIC;
2874             inputDesc->mDevice = profileType;
2875 
2876             // find the address
2877             DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
2878             //   the inputs vector must be of size 1, but we don't want to crash here
2879             String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
2880                     : String8("");
2881             ALOGV("  for input device 0x%x using address %s", profileType, address.string());
2882             ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");
2883 
2884             audio_config_t config = AUDIO_CONFIG_INITIALIZER;
2885             config.sample_rate = inputDesc->mSamplingRate;
2886             config.channel_mask = inputDesc->mChannelMask;
2887             config.format = inputDesc->mFormat;
2888             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
2889             status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(),
2890                                                            &input,
2891                                                            &config,
2892                                                            &inputDesc->mDevice,
2893                                                            address,
2894                                                            AUDIO_SOURCE_MIC,
2895                                                            AUDIO_INPUT_FLAG_NONE);
2896 
2897             if (status == NO_ERROR) {
2898                 for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
2899                     audio_devices_t type = inProfile->mSupportedDevices[k]->type();
2900                     ssize_t index =
2901                             mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
2902                     // give a valid ID to an attached device once confirmed it is reachable
2903                     if (index >= 0) {
2904                         sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
2905                         if (!devDesc->isAttached()) {
2906                             devDesc->attach(mHwModules[i]);
2907                             devDesc->importAudioPort(inProfile);
2908                         }
2909                     }
2910                 }
2911                 mpClientInterface->closeInput(input);
2912             } else {
2913                 ALOGW("Cannot open input stream for device %08x on hw module %s",
2914                       inputDesc->mDevice,
2915                       mHwModules[i]->mName);
2916             }
2917         }
2918     }
2919     // make sure all attached devices have been allocated a unique ID
2920     for (size_t i = 0; i  < mAvailableOutputDevices.size();) {
2921         if (!mAvailableOutputDevices[i]->isAttached()) {
2922             ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->type());
2923             mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
2924             continue;
2925         }
2926         // The device is now validated and can be appended to the available devices of the engine
2927         mEngine->setDeviceConnectionState(mAvailableOutputDevices[i],
2928                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
2929         i++;
2930     }
2931     for (size_t i = 0; i  < mAvailableInputDevices.size();) {
2932         if (!mAvailableInputDevices[i]->isAttached()) {
2933             ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->type());
2934             mAvailableInputDevices.remove(mAvailableInputDevices[i]);
2935             continue;
2936         }
2937         // The device is now validated and can be appended to the available devices of the engine
2938         mEngine->setDeviceConnectionState(mAvailableInputDevices[i],
2939                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
2940         i++;
2941     }
2942     // make sure default device is reachable
2943     if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
2944         ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
2945     }
2946 
2947     ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
2948 
2949     updateDevicesAndOutputs();
2950 
2951 #ifdef AUDIO_POLICY_TEST
2952     if (mPrimaryOutput != 0) {
2953         AudioParameter outputCmd = AudioParameter();
2954         outputCmd.addInt(String8("set_id"), 0);
2955         mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, outputCmd.toString());
2956 
2957         mTestDevice = AUDIO_DEVICE_OUT_SPEAKER;
2958         mTestSamplingRate = 44100;
2959         mTestFormat = AUDIO_FORMAT_PCM_16_BIT;
2960         mTestChannels =  AUDIO_CHANNEL_OUT_STEREO;
2961         mTestLatencyMs = 0;
2962         mCurOutput = 0;
2963         mDirectOutput = false;
2964         for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
2965             mTestOutputs[i] = 0;
2966         }
2967 
2968         const size_t SIZE = 256;
2969         char buffer[SIZE];
2970         snprintf(buffer, SIZE, "AudioPolicyManagerTest");
2971         run(buffer, ANDROID_PRIORITY_AUDIO);
2972     }
2973 #endif //AUDIO_POLICY_TEST
2974 }
2748行会解析/system/etc/audio_policy.conf配置文件,这是在找不到vendor定义的配置文件后的执行动作。

经过这个解析后,mAvailableOutputDevices和mAvailableInputDevices包括了所有的输出和输入设备。

2763行针对每一个设备进行加载。

2764行加载Hwmodule。

<frameworks/av/services/audioplolicy/AudioPolicyInterface.h>

class  ​ AudioPolicyClientInterface {
...
// loads a HW module.
    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
...
}

<./frameworks/av/services/audioflinger/AudioFlinger.cpp>

 ​1561 audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
1562 {
1563     if (name == NULL) {
1564         return 0;
1565     }
1566     if (!settingsAllowed()) {
1567         return 0;
1568     }
1569     Mutex::Autolock _l(mLock);
1570     return loadHwModule_l(name);
1571 }
1572 
1573 // loadHwModule_l() must be called with AudioFlinger::mLock held
1574 audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
1575 {
...
1583     audio_hw_device_t *dev;
1584 
1585     int rc = load_audio_interface(name, &dev);


1643     audio_module_handle_t handle = nextUniqueId();
1644     mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));

1649     return handle;
}

load_audio_interface也定义在AudioFlinger函数里的定义如下:

 
140 static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
 141 {
 142     const hw_module_t *mod;
 143     int rc;
 144 
 145     rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);

 151     rc = audio_hw_device_open(mod, dev);

 167 }

145行查看这类型的hw module是否存在,如果存在则会调用151行的open函数打开设备。

<./hardware/libhardware/include/hardware/audio.h>

 ​680 static inline int audio_hw_device_open(const struct hw_module_t* module,
681                                        struct audio_hw_device** device)
682 {
683     return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,
684                                  (struct hw_device_t**)device);
685 }

实际上的open函数定义于具体声卡类型的文件中,针对与usb audio设备,其定义于

<hardware/libhardware/modules/usbaudio/audio_hal.c>

 ​1076 static struct hw_module_methods_t hal_module_methods = {
1077     .open = adev_open,
1078 };
1079 
1080 struct audio_module HAL_MODULE_INFO_SYM = {
1081     .common = {
1082         .tag = HARDWARE_MODULE_TAG,
1083         .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
1084         .hal_api_version = HARDWARE_HAL_API_VERSION,
1085         .id = AUDIO_HARDWARE_MODULE_ID,
1086         .name = "USB audio HW HAL",
1087         .author = "The Android Open Source Project",
1088         .methods = &hal_module_methods,
1089     },
1090 };

不出意外,这个open应该是成功的。接着打开流程loadHwModule的1644行。创建了一个硬件设备。该类的构造函数如下:

 ​    AudioHwDevice(audio_module_handle_t handle,
                  const char *moduleName,
                  audio_hw_device_t *hwDevice,
                  Flags flags)
        : mHandle(handle)
        , mModuleName(strdup(moduleName))
        , mHwDevice(hwDevice)
        , mFlags(flags) { }

设备打开和添加的操作是完成了,接下来是打开对应的stream。AudioPolicyManager的2773行。

<./frameworks/av/services/audioflinger/AudioFlinger.cpp>

1775 sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
1776                                                             audio_io_handle_t *output,
1777                                                             audio_config_t *config,
1778                                                             audio_devices_t devices,
1779                                                             const String8& address,
1780                                                             audio_output_flags_t flags)
1781 {
1782     AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
1787     audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
1816     status_t status = outHwDev->openOutputStream(
1817             &outputStream,
1818             *output,
1819             devices,
1820             flags,
1821             config,
1822             address.string());
...
}
​1848 status_t AudioFlinger::openOutput(audio_module_handle_t module,
1849                                   audio_io_handle_t *output,
1850                                   audio_config_t *config,
1851                                   audio_devices_t *devices,
1852                                   const String8& address,
1853                                   uint32_t *latencyMs,
1854                                   audio_output_flags_t flags)
1855 {
1870     sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags);
关键函数是1816行,打开stream。

<./frameworks/av/services/audioflinger/AudioHwDevice.cpp>

 34 status_t AudioHwDevice::openOutputStream(
 35         AudioStreamOut **ppStreamOut,
 36         audio_io_handle_t handle,
 37         audio_devices_t devices,
 38         audio_output_flags_t flags,
 39         struct audio_config *config,
 40         const char *address)
 41 {
​ 
 44     AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
status_t status = outputStream->open(handle, devices, config, address);
AudioStreamOut类的作用是管理对HAL层output Stream的操作。

<./frameworks/av/services/audioflinger/AudioStreamOut.cpp>

112 status_t AudioStreamOut::open(
113         audio_io_handle_t handle,
114         audio_devices_t devices,
115         struct audio_config *config,
116         const char *address)
117 {
118     audio_stream_out_t *outStream;
119     int status = hwDev()->open_output_stream(
120             hwDev(),
121             handle,
122             devices,
123             flags,
124             config,
125             &outStream,
126             address);
127     ALOGV("AudioStreamOut::open(), HAL open_output_stream returned "
128             " %p, sampleRate %d, Format %#x, "
129             "channelMask %#x, status %d",
130             outStream,
131             config->sample_rate,
132             config->format,
133             config->channel_mask,
134             status);
135 
136     if (status == NO_ERROR) {
137         stream = outStream;
138         mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
139         ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
140         mHalFrameSize = audio_stream_out_frame_size(stream);
141     }
142 
143     return status;
144 }

AudioStreamOut.cpp文件里的绝大多数函数是调用HAL层代码完成其工作的。

上面的函数119行调用hardware/libhardware/modules/usbaudio/audio_hal.c的adev_open_output_stream完成实际的打开动作。

engin函数会对设备的类型和config参数进行相应的设置。

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

USB audio调试 的相关文章

  • 使用 Android 前台服务为 MediaPlayer 创建通知

    问题就在这里 我目前正在开发一个应用程序 该应用程序必须提供 A 广播播放器 来自 URL 的 AAC 直播 还有一个播客播放器 来自 URL 的 MP3 流 该应用程序必须能够在后台运行 Android 服务 并通过以下方式向用户公开持续
  • 与 Admob 广告单元 ID 混淆

    我跟着tutorial https developers google com admob android quick start在我的应用程序中创建广告横幅 到目前为止 这有效 我可以看到测试广告 但是 本教程指示我在两个不同的位置使用两
  • 如何更新 Firebase 中的节点密钥?

    如何重命名14 04 2017 node 没有用于重命名节点的 API 您必须获取节点的值 使用新名称将其保存到数据库并删除旧节点
  • 菜单未显示在应用程序中

    由于某种原因 我的操作菜单在我的 Android Studio 应用程序中消失了 我正在按照教程学习如何创建 Android 应用程序 但最终遇到了这个问题 我正在使用 atm 的教程 http www raywenderlich com
  • 设置从 Facebook 登录获取用户电子邮件 ID 的权限

    我在用着Facebook 3 0 SDK对于安卓 我必须实施Facebook登录 我正在访问用户的基本信息 例如姓名 用户 ID 但我也想访问用户的电子邮件 我浏览了很多博客和论坛 但不知道该怎么做 我正在使用我自己的 android 按钮
  • 如果我们使用后退按钮退出,为什么 Android 应用程序会重新启动?

    按住主页按钮并返回应用程序时 应用程序不会重新启动 为什么使用后退按钮会重新启动 如果我们使用后退按钮退出 有什么方法可以解决在不重新启动的情况下获取应用程序的问题吗 请帮忙 当您按下Home按钮 应用程序将暂停并保存当前状态 最后应用程序
  • Android 原理图内容提供程序库配置?

    Jake Wharton 在最近的一次演讲中提到了这个库 它看起来是避免大量样板文件的好方法 所以我尝试了一下 但没有任何成功 https github com SimonVT schematic https github com Simo
  • CookieManager.getInstance().removeAllCookie();不删除所有cookie

    我在应用程序的 onCreate 中调用 CookieManager getInstance removeAllCookie 我遇到了一个奇怪的问题 我看到 GET 请求中传递了意外的 cookie 值 事实上 cookie 值是一个非常非
  • 从 android 简单上传到 S3

    我在网上搜索了从 android 上传简单文件到 s3 的方法 但找不到任何有效的方法 我认为这是因为缺乏具体步骤 1 https mobile awsblog com post Tx1V588RKX5XPQB TransferManage
  • Android相机意图:如何获取全尺寸照片?

    我正在使用意图来启动相机 Intent cameraIntent new Intent android provider MediaStore ACTION IMAGE CAPTURE getParent startActivityForR
  • 如何将设备连接到Eclipse?

    我无法解决这个简单的问题 我正在尝试通过 USB 电缆将我的设备连接到 Eclipse 在我的 PC 上 我已经安装了 Eclipse 和 Android SDK 并且在模拟器上运行该程序运行良好 我已在我的电脑上下载并安装了 Samsun
  • 通过 ADB 拔出设备:“找不到服务”

    我必须测试我的应用程序在打瞌睡模式下的行为 根据文档 https developer android com training monitoring device state doze standby html testing doze 我
  • 当手机旋转(方向改变)时如何最好地重新创建标记/折线

    背景 开发一个使用 Android Google Map v2 的本机 Android 应用程序 使用android support v4 app FragmentActivity 在 Android v2 2 上运行 客观的 在更改手机方
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • SharedFlow 和 StateFlow 的主要区别

    两者有什么区别共享流 and 状态流 以及如何使用这些MVI建筑学 使用简单更好吗Flow或者这些作为状态和事件 Flow 是冷的 意味着它仅在收集数据时才发出数据 另外Flow不能保存数据 可以把它看成是水在里面流动的管道 Flow中的数
  • Android:有没有办法以毫安为单位获取设备的电池容量?

    我想获取设备的电池容量来进行一些电池消耗计算 是否可以以某种方式获取它 例如 三星 Galaxy Note 2 的电池容量为 3100mAh 谢谢你的帮助 知道了 在 SDK 中无法直接找到任何内容 但可以使用反射来完成 这是工作代码 pu
  • 用于推送通知的设备令牌

    我正在实施推送通知服务 我需要创建一个数据库来存储 4 个移动平台的所有设备令牌 我想根据他们的平台 iOS Android BlackBerry WP7 来组织它们 但是有什么方法可以区分平台 这样如果我只想向 Android 用户发送消
  • android Accessibility-service 突然停止触发事件

    我有一个 AccessibilityService 工作正常 但由于开发过程中的某些原因它停止工作 我似乎找不到这个原因 请看一下我的代码并告诉我为什么它不起作用 public class MyServicee extends Access
  • 无法将 admob 与 firebase iOS/Android 项目链接

    我有两个帐户 A 和 B A 是在 Firebase 上托管 iOS Android unity 手机游戏的主帐户 B 用于将 admob 集成到 iOS Android 手机游戏中 我在尝试将 admob 分析链接到 Firebase 项
  • 在 Google 地图上绘制线条/路径

    我很长一段时间都在忙于寻找如何在 HelloMapView 中的地图上的两个 GPS 点之间画一条线 但没有运气 谁能告诉我该怎么做 假设我使用扩展 MapView 的 HelloMapView 我需要使用叠加层吗 如果是这样 我是否必须重

随机推荐

  • 全国程序员收入大调查,粒度到省

    2019年五一假期 我没休息 而是统计某招聘网站了全国的程序员工资 总体统计 2019年4月全国招收程序员302303人 2019年4月全国程序员平均工资12807元 工资中位数11500元 其中95 的人的工资介于3750元到32500元
  • (python算法)LeetCode-版本号比较

    第一次笔试 发挥的很糟糕 基础不好是硬伤 碰到了版本号比较这个问题 回来后搜了下 发现在LeetCode里有 正好再仔细研究下 以下是原题 比较两个版本号 version1 和 version2 如果 version1 gt version
  • python怎么一步步调试_PyCharm入门第一步(二)——调试第一个Python应用程序

    第2步 调试您的第一个Python应用程序 找出问题的根源 PyCharm报告运行时错误 a ZeroDivisionError 深入研究一下代码 找出问题所在 这里可以使用PyCharm调试器来查看代码中发生了什么 要开始调试 您必须先设
  • 【珍藏版】 2012Java开发工程师必备精品资料(115个)

    Java应用广泛 涉及个人PC 数据中心 游戏控制台 科学超级计算机 移动电话和互联网等领域 同时拥有全球最大的开发者专业社群 小弟精心整理了115个精品资料 包括11个Java开发专题和104个热门资源 网上的资料众多 参差不齐 然而这批
  • PHPBONE使用问题集--.Net直接POST数据被过滤

    当 NET用POST发送数据到服务端时 发现 加号全被过滤成空格了 以为是PHPBONE的问题 查了半天代码也没发现哪有异常 但是以前也遇到过 也的确是处理过 只是不记得是怎么处理的了 无耐翻出以前的程序查找了一番 结果发现是编码问题 把数
  • 2021-07-18

    JQuery之DOM操作 1 创建节点及结点属性 1 DOM创建节点及结点属性 创建流程比较简单 大体如下 创建节点 常见的 元素 属性和文本 添加节点的一些属性 加入到文档中 流程中涉及的一点方法 创建元素 document create
  • 哲学家问题(死锁问题)

    1 问题描述 有五个哲学家绕着圆桌坐 每个哲学家面前有一盘面 两人之间有一支筷子 这样每个哲学家左右各有一支筷子 哲学家有2个状态 思考或者拿起筷子吃饭 如果哲学家拿到一只筷子 不能吃饭 直到拿到2只才能吃饭 并且一次只能拿起身边的一支筷子
  • git从某个分支创建新分支

    如题 记录一下从某个分支创建新分支的方法 如从dev分支创建一个test分支 第一步 切换到你指定的分支 如我要从dev上拉一个分支 代码一模一样 git checkout dev 第二步 拉取dev的最新代码 git pull 第三步 在
  • Android Bitmap加载内存占用彻底分析

    背景 在某个版本应用上线后 偶然测得首页占用的内存非常的大而且一直不能回收掉 经过一轮的排查后最终确定是3张图片引起的 当时每张图片占用了将近20m内存 当时紧急处理好后还一直惦记着此事 后来对Android加载Bitmap的内存占用作了彻
  • Android系统源代码的下载与编译

    http www jianshu com p aeaceda41798
  • UVa 12955 Factorial

    Problem uva onlinejudge org index php option com onlinejudge Itemid 8 page show problem problem 4834 开始想多了 想着不能简单贪心 要用dp
  • C# Task异步编程

    Task任务用法 Task用的是线程池 线程池的线程数量的有上限的 这个可以通过ThreadPool修改 我们经常会用到task run new task 和task factory startnew方法来创建任务 Task Factory
  • 检查HDFS块状态

    hadoop集群运行过程中 节点的块状态或者上下线节点时集群都会受影响 如何查看当前的hdfs的块的状态 hadoop1 x时候的命令 hadoop2 x也可使用 hadoop fsck 在hadoop2 0之后 可以使用新命令 hdfs
  • 关于 JavaScript 中的 Promises

    在 JavaScript 中 Promise 是一个对象 它表示一个可能还不可用 但会在未来解决的值 Promises 用于处理异步操作 例如发出网络请求或访问数据库 其中结果不是立即可用的 如果你准备好了 我想开始我们的冒险 承诺如何运作
  • vc2010中开始执行不调试灰的_Intellij IDEA调试功能使用总结

    这段时间一直在使用Intellij IDEA 今天把调试区工具的使用方法记录于此 先编译好要调试的程序 1 设置断点 选定要设置断点的代码行 在行号的区域后面单击鼠标左键即可 2 开启调试会话 点击红色箭头指向的小虫子 开始进入调试 IDE
  • 快速傅里叶变换(FFT)

    前言 在学习FFT过程中看了很多博客 但发现在看博客的时候博客上的内容大多都晦涩难懂 于是乎想自己写一篇博客来记录一下自己学习的心得体会 知其源 先来讲讲FFT的起源 快速傅里叶变换是1965年由J W 库利和T W 图基提出的 采用这种算
  • 微服务项目之JVM Thread线程数飙升

    查找步骤如下 1 找到使用的jdk 在下面找到bin目录 之后双击bin目录下jvisualvm exe 2 启动本地项目 按照上图就可以监控线程数变化 如果项目部署在远程服务器上 那么则需要添加远程监控 选中远程 gt 右键添加远程主机
  • 目标检测跟踪算法--传统方法

    第一阶段 目标跟踪分为两个部分 一个是对指定目标寻找可以跟踪的特征 常用的有颜色 轮廓 特征点 轨迹等 另一个是对目标特征进行跟踪 1 静态背景 1 背景差 对背景的光照变化 噪声干扰以及周期性运动等进行建模 通过当前帧减去背景图来捕获运动
  • python使用hash256加密验证字符串

    这篇博客使用hash256加密一个固定的字符串 同一个字符串有固定的hash256 因此可以通过验证hash值 判断字符串是否发生变化 import hashlib def get hash256 data str 对data加密 hash
  • USB audio调试

    androidstudio打印的信息有如下 07 12 08 27 17 660 2284 2284 I AudioFlinger loadHwModule Loaded a2dp audio interface from A2DP Aud