1. 程式人生 > >DLNA android關於Platinum庫的dmr底層c++程式碼實現

DLNA android關於Platinum庫的dmr底層c++程式碼實現

最近公司正在做關於DLNA的專案,初期在網上大概瞭解了一些DLNA相關知識,可以用來開發的框架有Platinum,Cling和Cybergarage。同學們可以選擇適合自己的框架進行學習開發,至於為什麼選擇Platinum庫是因為他是一個跨平臺的C++庫,效率較高,穩定性也很強。

網上的示例帖子很少,有一大部分都是藍斯老師的,在這裡要感謝他。下面開始講解利用Platinum庫開發步驟:

1.NDK下的降Platinum庫編譯成so檔案

下載的Platinum為1-0-5-13_0ab854版本,博文中提到的將LOCAL_LDLIBS += -laxTls改為LOCAL_LDLIBS += -laxTLS新版本已經修復了。

2.Platinum庫c++的實現

大家可以在目錄Platinum\Source\Platform\Android\module\platinum\jni\下找到platinum-jni.cpp,這裡邊有示例程式碼:

/*****************************************************************
|
|      Android JNI Interface
|
|      (c) 2002-2012 Plutinosoft LLC
|      Author: Sylvain Rebaud ([email protected])
|
 ****************************************************************/

/*----------------------------------------------------------------------
|       includes
+---------------------------------------------------------------------*/
#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();
}

編譯後你會發現沒有辦法開啟一個裝置,因為PLT_UPnP中並沒有加入PLT_DeviceHostReference物件,所以不能開啟裝置。但是在\Platinum\Source\Tests\MediaRenderer目錄下大家可以找到MediaRendererTest.cpp檔案:
/*****************************************************************
|
|   Platinum - Test UPnP A/V MediaRenderer
|
| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of the GNU General Public License
| as published by the Free Software Foundation; either version 2
| of the License, or (at your option) any later version.
|
| OEMs, ISVs, VARs and other distributors that combine and 
| distribute commercially licensed software with Platinum software
| and do not wish to distribute the source code for the commercially
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
| 
[email protected]
| | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program; see the file LICENSE.txt. If not, write to | the Free Software Foundation, Inc., | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | http://www.gnu.org/licenses/gpl-2.0.html | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #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; }

可以看到程式碼中構建了一個PLT_DeviceHostReference物件,然後用upnp.AddDevice(device)新增進去,就可以正常開啟一個dmr裝置了。(我在實現自己的platinum-jni時,編譯會報undefined reference to `PLT_MediaRenderer::PLT_MediaRenderer(char const*, bool, char const*, unsigned int, bool)的錯誤,可以嘗試在mk檔案中新增LOCAL_C_INCLUDES += $(PLT_SRC_ROOT)/Devices/MediaRenderer,問題解決)。

接下來我們要做的事情就是將c++中接受到的action事件反射到java層進行處理:

此時我們就要去\Platinum\Source\Devices\MediaRenderer目錄下找PltMediaRenderer.cpp檔案:

/*----------------------------------------------------------------------
|   PLT_MediaRenderer::OnAction
+---------------------------------------------------------------------*/
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 not
    NPT_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 variables
    NPT_CHECK_LABEL_WARNING(action->SetArgumentsOutFromStateVariable(), failure);
    return NPT_SUCCESS;

failure:
    action->SetError(401,"No Such Action.");
    return NPT_FAILURE;
}

可以看到OnAction方法,此方法會在mediaRender裝置接收到事件時呼叫
/*----------------------------------------------------------------------
|   PLT_MediaRenderer::OnNext
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaRenderer::OnNext(PLT_ActionReference& action)
{
    if (m_Delegate) {
        return m_Delegate->OnNext(action);
    }
    return NPT_ERROR_NOT_IMPLEMENTED;
}

接著會調PltMediaRenderer的各種OnXXX(PLT_ActionReference& action)方法,在這裡我們可以看到把action事件交給了m_Delegate來處理,所以我們要手動設定一個m_Delegate。在\Platinum\Source\Devices\MediaRenderer目錄下有PltMediaRenderer.h標頭檔案,定義了一個方法:
// methods
    virtual void SetDelegate(PLT_MediaRendererDelegate* delegate) { m_Delegate = delegate; }
PLT_MediaRenderDelegate* delegate是從這個方法裡邊設定進來的,所以我們需要繼承PLT_MediaRenderDelagate來定義一個自己的子類,程式碼如下:
class IMediaActionReceiver : public PLT_MediaRendererDelegate
{
 public:
      static const int MEDIA_RENDER_CTL_MSG_BASE = 0x100;
      static const int MEDIA_RENDER_CTL_MSG_SET_AV_URL = (MEDIA_RENDER_CTL_MSG_BASE+0);
      static const int MEDIA_RENDER_CTL_MSG_STOP = (MEDIA_RENDER_CTL_MSG_BASE+1);
      static const int MEDIA_RENDER_CTL_MSG_PLAY = (MEDIA_RENDER_CTL_MSG_BASE+2);
      static const int MEDIA_RENDER_CTL_MSG_PAUSE = (MEDIA_RENDER_CTL_MSG_BASE+3);
      static const int MEDIA_RENDER_CTL_MSG_SEEK = (MEDIA_RENDER_CTL_MSG_BASE+4);
      static const int MEDIA_RENDER_CTL_MSG_SETVOLUME = (MEDIA_RENDER_CTL_MSG_BASE+5);
      static const int MEDIA_RENDER_CTL_MSG_SETMUTE = (MEDIA_RENDER_CTL_MSG_BASE+6);
      static const int MEDIA_RENDER_CTL_MSG_SETPLAYMODE = (MEDIA_RENDER_CTL_MSG_BASE+7);
      static const int MEDIA_RENDER_CTL_MSG_PRE = (MEDIA_RENDER_CTL_MSG_BASE+8);
      static const int MEDIA_RENDER_CTL_MSG_NEXT = (MEDIA_RENDER_CTL_MSG_BASE+9);
      
public:
    virtual void ActionInflect(int cmd, const char* value, const char* data);
    virtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action);

    // AVTransport
    virtual NPT_Result OnNext(PLT_ActionReference& action);
    virtual NPT_Result OnPause(PLT_ActionReference& action);
    virtual NPT_Result OnPlay(PLT_ActionReference& action);
    virtual NPT_Result OnPrevious(PLT_ActionReference& action);
    virtual NPT_Result OnSeek(PLT_ActionReference& action);
    virtual NPT_Result OnStop(PLT_ActionReference& action);
    virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action);
    virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action);
   
    // RenderingControl
    virtual NPT_Result OnSetVolume(PLT_ActionReference& action);
    virtual NPT_Result OnSetVolumeDB(PLT_ActionReference& action);
    virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference& action);
    virtual NPT_Result OnSetMute(PLT_ActionReference& action);
};

在相關程式碼中實現此類並且呼叫自己的ActionInflect方法來進行處理:
NPT_Result 
IMediaActionReceiver::OnNext(PLT_ActionReference& action)
{
    NPT_String curURI;
    action->GetArgumentValue("CurrentURI", curURI);
    NPT_String metaData ;
    action->GetArgumentValue("CurrentURIMetaData", metaData);
    ActionInflect(MEDIA_RENDER_CTL_MSG_NEXT, curURI.GetChars(),	  metaData.GetChars());
    return NPT_SUCCESS;
}
ActionInflect方法程式碼如下:
void
IMediaActionReceiver::ActionInflect(int cmd, const char* value, const char* data)
{	
NPT_LOG_INFO("------------------->@@@@@@@############.\n");
	int status;
	JNIEnv *env = NULL;
	bool isAttach = false;
	status = jvm->GetEnv((void**) &env, JNI_VERSION_1_4);

	if(status != JNI_OK) 
	{
		status = jvm->AttachCurrentThread(&env, NULL);
		if(status < 0) {
			return;
		}
		isAttach = true;
	}

	jstring valueString = NULL;
	jstring dataString = NULL;

	jclass inflectClass = g_inflectClass;
	jmethodID inflectMethod = g_methodID;

	if (inflectClass == NULL || inflectMethod == NULL)
	{ 
		goto end;
	}

	
	valueString = env->NewStringUTF(value);
	dataString = env->NewStringUTF(data);

	env->CallStaticVoidMethod(inflectClass, inflectMethod,valueString, dataString,cmd);

	env->DeleteLocalRef(valueString);
	env->DeleteLocalRef(dataString);
end:
	if (env->ExceptionOccurred())
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
	}
	if (isAttach)
	{
		jvm->DetachCurrentThread();
	}
}
其中jvm可以在JNI_OnLoad方法中得到,g_inflectClass跟g_methodID是你java層反射函式的Class跟方法ID(根據自身需求來定)。

下一步我們需要將事件狀態值更新至所在服務列表

可以參考程式碼:

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"); 

        // GetCurrentTransportActions
        service->SetStateVariable("CurrentTransportActions", "Play,Pause,Stop,Seek,Next,Previous");

        // GetDeviceCapabilities
        service->SetStateVariable("PossiblePlaybackStorageMedia", "NONE,NETWORK,HDD,CD-DA,UNKNOWN");
        service->SetStateVariable("PossibleRecordStorageMedia", "NOT_IMPLEMENTED");
        service->SetStateVariable("PossibleRecordQualityModes", "NOT_IMPLEMENTED");

        // GetMediaInfo
        service->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");

        // GetPositionInfo
        service->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_IMPLEMENTED
        service->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED

        // disable indirect eventing for certain state variables
        PLT_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();

        // GetTransportInfo
        service->SetStateVariable("TransportState", "NO_MEDIA_PRESENT");
        service->SetStateVariable("TransportStatus", "OK");
        service->SetStateVariable("TransportPlaySpeed", "1");

        // GetTransportSettings
        service->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 instead
        service->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;
}

按照這些步驟,就能構建自己的dmr。說明一下自己在開發中遇到的一個問題,在構建自己的PLT_MediaRender時:
JNIEXPORT jint JNICALL Java_com_geniusgithub_mediarender_jni_PlatinumJniProxy__1startMediaRender(JNIEnv *env, jclass, jlong _self, jbyteArray _jbyteArrName,jbyteArray _jbyteArrayUUID)
{ 
    PLT_UPnP* upnp = (PLT_UPnP*)_self;
    char* dmr_name = (char*)env->GetByteArrayElements(_jbyteArrName, 0);
    char* dmr_uuid = (char*)env->GetByteArrayElements(_jbyteArrayUUID, 0);
    PLT_MediaRenderer* mediaRender = new PLT_MediaRenderer(dmr_name,false,dmr_uuid,36439,false);
    PLT_DeviceHostReference device(mediaRender);
    myDevice = device;
    upnp->AddDevice(myDevice); 
    upnp->Start(); 
    return 0; 
}
<span style="font-size:18px;">GetByteArrayElements有可能發生字元亂碼情況,把方法中傳入的jbyteArray改為jstring(相應的java層也應改變),程式碼改為:</span>
<pre name="code" class="cpp">char* dmr_name = (char *) env->GetStringUTFChars(name, 0);
char* dmr_uuid = (char *) env->GetStringUTFChars(uuid, 0);
<span style="font-size:18px;">亂碼問題得到解決。所有要講解的就到這了,過程中遇到了很多問題,所以寫了這篇博文供大家參考,再次謝謝藍斯博主!</span>




相關推薦

DLNA android關於Platinumdmr底層c++程式碼實現

最近公司正在做關於DLNA的專案,初期在網上大概瞭解了一些DLNA相關知識,可以用來開發的框架有Platinum,Cling和Cybergarage。同學們可以選擇適合自己的框架進行學習開發,至於為什麼選擇Platinum庫是因為他是一個跨平臺的C++庫,效率較高,穩定性也

C程式碼實現從FTP上下載檔案

從FTP上下載檔案這個功能我早就想實現了,但是苦於百度的文章大多是下載連結,一直沒捨得積分下載,這次通過查閱MSDN,將一套下載流程函式摸了一下,寫出程式碼實現從FTP下載檔案 環境 VS2015 程式碼: #include <iostream> #include <

c#程式碼實現排序演算法之歸併排序

歸併排序的平均時間複雜度為O(nlogn),最好時間複雜度為O(nlogn),最壞時間複雜度為O(nlogn),空間複雜度為O(n),是一種穩定的演算法。 1.將待排序序列r(1),r(2),…,r(n)劃分為兩個長度相等的子序列r(1),…r(n/2)和r(n/2+1),…,r

c#程式碼實現排序演算法之快速排序

快速排序的平均時間複雜度為O(nlog2n),最好時間複雜度為O(nlog2n),最壞時間複雜度為O(n²),空間複雜度為O(log2n),是一種不穩定的演算法。 1.劃分:選定一個記錄作為軸值,以軸值為基準將整個序列劃分為兩個子序列r(1)…r(i-1)和r(i+1)…r(n)

c#程式碼實現排序演算法之氣泡排序

氣泡排序的平均時間複雜度為O(n²),最好時間複雜度為O(n),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種穩定的演算法。 1.將整個待排序的記錄序列劃分成有序區和無序區,初始時有序區為空,無序區包括所有待排序的記錄。 2.對無序區從前向後依次比較相鄰記錄,若反序則交

c#程式碼實現排序演算法之選擇排序

選擇排序的平均時間複雜度為O(n²),最好時間複雜度為O(n²),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種不穩定的演算法。 1.將整個記錄序列劃分為有序區和無序區,初始時有序區為空,無序區含有待排序的所有記錄。 2.在無序區查詢值最小的記錄,將它與無序區的第一個記

c#程式碼實現排序演算法之插入排序

插入排序的平均時間複雜度為O(n²),最好時間複雜度為O(n),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種穩定的演算法。 1.將整個待排序的記錄序列劃分成有序區和無序區,初始時有序區為待排序記錄序列的第一個記錄,無序區包括所有剩餘待排序的記錄。 2.將無序區的第一個

《大話資料結構4》—— 佇列的順序儲存結構 (迴圈佇列)—— C++程式碼實現

   佇列  ● 佇列的概念:   佇列(簡稱作隊,Queue)也是一種特殊的線性表,佇列的資料元素以及資料元素間的邏輯關係和線性表完全相同,其差別是線性表允許在任意位置插入和刪除,而佇列只允許在其一端進行插入操作在其另一端進行刪除操作。 佇

《大話資料結構5》—— 佇列的鏈式儲存結構 —— C++程式碼實現

目錄 鏈佇列 迴圈佇列和鏈式佇列的比較 鏈佇列 ●  實現佇列的最好的方式就是使用單鏈表來實現,佇列的鏈式儲存結構,其實就是線性表的單鏈表,只不過它只能尾進頭出而已——稱為鏈佇列。 ● 那為了操作方便,頭指標指向頭結點,隊尾指標指向終端節點,即最後一個結點元

Vivado HLS實現FIR濾波器(1)——使用官方C程式碼實現FIR

使用官方C程式碼實現FIR 參考資料: 不同點說明 程式結構 C語言程式碼 模擬綜合 參考資料: 教程——基於HLS實現FIR濾波器https://blog.csdn.net/LZY27

資料結構經典例題解析C/C++程式碼實現(二)

第一題 題目 編一C程式,它能把讀入的整數依次插入到一個初始為空的二叉排序樹中,一直讀到-9999為止(-9999不插入該二叉排序樹)。輸出該二叉排序樹的前序序列、後序序列及葉結點的個數。(輸入時,兩個相鄰的整數用空格隔開)。 解析 這個程式碼可以參考二叉樹

資料結構經典例題解析C/C++程式碼實現(一)

考研需要吧,雖然挺基礎的,但是還是要練習下的,而且,還可以幫助一些其他同樣需要這些程式碼的朋友。 實現最基礎的資料結構建議是用C語言,這樣子很多細節都可以很好地把握,當然,如果用STL可以簡單地實現,那麼我也會實現一下。 第一題 題目 編一C程式,它能根據讀入的資

《大話資料結構9》—— “二叉樹的順序儲存結構”——C++程式碼實現

  順序儲存結構: 二叉樹的順序儲存結構就是用一維陣列儲存二叉樹中的結點,並且結點的儲存位置,也就是陣列的下標要能體現結點之間的關秀,比如雙親與孩子的關係,左右結點的兄弟關係。 完全二叉樹: 完全二叉樹由於其結構上的特點,通常採用順序儲存方式儲存。一棵有n個結點的完全二

【初探】“ 選擇排序 ” ——C++程式碼實現

  選擇排序(Selection sort)是一種簡單直觀的排序演算法。無論什麼資料進去都是 O(n²) 的時間複雜度。所以用到它的時候,資料規模越小越好。唯一的好處可能就是不佔用額外的記憶體空間了吧。   簡單排序處理流程 首先在未排序序列中找到最小

【初探】“直接插入排序”—— C++程式碼實現

目錄 直接插入排序簡介 演算法步驟 演算法演示 複雜度分析 穩定性 直接插入排序演算法的特點 直接插入排序簡介 ● 插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從

最大堆、最小堆定義及其C++程式碼實現

資料:https://blog.csdn.net/guoweimelon/article/details/50904346 但是它的最大堆刪除部分的程式碼有問題,詳見連結裡的評論區 定義 堆首先必須是一棵完全二叉樹 最大堆:完全二叉樹,父節點的值不小於子節點的值 最小堆:完全二叉樹,父節

【初探】“ 希爾排序 ”—— C++程式碼實現

目錄 希爾排序演算法介紹 希爾排序的基本思想 希爾排序的演算法效能 時間複雜度          直接插入排序和希爾排序的比較 希爾排序演算法介紹 ● 希爾排序是希爾(Donald Shell)於

二叉排序樹的構造,插入,刪除,完整c程式碼實現

#include <stdio.h>   #include <stdlib.h>    typedef struct BiTNode{       int data;       s

二叉搜尋樹的C++程式碼實現

template<class K,class V> struct BinaryNode{ K _key; V _value; BinaryNode<K,V>* _left;

資料結構C/C++程式碼實現 棧連結串列基本操作

實現棧連結串列基本操作: #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct linknode {     ElemType data;     stru