Android HIDL学习(5) --- Jaimex_hidl 需求实现

前面学习写一个 hellowword ,现在我们正式来做项目了。
如下是整个项目的记录过程:

写完daemon后,目录结构如下:

ciellee@sh$ tree ./hardware/interfaces/jaimex_hidl/
./hardware/interfaces/jaimex_hidl/
├── 1.0
│   ├── Android.bp
│   ├── Android.mk
│   ├── client
│   │   ├── Android.mk
│   │   ├── client.cpp
│   │   └── hw_include
│   │       ├── VirtualAudioType.h
│   │       ├── VirtualAudioVendor.h
│   │       └── VirtualStreamData.h
│   ├── default
│   │   ├── Android.bp
│   │   ├── android.hardware.jaimex_hidl@1.0-service.rc
│   │   ├── Jaimex_hidl.cpp
│   │   ├── Jaimex_hidl.h
│   │   └── service.cpp
│   └── IJaimex_hidl.hal
├── Android.bp

4 directories, 14 files

1. IJaimex_hidl.hal 代码如下

// @ /hardware/interfaces/jaimex_hidl/1.0/IJaimex_hidl.hal

package android.hardware.jaimex_hidl@1.0;

interface IJaimex_hidl {
	
    enum AudioDevice: uint32_t {
        AUDIO_DEVICE_TYPE_SPEAKER = 0,
        AUDIO_DEVICE_TYPE_MIC = 1,
    };

    enum AudioSampleRates : int32_t {
        AUDIO_SAMPLE_RATE_8K = 8000,
        AUDIO_SAMPLE_RATE_16K = 16000,
        AUDIO_SAMPLE_RATE_32K = 32000,
        AUDIO_SAMPLE_RATE_44_1K = 44100,
        AUDIO_SAMPLE_RATE_48K = 48000,
    };

    enum AudioChannelMasks: uint32_t {
        AUDIO_CHANNEL_OUT_MONO = 0x1,
        AUDIO_CHANNEL_OUT_STEREO = 0x3,
        AUDIO_CHANNEL_IN_MONO = 0x10,
        AUDIO_CHANNEL_IN_STEREO = 0xC
    };

    enum AudioFormats: uint32_t {
        AUDIO_FORMAT_PCM_16_BIT = 0x1,
        AUDIO_FORMAT_PCM_8_BIT = 0x2,
        AUDIO_FORMAT_PCM_32_BIT = 0x3,
        AUDIO_FORMAT_PCM_8_24_BIT = 0x4
    };

    enum AudioStatus: uint32_t {
        AUDIO_STATUS_NORMAL = 0x1,
        AUDIO_STATUS_BUSY = 0x2,
        AUDIO_STATUS_ABNORMAL = 0x3
    };

    enum AudioCodec: uint32_t {
        FORMAT_AAC = 0,
        FORMAT_PCM = 1
    };

    enum AudioStreamType: uint32_t {
        AUDIO_STREAM_VOICE_CALL = 0,
        AUDIO_STREAM_SYSTEM = 1,
        AUDIO_STREAM_RING = 2,
        AUDIO_STREAM_MUSIC = 3,
        AUDIO_STREAM_ALARM = 4,
        AUDIO_STREAM_NOTIFICATION = 5,
        AUDIO_STREAM_BLUETOOTH_SCO = 6,
        AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
        AUDIO_STREAM_DTMF = 8,
        AUDIO_STREAM_TTS = 9,
        AUDIO_STREAM_ACCESSIBILITY = 10
    };

    enum AudioSource: uint32_t {
        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,
        AUDIO_SOURCE_UNPROCESSED = 9,
        AUDIO_SOURCE_FM_TUNER = 1998
    };

    struct AudioProfile
    {
        AudioSampleRates sampleRates;
        AudioChannelMasks channelMask;
        AudioFormats format;
    };

    struct AudioCapability
    {
        string serviceId;
        AudioDevice type;
		vec<AudioProfile> profiles;
        vec<AudioCodec> codecs;
    };

	struct map_struct
    {
        string key;
		int32_t value;
    };
	helloWorld(string name) generates(string result);


	GetAudioCapability() generates(vec<AudioCapability> capability);
    CloseAudioTrack(uint32_t sessionId) generates(uint32_t result);
    CloseAudioRecord(uint32_t sessionId) generates(uint32_t result);
};

2. 使用 hidl-gen 自动生成 cpp 文件

编写好 hal 文件后,编译:

$ source build/envsetup.sh && lunch 9
$ PACKAGE=android.hardware.jaimex_hidl@1.0
$ LOC=hardware/interfaces/jaimex_hidl/1.0/default/
$ make hidl-gen
// 如果有语法错误,这儿会报相应的错误
$ hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
$ hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE


3. 编写 HIDL cpp 代码

@ /hardware/interfaces/jaimex_hidl/1.0/default/Jaimex_hidl.cpp
1.0/
#include "Jaimex_hidl.h"

namespace android {
namespace hardware {
namespace jaimex_hidl {
namespace V1_0 {
namespace implementation {

// Methods from IJaimex_hidl follow.
Return<void> Jaimex_hidl::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
    // TODO implement

    char buf[100];
    ::memset( buf, 0x00 , 100 );

    ::snprintf( buf ,100, " [Jaimex_hidl::helloWorld] get parm = %s \n", name.c_str() );

    LOGE("[%s][%d] buf=%s \n",__func__, __LINE__, buf);

    hidl_string result(buf);

    _hidl_cb(result);
    return Void();
}

Return<void> Jaimex_hidl::GetAudioCapability(GetAudioCapability_cb _hidl_cb) {
    // TODO implement 
    AudioCapability capability;
    AudioProfile profile;

    std::vector<AudioCapability> capability_vec;
    std::vector<AudioProfile> profile_vec;
    std::vector<AudioCodec> codec_vec;

    codec_vec.push_back(AudioCodec::FORMAT_PCM);
    
    LOGE("[%s][%d] +++ \n",__func__, __LINE__);

    // fill up AudioProfile
    profile.channelMask = AudioChannelMasks::AUDIO_CHANNEL_OUT_MONO;
    profile.format = AudioFormats::AUDIO_FORMAT_PCM_16_BIT;
    profile.sampleRates = AudioSampleRates::AUDIO_SAMPLE_RATE_16K;
    profile_vec.push_back(profile);

    // Fill up AudioCapability
    capability.serviceId = "TYPE_SPEAKER";
    capability.type = AudioDevice::AUDIO_DEVICE_TYPE_SPEAKER;    //0: speaker  1: MIC
    capability.profiles = profile_vec;
    capability.codecs =  codec_vec;
    capability_vec.push_back(capability);

    // trans c++ data to hidl format
    hidl_vec<AudioCapability> capability_vec_hidl;
    capability_vec_hidl.setToExternal(capability_vec.data(),  capability_vec.size());

    // return hidl format
    _hidl_cb(capability_vec_hidl);
    return Void();
}

Return<uint32_t> Jaimex_hidl::CloseAudioTrack(uint32_t sessionId) {
    // TODO implement

    LOGE("[%s][%d] +++ %d \n",__func__, __LINE__, sessionId);

    return uint32_t {};
}

Return<uint32_t> Jaimex_hidl::CloseAudioRecord(uint32_t sessionId) {
    // TODO implement

   LOGE("[%s][%d] +++ %d \n",__func__, __LINE__, sessionId);

    return uint32_t {};
}


// Methods from ::android::hidl::base::V1_0::IBase follow.

IJaimex_hidl* HIDL_FETCH_IJaimex_hidl(const char* /* name */) {

    LOGE("[%s][%d] +++ \n",__func__, __LINE__);

    return new Jaimex_hidl();
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace jaimex_hidl
}  // namespace hardware
}  // namespace android


4. 编写 Jaimex_hidl.h 代码

@ /hardware/interfaces/jaimex_hidl/1.0/default/Jaimex_hidl.h
#ifndef ANDROID_HARDWARE_JAIMEX_HIDL_V1_0_JAIMEX_HIDL_H
#define ANDROID_HARDWARE_JAIMEX_HIDL_V1_0_JAIMEX_HIDL_H

#include <android/hardware/jaimex_hidl/1.0/IJaimex_hidl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>


// 打日志配置
#include <android/log.h>

#define LOG_TAG "jaimix_hidl"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__);


namespace android {
namespace hardware {
namespace jaimex_hidl {
namespace V1_0 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;

struct Jaimex_hidl : public IJaimex_hidl {
    // Methods from IJaimex_hidl follow.
    Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
    Return<void> GetAudioCapability(GetAudioCapability_cb _hidl_cb) override;
    Return<uint32_t> CloseAudioTrack(uint32_t sessionId) override;
    Return<uint32_t> CloseAudioRecord(uint32_t sessionId) override;

    // Methods from ::android::hidl::base::V1_0::IBase follow.

};

// FIXME: most likely delete, this is only for passthrough implementations
extern "C" IJaimex_hidl* HIDL_FETCH_IJaimex_hidl(const char* name);

}  // namespace implementation
}  // namespace V1_0
}  // namespace jaimex_hidl
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_JAIMEX_HIDL_V1_0_JAIMEX_HIDL_H


5. 添加 liblog 模块 用于cpp 打印log

打印 log 的话 要使用 “liblog” 模块。

cc_library_shared {
    name: "[email protected]",
    relative_install_path: "hw",
    proprietary: true,
    srcs: [
        "Jaimex_hidl.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "liblog",
        "[email protected]",
    ],
}


6. client.cpp 编写

#include <android/hardware/jaimex_hidl/1.0/IJaimex_hidl.h>

#include <hidl/Status.h>
#include <hidl/LegacySupport.h>
#include <utils/misc.h>
#include <hidl/HidlSupport.h>
#include <stdio.h>

#include "./hw_include/VirtualAudioVendor.h"

using android::hardware::jaimex_hidl::V1_0::IJaimex_hidl;
using android::sp;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;

// print vector
void print_vector( std::vector<Dmsdp::AudioCapability> _vector )
{	
	uint32_t i, j;
	for( i=0; i<_vector.size(); i++ )
	{
		printf("[jaimex_client][%s] AudioCapability[%d] ---> \n",__func__, i);

		// Print ServiceID , type
		printf("[jaimex_client][%s] serviceId=%s , type=%s \n",__func__, 
						_vector[i].serviceId.c_str(),
						_vector[i].type ? "AUDIO_DEVICE_TYPE_MIC" : "AUDIO_DEVICE_TYPE_SPEAKER" );

		// Print profile
		std::vector<Dmsdp::AudioProfile> target_AudioProfile = _vector[i].profiles;
		for(j=0; j < target_AudioProfile.size(); j++)
		{
			printf("[jaimex_client][%s] sampleRates=%d , channelMask=%d , format=%d\n",__func__, 
						target_AudioProfile[j].sampleRates,
						target_AudioProfile[j].channelMask,
						target_AudioProfile[j].format);
		}

		//Print codec
		std::vector<Dmsdp::AudioCodec> target_AudioCodec = _vector[i].codecs;
		for(j=0; j<target_AudioCodec.size(); j++ )
		{
			printf("[jaimex_client][%s] AudioCodec=%s\n",__func__, 
						target_AudioCodec[j] ? "FORMAT_PCM" : "FORMAT_AAC" );
		}
	}
}



// HIDL to CPP
std::vector<Dmsdp::AudioCapability> AudioCapability_hidl_2_cpp(std::vector<IJaimex_hidl::AudioCapability> origin)
{
	uint32_t i=0, j=0;
	std::vector<Dmsdp::AudioCapability> target_AudioCapability_vec;
	std::vector<Dmsdp::AudioProfile> profile_vec;
	std::vector<Dmsdp::AudioCodec> codec_vec;

	for(i = 0; i<origin.size(); i++){
		Dmsdp::AudioCapability target_AudioCapability;

		// get serviceId and type
		target_AudioCapability.serviceId = (std::string) (origin[i].serviceId);
		target_AudioCapability.type = static_cast<Dmsdp::AudioDevice> (origin[i].type);


		// get profile
		std::vector<IJaimex_hidl::AudioProfile> target_profile;
		target_profile = std::vector<IJaimex_hidl::AudioProfile> (origin[i].profiles);

		for( j=0; j<target_profile.size(); j++ )
		{
			Dmsdp::AudioProfile target_AudioProfile;

			target_AudioProfile.channelMask = static_cast<Dmsdp::AudioChannelMasks> (target_profile[j].channelMask);
			target_AudioProfile.format = static_cast<Dmsdp::AudioFormats> (target_profile[j].format);
			target_AudioProfile.sampleRates = static_cast<Dmsdp::AudioSampleRates> (target_profile[j].sampleRates);  
			profile_vec.push_back(target_AudioProfile);
		}
		target_AudioCapability.profiles = profile_vec;


		// get codec
		std::vector<IJaimex_hidl::AudioCodec> target_codec;
		target_codec = std::vector<IJaimex_hidl::AudioCodec> (origin[i].codecs);
		for( j=0; j<target_codec.size(); j++ )
		{
			Dmsdp::AudioCodec target_AudioCodec;
			target_AudioCodec = static_cast<Dmsdp::AudioCodec> (target_codec[j]);
			codec_vec.push_back(target_AudioCodec);
		}
		target_AudioCapability.codecs = codec_vec;


		target_AudioCapability_vec.push_back(target_AudioCapability);
	}
	return target_AudioCapability_vec;
}


int main()
{
	int ret;

	android::sp<IJaimex_hidl> service = IJaimex_hidl::getService();
	if(service == nullptr){
		printf("[jaimex_client] Failed to get service \n");
		return -1;	
	}else
		printf("[jaimex_client] get service success \n");

	service->helloWorld(
			"[jaimex_client]", 
			[&](hidl_string result){
				printf("_hidl_cb:  %s \n", result.c_str());
			}
	);

	service->GetAudioCapability([&](hidl_vec<IJaimex_hidl::AudioCapability> result){
		// 接收 hidl 反回值
		std::vector<IJaimex_hidl::AudioCapability> Capability_vec = result;

		// 解析 hidl vect
		std::vector<Dmsdp::AudioCapability>  capabilitys = AudioCapability_hidl_2_cpp(Capability_vec);

		// print data
		print_vector(capabilitys);

		printf("[jaimex_client][%s] Client call success \n", __func__);
	});
}


7. 实测结果

logcat 如下:

ciellee@sh:~/work/code/USB_Dongle_0912$ adb shell
adb server is out of date.  killing...

* daemon started successfully *
px30_evb:/ # ciellee@sh:~/work/code/USB_Dongle_0912$ adb logcat -b all | grep aimex
08-31 08:02:54.076  1847  1847 D vndksupport: Loading /vendor/lib64/hw/android.hardware.jaimex_hidl@1.0-impl.so from current namespace instead of sphal namespace.
08-31 08:02:54.077  1847  1847 E jaimix_hidl: [HIDL_FETCH_IJaimex_hidl][84] +++ 
08-31 08:02:54.080  1847  1847 I ServiceManagement: Removing namespace from process name android.hardware.jaimex_hidl@1.0-service to jaimex_hidl@1.0.
08-31 08:02:54.083  1847  1847 I android.hardware.jaimex_hidl@1.0-service: Registration complete for android.hardware.jaimex_hidl@1.0::IJaimex_hidl/default.


08-31 08:03:01.794  1847  1847 E jaimix_hidl: [helloWorld][18] buf= [Jaimex_hidl::helloWorld] get parm = [jaimex_client] 


client 输出如下:

px30_evb:/ # /vendor/bin/hw/android.hardware.jaimex_hidl@1.0-service  &                                         
[1] 1847
px30_evb:/ # 
px30_evb:/ # jaimex_hidl_client_test                                                                            
[jaimex_client] get service success 
_hidl_cb:   [Jaimex_hidl::helloWorld] get parm = [jaimex_client] 
 
[jaimex_client][print_vector] AudioCapability[0] ---> 
[jaimex_client][print_vector] serviceId=TYPE_SPEAKER , type=AUDIO_DEVICE_TYPE_SPEAKER 
[jaimex_client][print_vector] sampleRates=16000 , channelMask=1 , format=1
[jaimex_client][print_vector] AudioCodec=FORMAT_PCM
[jaimex_client][operator()] Client call success 
px30_evb:/ #               
发布了329 篇原创文章 · 获赞 66 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/101432213
今日推荐