接上篇博文 NDK下 将Platinum SDK 编译成so库 (android - upnp)

讲述了如何利用该代码库编译给android程序调用的so库,其中也提到了,在使用sample-upnp工程来测试生成的so库是无效的

大家比对一下Platinum开发库的Platinum\Source\Platform\Android\module\platinum\jni\platinum-jni.cpp和

Platinum\Source\Tests\MediaRenderer\MediaRendererTest.cpp

platinum-jni.cpp

#include <assert.h>
#include <jni.h>
#include <string.h>
#include <sys/types.h>#include "platinum-jni.h"
#include "Platinum.h"#include <android/log.h>/*----------------------------------------------------------------------
|   logging
+---------------------------------------------------------------------*/
NPT_SET_LOCAL_LOGGER("platinum.android.jni")/*----------------------------------------------------------------------
|   functions
+---------------------------------------------------------------------*/
__attribute__((constructor)) static void onDlOpen(void)
{
}/*----------------------------------------------------------------------
|    JNI_OnLoad
+---------------------------------------------------------------------*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{NPT_LogManager::GetDefault().Configure("plist:.level=FINE;.handlers=ConsoleHandler;.ConsoleHandler.outputs=2;.ConsoleHandler.colors=false;.ConsoleHandler.filter=59");return JNI_VERSION_1_4;
}/** Class:     com_plutinosoft_platinum_UPnP* Method:    _init* Signature: ()J*/
JNIEXPORT jlong JNICALL Java_com_plutinosoft_platinum_UPnP__1init(JNIEnv *env, jclass)
{NPT_LOG_INFO("init");PLT_UPnP* self = new PLT_UPnP();return (jlong)self;
}/** Class:     com_plutinosoft_platinum_UPnP* Method:    _start* Signature: (J)I*/
JNIEXPORT jint JNICALL Java_com_plutinosoft_platinum_UPnP__1start(JNIEnv *, jclass, jlong _self)
{NPT_LOG_INFO("start");PLT_UPnP* self = (PLT_UPnP*)_self;return self->Start();
}/** Class:     com_plutinosoft_platinum_UPnP* Method:    _stop* Signature: (J)I*/
JNIEXPORT jint JNICALL Java_com_plutinosoft_platinum_UPnP__1stop(JNIEnv *, jclass, jlong _self)
{NPT_LOG_INFO("stop");PLT_UPnP* self = (PLT_UPnP*)_self;return self->Stop();
}

MediaRendererTest.cpp

#include "PltUPnP.h"
#include "PltMediaRenderer.h"#include <stdlib.h>/*----------------------------------------------------------------------
|   globals
+---------------------------------------------------------------------*/
struct Options {const char* friendly_name;
} Options;/*----------------------------------------------------------------------
|   PrintUsageAndExit
+---------------------------------------------------------------------*/
static void
PrintUsageAndExit(char** args)
{fprintf(stderr, "usage: %s [-f <friendly_name>]\n", args[0]);fprintf(stderr, "-f : optional upnp server friendly name\n");fprintf(stderr, "<path> : local path to serve\n");exit(1);
}/*----------------------------------------------------------------------
|   ParseCommandLine
+---------------------------------------------------------------------*/
static void
ParseCommandLine(char** args)
{const char* arg;char**      tmp = args+1;/* default values */Options.friendly_name = NULL;while ((arg = *tmp++)) {if (!strcmp(arg, "-f")) {Options.friendly_name = *tmp++;} else {fprintf(stderr, "ERROR: too many arguments\n");PrintUsageAndExit(args);}}
}/*----------------------------------------------------------------------
|   main
+---------------------------------------------------------------------*/
int
main(int /* argc */, char** argv)
{   PLT_UPnP upnp;/* parse command line */ParseCommandLine(argv);PLT_DeviceHostReference device(new PLT_MediaRenderer(Options.friendly_name?Options.friendly_name:"Platinum Media Renderer",false,"e6572b54-f3c7-2d91-2fb5-b757f2537e21"));upnp.AddDevice(device);bool added = true;upnp.Start();char buf[256];while (gets(buf)) {if (*buf == 'q')break;if (*buf == 's') {if (added) {upnp.RemoveDevice(device);} else {upnp.AddDevice(device);}added = !added;}}upnp.Stop();return 0;
}

可以看出JNI接口中的PLT_UPnP对象并没有加入PLT_DeviceHostReference对象,所以无法启动设备,只要参照MediaRenderTest.cpp的做法我们就可以实现一个dmr设备的开启与关闭了,童鞋们可以仿照博文 基于Platinum库的DMR实现(android)当中的jni类来尝试实现一下这两个接口

public static native int startMediaRender(byte[] friendname ,byte[] uuid);

public static native int stopMediaRender();

完成这一步,DMR的实现就已经成功一半了

接下来我们要做的两件事就是

1.将外部的action事件通过反射机制抛给java层处理

2.通过jni将一些事件状态值更新至所在服务列表

先看第一点,每当有action事件到来时,PLT_MediaRenderer的

virtual NPT_Result OnAction(PLT_ActionReference&action,const PLT_HttpRequestContext& context);方法就会被调用

NPT_Result
PLT_MediaRenderer::OnAction(PLT_ActionReference&          action, const PLT_HttpRequestContext& context)
{NPT_COMPILER_UNUSED(context);/* parse the action name */NPT_String name = action->GetActionDesc().GetName();// since all actions take an instance ID and we only support 1 instance// verify that the Instance ID is 0 and return an error here now if notNPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType();if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) {if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) {action->SetError(718, "Not valid InstanceID");return NPT_FAILURE;}}serviceType = action->GetActionDesc().GetService()->GetServiceType();if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) {if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) {action->SetError(702, "Not valid InstanceID");return NPT_FAILURE;}}/* Is it a ConnectionManager Service Action ? */if (name.Compare("GetCurrentConnectionInfo", true) == 0) {return OnGetCurrentConnectionInfo(action);}  /* Is it a AVTransport Service Action ? */if (name.Compare("Next", true) == 0) {return OnNext(action);}if (name.Compare("Pause", true) == 0) {return OnPause(action);}if (name.Compare("Play", true) == 0) {return OnPlay(action);}if (name.Compare("Previous", true) == 0) {return OnPrevious(action);}if (name.Compare("Seek", true) == 0) {return OnSeek(action);}if (name.Compare("Stop", true) == 0) {return OnStop(action);}if (name.Compare("SetAVTransportURI", true) == 0) {return OnSetAVTransportURI(action);}if (name.Compare("SetPlayMode", true) == 0) {return OnSetPlayMode(action);}/* Is it a RendererControl Service Action ? */if (name.Compare("SetVolume", true) == 0) {return OnSetVolume(action);}if (name.Compare("SetVolumeDB", true) == 0) {return OnSetVolumeDB(action);}if (name.Compare("GetVolumeDBRange", true) == 0) {return OnGetVolumeDBRange(action);}if (name.Compare("SetMute", true) == 0) {return OnSetMute(action);}// other actions rely on state variablesNPT_CHECK_LABEL_WARNING(action->SetArgumentsOutFromStateVariable(), failure);return NPT_SUCCESS;failure:action->SetError(401,"No Such Action.");return NPT_FAILURE;
}

部分事件会由m_Delegate成员变量来处理,也就是 virtual void SetDelegate(PLT_MediaRendererDelegate* delegate) { m_Delegate = delegate; }传进来的

所以我们只需要从PLT_MediaRendererDelegate类派生一个子类,然后将它设进PLT_MediaRenderer并实现相应的action方法并把一些需要的值反射出来即可

class PLT_MediaRendererDelegate
{
public:virtual ~PLT_MediaRendererDelegate() {}// ConnectionManagervirtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action) = 0;// AVTransportvirtual NPT_Result OnNext(PLT_ActionReference& action) = 0;virtual NPT_Result OnPause(PLT_ActionReference& action) = 0;virtual NPT_Result OnPlay(PLT_ActionReference& action) = 0;virtual NPT_Result OnPrevious(PLT_ActionReference& action) = 0;virtual NPT_Result OnSeek(PLT_ActionReference& action) = 0;virtual NPT_Result OnStop(PLT_ActionReference& action) = 0;virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action) = 0;virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action) = 0;// RenderingControlvirtual NPT_Result OnSetVolume(PLT_ActionReference& action) = 0;virtual NPT_Result OnSetVolumeDB(PLT_ActionReference& action) = 0;virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference& action) = 0;virtual NPT_Result OnSetMute(PLT_ActionReference& action) = 0;
};
void ActionInflect(int cmd, const char* value, const char* data)
{if (g_vm == NULL){UpnpPrintInfo("g_vm = NULL!!!");return ;}int status;JNIEnv *env = NULL;bool isAttach = false;status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);if(status != JNI_OK) {status = g_vm->AttachCurrentThread(&env, NULL);if(status < 0) {UpnpPrintInfo("callback_handler: failed to attach , current thread, status = %d", status);return;}isAttach = true;}jstring valueString = NULL;jstring dataString = NULL;jclass inflectClass = g_inflectClass;jmethodID inflectMethod = g_methodID;if (inflectClass == NULL || inflectMethod == NULL){goto end;}//    UpnpPrintInfo("CMD = %d\nVALUE = %s\nDATA = %s",cmd, value, data);valueString = env->NewStringUTF(value);dataString = env->NewStringUTF(data);env->CallStaticVoidMethod(inflectClass, inflectMethod, cmd, valueString, dataString);env->DeleteLocalRef(valueString);env->DeleteLocalRef(dataString);end:if (env->ExceptionOccurred()){env->ExceptionDescribe();env->ExceptionClear();}if (isAttach){g_vm->DetachCurrentThread();}}

再看第二点,如何将事件变量值更新至服务列表

首先通过FindServiceByType方法找到urn:schemas-upnp-org:service:AVTransport:1服务,

然后通过SetStateVariable更新值即可

变量名与值对应关系大家参照dlna文档开发即可

http://download.csdn.net/detail/geniuseoe2012/4969961

重点看standardizeddcps\MediaServer_4 and  MediaRenderer_3下的UPnP-av-AVTransport-v3-Service-20101231.pdf文档

代码实现可以参照PLT_MediaRenderer::SetupServices()方法

NPT_Result
PLT_MediaRenderer::SetupServices()
{PLT_Service* service;{/* AVTransport */service = new PLT_Service(this,"urn:schemas-upnp-org:service:AVTransport:1", "urn:upnp-org:serviceId:AVTransport","AVTransport","urn:schemas-upnp-org:metadata-1-0/AVT/");NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_AVTransportSCPD));NPT_CHECK_FATAL(AddService(service));service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f));service->SetStateVariable("A_ARG_TYPE_InstanceID", "0"); // GetCurrentTransportActionsservice->SetStateVariable("CurrentTransportActions", "Play,Pause,Stop,Seek,Next,Previous");// GetDeviceCapabilitiesservice->SetStateVariable("PossiblePlaybackStorageMedia", "NONE,NETWORK,HDD,CD-DA,UNKNOWN");service->SetStateVariable("PossibleRecordStorageMedia", "NOT_IMPLEMENTED");service->SetStateVariable("PossibleRecordQualityModes", "NOT_IMPLEMENTED");// GetMediaInfoservice->SetStateVariable("NumberOfTracks", "0");service->SetStateVariable("CurrentMediaDuration", "00:00:00");service->SetStateVariable("AVTransportURI", "");service->SetStateVariable("AVTransportURIMetadata", "");;service->SetStateVariable("NextAVTransportURI", "NOT_IMPLEMENTED");service->SetStateVariable("NextAVTransportURIMetadata", "NOT_IMPLEMENTED");service->SetStateVariable("PlaybackStorageMedium", "NONE");service->SetStateVariable("RecordStorageMedium", "NOT_IMPLEMENTED");service->SetStateVariable("RecordMediumWriteStatus", "NOT_IMPLEMENTED");// GetPositionInfoservice->SetStateVariable("CurrentTrack", "0");NPT_Result durResult = service->SetStateVariable("CurrentTrackDuration", "00:00:00");service->SetStateVariable("CurrentTrackMetadata", "");service->SetStateVariable("CurrentTrackURI", "");NPT_Result relTimeResult = service->SetStateVariable("RelativeTimePosition", "00:00:00"); service->SetStateVariable("AbsoluteTimePosition", "00:50:00");service->SetStateVariable("RelativeCounterPosition", "2147483647"); // means NOT_IMPLEMENTEDservice->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED// disable indirect eventing for certain state variablesPLT_StateVariable* var;var = service->FindStateVariable("RelativeTimePosition");if (var) var->DisableIndirectEventing();var = service->FindStateVariable("AbsoluteTimePosition");if (var) var->DisableIndirectEventing();var = service->FindStateVariable("RelativeCounterPosition");if (var) var->DisableIndirectEventing();var = service->FindStateVariable("AbsoluteCounterPosition");if (var) var->DisableIndirectEventing();// GetTransportInfoservice->SetStateVariable("TransportState", "NO_MEDIA_PRESENT");service->SetStateVariable("TransportStatus", "OK");service->SetStateVariable("TransportPlaySpeed", "1");// GetTransportSettingsservice->SetStateVariable("CurrentPlayMode", "NORMAL");service->SetStateVariable("CurrentRecordQualityMode", "NOT_IMPLEMENTED");}{/* ConnectionManager */service = new PLT_Service(this,"urn:schemas-upnp-org:service:ConnectionManager:1", "urn:upnp-org:serviceId:ConnectionManager","ConnectionManager");NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_ConnectionManagerSCPD));NPT_CHECK_FATAL(AddService(service));service->SetStateVariable("CurrentConnectionIDs", "0");// put all supported mime types here insteadservice->SetStateVariable("SinkProtocolInfo", "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_SP_G726,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMDRM_WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPLL_BASE,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC_XAC3,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMDRM_WMVSPLL_BASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_BASE,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L5_SO_G726,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL_XAC3,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAPRO,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L4_SO_G726,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3X,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_MP3,http-get:*:video/x-ms-wmv:*,http-get:*:video/mp4:*");service->SetStateVariable("SourceProtocolInfo", "");}{/* RenderingControl */service = new PLT_Service(this,"urn:schemas-upnp-org:service:RenderingControl:1", "urn:upnp-org:serviceId:RenderingControl","RenderingControl","urn:schemas-upnp-org:metadata-1-0/RCS/");NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_RenderingControlSCPD));NPT_CHECK_FATAL(AddService(service));service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f));service->SetStateVariable("Mute", "0");service->SetStateVariableExtraAttribute("Mute", "Channel", "Master");service->SetStateVariable("Volume", "100");service->SetStateVariableExtraAttribute("Volume", "Channel", "Master");service->SetStateVariable("VolumeDB", "0");service->SetStateVariableExtraAttribute("VolumeDB", "Channel", "Master");service->SetStateVariable("PresetNameList", "FactoryDefaults");}return NPT_SUCCESS;
}

至此代码实现步骤已全部讲解完毕,当然在具体实现过程中多多少少会遇到些问题

根据log信息多问问谷哥度娘,一般都能找到解决方案的

同时在jni层转换C++类型与java类型时一定要注意及时释放资源,不要造成内存泄漏了

另外不要再向楼主索要源码了,编程最重要的是思维

只有自己动手实践了,摸索了,思考了,解决了,自身水平才会提高

否则你永远都只能是code-farmer而无法成为code-designer

授之以鱼不如授之予渔也是蓝老师一贯的教学宗旨,伸手党请自觉绕道

最后感谢大家的支持,我们下节课再见!

more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.net/geniuseoe2012

转载于:https://www.cnblogs.com/dyllove98/p/3157236.html

关于Platinum库的MediaRender具体C++代码实现探讨相关推荐

  1. inflect java_关于Platinum库的MediaRender具体C++代码实现探讨

    讲述了如何利用该代码库编译给android程序调用的so库,其中也提到了,在使用sample-upnp工程来测试生成的so库是无效的 大家比对一下Platinum开发库的Platinum\Source ...

  2. python开源代码-这7个开源的Python库,让你轻松代码分析

    原标题:这7个开源的Python库,让你轻松代码分析 开源最前线(ID:OpenSourceTop) 猿妹编译 来源:https://opensource.com/article/18/7/7-pyt ...

  3. 共享库中的位置无关代码(PIC)

    原作者:Eli Bendersky http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-li ...

  4. linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  5. NGenerics算法库是学习的好代码

    NGenerics算法库是学习的好代码 地址为: http://www.codeplex.com/NGenerics posted on 2007-04-29 22:48 黄尚 阅读(...) 评论( ...

  6. 单片机只会调库和复制别人的代码是什么水平?

    单片机只会调库和复制别人的代码是什么水平? 前言 什么是调库? 如何不调库点亮一个LED 调库与不调库的区别 为什么要操作寄存器 结语 前言 相信对于学习过单片机的同学对于调库这个操作都不陌生,大家都 ...

  7. Python科学计算库核心知识点总结_代码篇(ML/DL依赖语法)

    Python科学计算库核心知识点总结_代码篇(ML/DL依赖语法)                                                                    ...

  8. 又一巨头从Java迁移到Kotlin:关键应用全部开始切换、安卓代码库超过千万行Kotlin代码

    Meta 现在爱 Kotlin 多于 Java. Facebook 母公司 Meta 正在将其 Android 应用的 Java 代码迁移到 Kotlin.根据 Meta 的官方博客所述,截至今天,其 ...

  9. 蓝库云|如何利用零代码工具创建人力资源管理系统

    您是否希望使用零代码代码技术创建人力资源管理系统呢?如果是,这篇文章适合你.随着世界的发展,生活变得越来越简单.人力资源管理和所有业务专业人员都在使用零代码平台来构建应用程序,以节省时间.金钱和人力资 ...

最新文章

  1. 启用新域名:ju690.com --聚了就灵的谐音
  2. java实现红包要多少钱_Java实现发红包功能
  3. 前端小技巧-定位的活学活用之仿淘宝列表
  4. SpringCloud之路由网关zuul(五)
  5. Android—开发过程中的相关注意事项
  6. 威海二职工业机器人专业_工业机器人专业就业前景-山东省好的中专学校
  7. C++ STL vector的构造
  8. html 控件命名规则,前端组件命名规则
  9. Golang程序性能分析(三)用pprof分析gRPC服务的性能
  10. dbname, instance, sid
  11. Golang map的底层实现
  12. 非均匀采样的kalman滤波
  13. android webview richeditor,GitHub - IllegalCreed/react-native-webview-richeditor
  14. imo free video calls and text(IMO免费视频通话)
  15. selenium测试框架快速搭建(ui自动化测试)
  16. ipad创建id显示服务器失败,为什么无法创建苹果id什么原因
  17. MySQL监控-Datadog数据库监控调研
  18. 修复打不开计算机管理,win10系统设备管理器打不开的修复技巧
  19. 【Linux】MBR磁盘分区表只能有四个分区?
  20. 收购Beat Game,Facebook离“VR游戏社交王国”梦还有多远?

热门文章

  1. python 无法初始化设备prn_彻底搞懂Python一切皆对象,面试必过
  2. 如何使用cmd进入打印机选项_用命令添加打印机
  3. sql取整数_SQL 窗口函数
  4. python中的模块_python3.0中重载模块
  5. Leetcode-148-排序链表(递归+迭代)
  6. Java -考研 学习路线(笔记链接汇总)-个人用
  7. 嵌入式系统——流水线处理机执行时间计算
  8. C语言:输入四个数a,b,c,d,将这四个数由小到大排序
  9. 【equals与==比较】String的两种拼接
  10. delphi xe3 mysql,delphi10.3安装使用mySQL