android FM JNI library reference native implementation

Refer to the implementation of jni library in FMRadio App under different platforms. This article is based on MTK platform implementation, so refer to vendor\mediatek\proprietary\packages\apps\FMRadio\jni\fmr
.
├── Android.mk
├── common.cpp
├ ── fm.h
├── fmr_core.cpp
├── fmr_err.cpp
├── fmr.h
├── libfm_jni.cpp
├── NOTICE
└── The
first thing README should pay attention to is how the underlying driver controls FM Of course, we will think of the simplest and rude form of directly operating all functional nodes. The actual situation is to encapsulate, and use the ioctl command to execute the familiar powerup, powerdown, tune, seek, mute, etc.

fmr.h, you need to pay attention to the defined ioctl commands directly, here is also a prerequisite, that is, the kernel must implement these for calling
// ********** ** FM IOCTL define start * ******************************
#define FM_IOC_MAGIC 0xf5
#define FM_IOCTL_POWERUP _IOWR(FM_IOC_MAGIC, 0, struct fm_tune_parm
)
#define FM_IOCTL_POWERDOWN _IOWR (FM_IOC_MAGIC,. 1, int32_t
)
#define FM_IOCTL_TUNE _IOWR (FM_IOC_MAGIC, 2, struct fm_tune_parm
)
#define FM_IOCTL_SEEK _IOWR (FM_IOC_MAGIC,. 3, struct fm_seek_parm
)
#define FM_IOCTL_SETVOL _IOWR (FM_IOC_MAGIC,. 4, uint32_t
)
#define FM_IOCTL_GETVOL _IOWR (FM_IOC_MAGIC,. 5 , uint32_t
)
#define FM_IOCTL_MUTE _IOWR(FM_IOC_MAGIC, 6, uint32_t
)
#define FM_IOCTL_GETRSSI _IOWR(FM_IOC_MAGIC, 7, int32_t
)
#define FM_IOCTL_SCAN _IOWR(FM_IOC_MAGIC, 8, struct fm_scan_parm
)
#define FM_IOCTL_STOP_SCAN _IO(FM_IOC_MAGIC, 9)

so independent, easy to make compatible modules with built-in FM, the code calls the basic
structure of the code as follows:
.
├── Android.mk
├── Common.cpp
├── ext_fm.cpp
├── fm.h
├── fmr_core.cpp
└── fmr.h

common.cpp directly encapsulates the interface of the underlying ioctl. The
structure fm_cbk_tbl defines the functions of all ioctl commands that need to be encapsulated

struct fm_cbk_tbl {
    
    
    //Basic functions.
    int (*open_dev)(const char *pname, int *fd);
    int (*close_dev)(int fd);
    int (*pwr_up)(int fd, int band, int freq);
    int (*pwr_down)(int fd, int type);
    int (*seek)(int fd, int *freq, int band, int dir, int lev);
    ...
}

Entry function, pointer to

void FM_interface_init(struct fm_cbk_tbl *cbk_tbl)
{
    
    
    //Basic functions.
    cbk_tbl->open_dev = COM_open_dev_ext;
    cbk_tbl->close_dev = COM_close_dev_ext;
    cbk_tbl->pwr_up = COM_pwr_up_ext;
    cbk_tbl->pwr_down = COM_pwr_down_ext;
    cbk_tbl->tune = COM_tune_ext;
    cbk_tbl->set_mute = COM_set_mute_ext;
    cbk_tbl->seek_all_ext = COM_Seek_all_ext_fm;
...
    return;
}

The specific implementation of a single function. Take the above electricity as an example, FM_IOCTL_POWERUP is the ioctl that has implemented specific functions at the bottom layer

int COM_pwr_up_ext(int fd, int band, int freq)
{
    
    	
	fm_tune_parm parm;
	
	int ret = 0;
	int pwrState = -1;
	parm.band = band;
	parm.freq = freq;
	ret = ioctl(fd, FM_IOCTL_POWERUP, &parm);
	LOGE("%s, ExtFm Externel FM power up \n", __func__);
	if(ret < 0){
    
    
		LOGE("%s, ExtFm Externel FM power up failed\n", __func__);
	}
	return ret;

}

fmr_core.cpp is further encapsulated for jni to call

int FMR_pwr_up(int idx, int freq)
{
    
    
    int ret = 0;

    FMR_ASSERT(FMR_cbk_tbl(idx).pwr_up);

    LOGI("%s,[freq=%d]\n", __func__, freq);
    if (freq < fmr_data.cfg_data.low_band || freq > fmr_data.cfg_data.high_band) {
    
    
        LOGE("%s error freq: %d\n", __func__, freq);
        ret = -ERR_INVALID_PARA;
        return ret;
    }
    ret = FMR_cbk_tbl(idx).pwr_up(FMR_fd(idx), fmr_data.cfg_data.band, freq);
    if (ret < 1) {
    
    
        LOGE("%s failed, [ret=%d]\n", __func__, ret);
    }
    fmr_data.cur_freq = freq;
    LOGD("%s, [ret=%d]\n", __func__, ret);
    return ret;
}

Registration of the ext_fm.cpp jni function to provide a static interface for the upper app java to call

jboolean powerUp(JNIEnv *env, jobject thiz, jfloat freq)
{
    
    
	int ret = 0;
	int tmp_freq;
	UNUSED(env);
	UNUSED(thiz);

	LOGI("%s, [freq=%d]\n", __func__, (int)freq);
	tmp_freq = (int)(freq * 100);		 //Eg, 87.5 * 100 --> 8750
	ret = FMR_pwr_up(g_idx, tmp_freq);

	LOGD(" ExtFm [ret=%d]\n", ret);
	return ret?JNI_FALSE:JNI_TRUE;
}

APP call method

System.loadLibrary("ext_fm_jni");

Note that when packaging the function so, you need to pay attention to the form of the module name of Android.mk must be prefixed with lib, libext_fm_jni, and the final generation must also be libext_fm_jni.so for java to call

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    common.cpp	\
    ext_fm.cpp	\
    fmr_core.cpp	

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
    frameworks/base/include/media

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libdl \
    libmedia \
    liblog

LOCAL_MODULE := libext_fm_jni
LOCAL_CFLAGS += \
    -Wno-error=unused-parameter  \
    -Wno-error=deprecated-register

Newly added ExtFm.java, you can directly refer to the implementation of the source code, the only difference is that it is modified to a public method for calling

package com.android.fmradio;

/**
 * This class define FM native interface, will description FM native interface
 */
public class FmNative {
    
    
    static {
    
    
        System.loadLibrary("fmjni");
    }
...

    /**
     * power up FM with frequency use long antenna
     *
     * @param frequency frequency(50KHZ, 87.55; 100KHZ, 87.5)
     *
     * @return (true, success; false, failed)
     */
    public static native boolean powerUp(float frequency);
...

Guess you like

Origin blog.csdn.net/jeephao/article/details/105615687