Android FM录音功能

最近有个需求,FM需要做听歌识曲,然后我就发现,Andoid原生就提供了一个这个:

//MediaRecorder.java
/**
* Audio source for capturing broadcast radio tuner output.
* @hide
*/
@SystemApi
public static final int RADIO_TUNER = 1998;

​ 那我就要试试,这么操作,会怎么样:

int channelConfiguration = AudioFormat.CHANNEL_IN_STEREO;
            int audioEncodingBits = AudioFormat.ENCODING_PCM_16BIT;
            int sampleRateInHz = 8000;
            int audioSource = MediaRecorder.AudioSource.RADIO_TUNER;
            int recordBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfiguration, audioEncodingBits);
            mAudioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfiguration, audioEncodingBits,
                    recordBufferSize);

结果,我发现报错了:

 //1998就是RADIO_TUNER
 AudioRecord: set(): inputSource 1998, sampleRate 8000, format 0x1, channelMask 0xc, frameCount 320, notificationFrames 0, sessionId 0, transferType 0, flags 0, opPackageName com.chj.voicerecognize.captureservice uid -1, pid -1
10-19 09:05:27.160  2162  2162 V AudioRecord: Building AudioRecord with attributes: source=1998 flags=0x0 tags=[]
10-19 09:05:27.160  2162  2162 V AudioRecord: set(): mSessionId 33
10-19 09:05:27.163   779  1008 V APM_AudioPolicyManager: getInputForAttr() source 1998, samplingRate 8000, format 1, channelMask c,session 33, flags 0                       
10-19 09:05:27.163   779  1008 V APM::AudioPolicyEngine: getDeviceForInputSource() no device found for source 1998
10-19 09:05:27.163   779  1008 E APM::AudioPolicyEngine: getDeviceForInputSource() no default device defined
10-19 09:05:27.163   779  1008 V APM::AudioPolicyEngine: getDeviceForInputSource()input source 1998, device 00000000
10-19 09:05:27.163   779  1008 W APM_AudioPolicyManager: getInputForAttr() could not find device for source 1998

报错的地方在这里:

Engine.cpp
audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
    ...
    case AUDIO_SOURCE_FM_TUNER:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
            //没走到这里
            device = AUDIO_DEVICE_IN_FM_TUNER;
        }
        break;
    ...
}

也就是说availableDeviceTypes里没有包含AUDIO_DEVICE_IN_FM_TUNER。

于是,我查看了配置:

//audio_policy_configuration.xml
...
<attachedDevices>
   ...
   <item>Built-In Micitem>
   <item>Built-In Back Micitem>
   <item>FM Tuneritem>
   ...
...

按理说,他是这样的:

//Serializer.cpp
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                   PtrSerializingCtx ctx)
{
    ...
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("ZDQ %s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp<DeviceDescriptor> device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        //就是这里
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
     ...
}

我加了log打印

void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
    {
        ALOGV("ZDQ addAvailableDevice %0x",availableDevice->type());
        if (audio_is_output_device(availableDevice->type())) {
            ALOGV("is output device");
            mAvailableOutputDevices.add(availableDevice);
        } else if (audio_is_input_device(availableDevice->type())) {
            ALOGV("is in device");
            mAvailableInputDevices.add(availableDevice);
        }
    }

log如下:

01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ deserialize: module item=Built-In Mic
01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ addAvailableDevice 80000004
01-01 11:57:33.145 779 779 V APM::Serializer: is in device
01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ deserialize: module item=Built-In Back Mic
01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ addAvailableDevice 80000080
01-01 11:57:33.145 779 779 V APM::Serializer: is in device
01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ deserialize: module item=FM Tuner
01-01 11:57:33.145 779 779 V APM::Serializer: ZDQ addAvailableDevice 80002000 
01-01 11:57:33.145 779 779 V APM::Serializer: is in device

明明加进去了呀。可是我dumpsys media.audio_policy

- Available input devices:
  Device 1:
  - id: 18
  - tag name: Built-In Mic
  - type: AUDIO_DEVICE_IN_BUILTIN_MIC                     
  - Profiles:
  ...
  Device 2:
  - id: 19
  - tag name: Built-In Back Mic
  - type: AUDIO_DEVICE_IN_BACK_MIC                        
  - Profiles:
      Profile 0:
  ...

就是没有!这可就奇怪了。想了好久好久。。。

后来想到,会不会加进去之后,又被删掉了?

在AudioPolicyManager(真正使用mAvailableInputDevices的地方)搜索了下,果不其然

两个地方:

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    ...
    for (size_t i = 0; i  < mAvailableInputDevices.size();) {
        if (!mAvailableInputDevices[i]->isAttached()) {
            ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->type());
            mAvailableInputDevices.remove(mAvailableInputDevices[i]);
            continue;
        }
        // The device is now validated and can be appended to the available devices of the engine
        mEngine->setDeviceConnectionState(mAvailableInputDevices[i], AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
        i++;
    }
    ...
}

对应的InputDevice没有被加载(细节这里就不展开说了,对应有个so,会被load),会被删掉。

status_t AudioPolicyManager::setDeviceConnectionStateInt()
{
    ...
// handle input device disconnection
        case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
            if (index < 0) {
                return INVALID_OPERATION;
            }
            // Set Disconnect to HALs
            broadcastDeviceConnectionState(device, state, devDesc->mAddress);
            checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress);
            mAvailableInputDevices.remove(devDesc);
            mEngine->setDeviceConnectionState(devDesc, state);
        } break;
    ...
}

状态切换的时候,也会被删掉。。。fm会disconnect?

然后,我不死心,搜索了下AUDIO_DEVICE_IN_FM_TUNER。竟然发现了这个:

//frameworks/base/services/core/jni/BroadcastRadio/Tuner.cpp
static void notifyAudioService(TunerContext& ctx, bool connected) {
    ...
    AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
            connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
            nullptr, kAudioDeviceName);
    ...
}

还真的会有connect的时候。

我有在之前的文章分析过原生Android tunner的机制:

https://blog.csdn.net/bberdong/article/details/81865975

其实hal层相关的东西都是有的!

最终发现

//frameworks/base/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jint moduleId,jobject bandConfig, bool withAudio, jobject callback) {
    ...
    Tuner::assignHalInterfaces(env, tuner, module, halTuner);
    ...
}
//frameworks/base/services/core/jni/BroadcastRadio/Tuner.cpp
void assignHalInterfaces(/*参数省略*/)
{
    ...
        notifyAudioService(ctx, true);
    ...
}

​ 然后,我愉快地打开我们的FM app.发现Available input devices中有FM Tuner了。哈哈!回到最开始的地方,需要先调用nativeOpenTuner,打开收音机模块,我的AudioRecord调用就不会报错了。

​ 然后,改下这两个地方,就能正常录到:

@@ -355,7 +355,7 @@ static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
                                             MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_LINE_IN_PASSTHROUGH] = {-1, -1},
     [USECASE_AUDIO_HDMI_IN_PASSTHROUGH] = {-1, -1},
-
+    [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {AUDIO_RECORD_PCM_DEVICE,AUDIO_RECORD_PCM_DEVICE},
 };

//这里改成自己的配置。比如说我的fm-loopback
     <path name="fm-virtual-record capture-fm">
-        <ctl name="QUAT_TDM_TX_0 Channels" value="One" />
-        <ctl name="MultiMedia2 Mixer QUAT_TDM_TX_0" value="1" />
+        <!--<ctl name="QUAT_TDM_TX_0 Channels" value="One" />
+        <ctl name="MultiMedia2 Mixer QUAT_TDM_TX_0" value="1" />-->
+        <path name="fm-loopback"/>
     </path>

当然,前面的一切,都是基于硬件要支持。。。

你可能感兴趣的:(安卓,Audio)