【Android源码分析】理一理Radio(Tunner)BandConfig

前言
上篇文章讲解到Radio创建过程 https://blog.csdn.net/xuqiang918/article/details/80065145
这篇文章继续分析下Radio在创建过程中传递的BandConfig参数获取过程
1 入口
回到函数 openRadioBandInternal中可以看到 config 在每次调用 openTuner 时候都会去获取一次当前band配置信息
------------------------------------------------------------------------------------------------------------------------------------------
RadioManager.BandConfig config = getRadioConfig(radioBand);
if (config == null ) {
Log. w ( TAG , "Cannot create config for radio band: " + radioBand) ;
return RadioManager. STATUS_ERROR ;
}
Log. e ( "Radio" , "[RadioService] openRadioBandInternal " + config) ;
if ( mRadioTuner != null ) {
mRadioTuner .setConfiguration(config) ;
} else {
mRadioTuner = mRadioManager.openTuner(mModules.get(0).getId(), config, true,
mInternalRadioTunerCallback, null /* handler */);
}
------------------------------------------------------------------------------------------------------------------------------------------
2.跟踪 getRadioConfig函数
------------------------------------------------------------------------------------------------------------------------------------------
/**
* Returns the proper { @link android.hardware.radio.RadioManager.BandConfig} for the given
* radio band. { @code null} is returned if the band is not suppored.
*/
@Nullable
private RadioManager.BandConfig getRadioConfig ( int selectedRadioBand) {
switch (selectedRadioBand) {
case RadioManager. BAND_AM :
return mAmConfig ;
case RadioManager. BAND_FM :
return mFmConfig ;
// TODO: Support BAND_FM_HD and BAND_AM_HD.
default :
return null;
}
}
发现config来自于JAVA中保存的两个变量 mAmConfig mFmConfig;
继续跟踪mAmConfig和mFmConfig变量发现他们都来自于 initialze 函数中程序第一次初始化或者resume调用
------------------------------------------------------------------------------------------------------------------------------------------
3.跟踪initialze() 函数
/**
* Connects to the { @link RadioManager}.
*/
private void initialze () {
Log. d ( TAG , " initialze ..." ) ;
mRadioManager = (RadioManager) getSystemService(Context.RADIO_SERVICE) ;

if (Log. isLoggable ( TAG , Log. DEBUG )) {
Log. d ( TAG , "initialze(); mRadioManager: " + mRadioManager ) ;
}
if ( mRadioManager == null ) {
Log. w ( TAG , "RadioManager could not be loaded." ) ;
return;
}
int status = mRadioManager.listModules(mModules);
if (status != RadioManager. STATUS_OK ) {
Log. w ( TAG , "Load modules failed with status: " + status) ;
return;
}
if (Log. isLoggable ( TAG , Log. DEBUG )) {
Log. d ( TAG , "initialze(); listModules complete: " + mModules ) ;
}
if ( mModules .size() == 0 ) {
Log. w ( TAG , "No radio modules on device." ) ;
return;
}
boolean isDebugLoggable = Log. isLoggable ( TAG , Log. DEBUG ) ;
// Load the possible radio bands. For now, just accept FM and AM bands.
for (BandDescriptor band : mModules .get( 0 ).getBands()) {
//if (isDebugLoggable) {
Log. d ( TAG , "loading band: " + band.toString()) ;
//}
if ( mFmDescriptor == null && band.getType() == RadioManager. BAND_FM ) {
mFmDescriptor = (RadioManager.FmBandDescriptor) band ;
}
if ( mAmDescriptor == null && band.getType() == RadioManager. BAND_AM ) {
mAmDescriptor = (RadioManager.AmBandDescriptor) band ;
}
}
if ( mFmDescriptor == null && mAmDescriptor == null ) {
Log. w ( TAG , "No AM and FM radio bands could be loaded." ) ;
return;
}
// TODO: Make stereo configurable depending on device.
mFmConfig = new RadioManager.FmBandConfig.Builder( mFmDescriptor )
.setStereo( true )
.build() ;
mAmConfig = new RadioManager.AmBandConfig.Builder( mAmDescriptor )
.setStereo( true )
.build() ;
// If there is a second tuner on the device, then set it up as the background scanner.
if ( mModules .size() >= 2 ) {
if (isDebugLoggable) {
Log. d ( TAG , "Second tuner detected on device; setting up background scanner" ) ;
}
}
mRadioSuccessfullyInitialized = true;
}
说明:最终发现他们来自 RadioManager类中的 JNI函数listModules
class RadioManager {
public native int listModules(List<RadioManager.ModuleProperties> var1) ;
...
};
JNI声明:
static JNINativeMethod gMethods[] = {
{" listModules",
"(Ljava/util/List;)I",
(void *)android_hardware_Radio_listModules},
{"isSounding",
"()Z",
(void *)android_hardware_Radio_isSounding},
};
JNI实现:
static jint
android_hardware_Radio_listModules(JNIEnv *env, jobject clazz,
jobject jModules)
{
ALOGV("%s", __FUNCTION__);

if (jModules == NULL) {
ALOGE("listModules NULL ArrayList");
return RADIO_STATUS_BAD_VALUE;
}
if (!env->IsInstanceOf(jModules, gArrayListClass)) {
ALOGE("listModules not an arraylist");
return RADIO_STATUS_BAD_VALUE;
}

unsigned int numModules = 0;
radio_properties_t *nModules = NULL;

status_t status = Radio::listModules(nModules, &numModules); //
if (status != NO_ERROR || numModules == 0) {
return (jint)status;
}

nModules = (radio_properties_t *)calloc(numModules, sizeof(radio_properties_t));

status = Radio::listModules(nModules, &numModules); // 注意前面失败后再次初始化处理
ALOGV("%s Radio::listModules status %d numModules %d", __FUNCTION__, status, numModules);

if (status != NO_ERROR) {
numModules = 0;
}

for (size_t i = 0; i < numModules; i++) {
if (nModules[i].num_bands == 0) {
continue;
}
ALOGV("%s module %zu id %d implementor %s product %s",
__FUNCTION__, i, nModules[i].handle, nModules[i].implementor,
nModules[i].product);


jobjectArray jBands = env->NewObjectArray(nModules[i].num_bands,
gRadioBandDescriptorClass, NULL);

for (size_t j = 0; j < nModules[i].num_bands; j++) {
jobject jBandDescriptor;
int jStatus =
convertBandDescriptorFromNative(env, &jBandDescriptor, &nModules[i].bands[j]);
if (jStatus != RADIO_STATUS_OK) {
continue;
}
env->SetObjectArrayElement(jBands, j, jBandDescriptor);
env->DeleteLocalRef(jBandDescriptor);
}

if (env->GetArrayLength(jBands) == 0) {
continue;
}
jstring jImplementor = env->NewStringUTF(nModules[i].implementor);
jstring jProduct = env->NewStringUTF(nModules[i].product);
jstring jVersion = env->NewStringUTF(nModules[i].version);
jstring jSerial = env->NewStringUTF(nModules[i].serial);
jobject jModule = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
nModules[i].handle, nModules[i].class_id,
jImplementor, jProduct, jVersion, jSerial,
nModules[i].num_tuners,
nModules[i].num_audio_sources,
nModules[i].supports_capture,
jBands);

env->DeleteLocalRef(jImplementor);
env->DeleteLocalRef(jProduct);
env->DeleteLocalRef(jVersion);
env->DeleteLocalRef(jSerial);
env->DeleteLocalRef(jBands);
if (jModule == NULL) {
continue;
}
env->CallBooleanMethod(jModules, gArrayListMethods.add, jModule);
}

free(nModules);
return (jint) status;
}
------------------------------------------------------------------------------------------------------------------------------------------
4.还是熟悉的binder通信调用RadioService的 listModules
------------------------------------------------------------------------------------------------------------------------------------------
// Static methods
status_t Radio::listModules(struct radio_properties *properties,
uint32_t *numModules)
{
ALOGV("listModules()");
const sp<IRadioService> service = getRadioService();
if (service == 0) {
return NO_INIT;
}
return service-> listModules(properties, numModules);
}
------------------------------------------------------------------------------------------------------------------------------------------
5.跟踪I RadioService(framework\av\service\radio) listModules
------------------------------------------------------------------------------------------------------------------------------------------
virtual status_t listModules(struct radio_properties *properties,
uint32_t *numModules)
{
if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
unsigned int numModulesReq = (properties == NULL) ? 0 : *numModules;
data.writeInt32(numModulesReq);
status_t status = remote()->transact(LIST_MODULES, data, &reply); // binder通信机制
if (status == NO_ERROR) {
status = (status_t)reply.readInt32();
*numModules = (unsigned int)reply.readInt32();
}
ALOGV("listModules() status %d got *numModules %d", status, *numModules);
if (status == NO_ERROR) {
if (numModulesReq > *numModules) {
numModulesReq = *numModules;
}
if (numModulesReq > 0) {
reply.read(properties, numModulesReq * sizeof(struct radio_properties));
}
}
return status;
}
------------------------------------------------------------------------------------------------------------------------------------------
status_t RadioService::listModules(struct radio_properties *properties,
uint32_t *numModules)
{
ALOGV("listModules");

AutoMutex lock(mServiceLock);
if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
return BAD_VALUE;
}
size_t maxModules = *numModules;
*numModules = mModules.size();
ALOGV("listModules mModules.size %d", mModules.size());
for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
properties[i] = mModules.valueAt(i)->properties();
}
return NO_ERROR;
}
最终properties来自于mModules对应的属性值
------------------------------------------------------------------------------------------------------------------------------------------
status_t RadioService::attach(radio_handle_t handle,
const sp<IRadioClient>& client,
const struct radio_band_config *config,
bool withAudio,
sp<IRadio>& radio)
{
ALOGV("%s %d config %p withAudio %d", __FUNCTION__, handle, config, withAudio);

AutoMutex lock(mServiceLock);
radio.clear();
if (client == 0) {
return BAD_VALUE;
}
ssize_t index = mModules.indexOfKey(handle);
if (index < 0) {
return BAD_VALUE;
}
sp<Module> module = mModules.valueAt(index);

if (config == NULL) {
config = module->getDefaultConfig();
if (config == NULL) {
return INVALID_OPERATION;
}
}
ALOGV("%s region %d type %d", __FUNCTION__, config->region, config->band.type);

radio = module->addClient(client, config , withAudio);

if (radio == 0) {
return NO_INIT;
}
return NO_ERROR;
}
如果config为空就会获取默认的config 逐渐又回到了 onFirstRef () - > convertProperties() 函数 而最终还是调用 HAL层tuner_get_configuration ()
------------------------------------------------------------------------------------------------------------------------------------------
所以我们如果想改变config参数那么直接通过tuner_set_configuration设置config就行,而这里需要注意的是RadioManager.java中BandConfig和BandDescriptor都需要修改源码增加set方法,其他接口都已经有了。这样就可以根据不同Region设置不同参数。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值