Platiumライブラリを使用したdlnaスクリーン機能の開発


ここ数日、同社のアプリケーション(iOS端末)にdlnaの機能が追加され、ローカルエリアネットワーク内のデバイスのスクリーン制御の機能であり、モバイル端末制御を提供しています.三方ライブラリPlatinumはC++で書かれているので、ライブラリのObjective-Cパッケージの作業に割り当てられました.初めてこのようなことを引き継ぐのは、コンピューター専攻ではない学生にとって挑戦的だ.グループ長は、カプセル化するインタフェースと呼び出し方法を説明するために、インタフェース設計ドキュメントを先に書くと言いました.ネットでいろいろな資料を見るしかありません.
ここは私が狂捜して、いろいろなブログを見て収集した有用な資料で、リストは以下の通りです.
リンク
説明
Open Connectivity Foundation(OCF)公式サイト
ここにUPnP関連のドキュメントと各社が開発したSDKがあります.例えば、Plutinosoftが開発したPlatinumライブラリもここから順藤摸瓜で見つけることができます.
dlna公式サイト
ここではdlnaプロトコルについて説明したドキュメントのダウンロードがあり、dlnaを全面的に学ぶと言ってもいい.ここのドキュメントは欠かせない.もちろん、実際にはあまり深く学ぶ必要はありませんが、このリソースを知っていれば、学習には底があります.-)
dlanについて紹介したブログ
上の2つのサイトはこのブログ「DLNA&UPnP開発ノート」シリーズの4つの文章を読んで見つけたもので、価値のある読書です.
はい、以上のいくつかの資源があれば、私たちは動くことができます.私の仕事の中でPlatinumライブラリを使ってdlnaのメディアコントローラ(DMC)の開発を行って、だからdlnaに対してもあまり全面的な理解がなくて、すべてはPlatinumライブラリが提供したサンプルプログラムとプロジェクトREADMEファイルに対してコンパイルライブラリと関連開発の学習を行ったのです.
では、最初のステップは、プロジェクトのコンパイルと実行例を引き下げることです.
Platinumライブラリのコンパイル
まずgitを使用してプロジェクトの最近のコミットを引き下げる
git clone --depth=1 https://github.com/plutinosoft/Platinum.git

PlatinumのコンパイルはNeptuneというC++プラットフォーム間で実行する環境に依存する必要があるため、もちろんこのプロジェクトには解決策があり、Neptuneライブラリを別途ダウンロードしたりコンパイルしたりする必要はありません.Carthageツールを通じて、NeptuneのframeworkをPlatinumのプロジェクトディレクトリの下にダウンロードする必要があります.具体的なプロセスは次のとおりです.
まずPlatinumプロジェクトディレクトリの下で、CartfileまたはCartfile.resolvedというファイルがあります.ファイルにはCarthageというツールソフトウェアがダウンロードするframeworkの名前とバージョンが示されています.実はcarthageというツールはCocoaPodsというツールに似ています.しかし、あなたのMacにはcarthageがインストールされていない可能性が高いので、まずMacにhomebrewというツールをインストールし、homebrewを使用してcarghageをインストールすることができます.次のようになります.
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"  #   homebrew

brew install carthage  # homebrew      ,  carthage

cd Platinum/  #   Platinum     

carthage update  #   carthage      Carthfile      framework

以上の手順が完了すると、Platinum/Carthageというディレクトリの下に、NeptuneというC++プラットフォーム間実行環境のMacとiOSのframeworkが存在していることがわかります.以上のコマンドが正常に実行され、最終的にNeptuneのFrameWorkが得られると、PlatinumのiOSのプロジェクトとサンプルプログラムをコンパイルすることができます.
XCodeを使用して/Platinum/Build/Targets/universal-apple-macosx/Platinum.xcodeprojプロジェクトファイルを開き、それぞれTargetを実行すると、関連するframeworkとサンプル実行プログラムを生成できます.
ホストとシミュレータを同時にサポートするframeworkダイナミックリンクライブラリを生成Platinum-iOSを選択してスキーマ(Scheme)をコンパイルし、「スキーマ(Edit Scheme...)を編集する」ダイアログ・ボックスで、「(Run)分類の情報(Info)」タブの下で、「コンパイル構成(Build Configuration)」をReleaseに選択します.コンパイルスキームを設定した後、いずれかのシミュレータ(e.g:iphone SE)を選択して1回コンパイルし、汎用iOSデバイス(Generic iOSデバイス)を選択して1回コンパイルし、この2回のコンパイルで、それぞれi386 x86_64アーキテクチャに対応するシミュレータframeworkと、実機armv7 arm64アーキテクチャに対応するframeworkを得る.この2つの異なるアーキテクチャに対応するframeworkを1つのframeworkに統合すると、ホストデバッグとシミュレータデバッグを同時に満たすframeworkが完了します.
生成された2つの異なるアーキテクチャに対するframeworkが存在するディレクトリは、右クリックShow in Finderでそれらの位置を見つけることができます.この2つのディレクトリパスは動的に変化し、完全に私と一致しません.
#           armv7 arm64   
/Users/JokerAtBaoFeng/Library/Developer/Xcode/DerivedData/Platinum-bawuiqxkhqixgybjjufqgvmduavh/Build/Products/Release-iphoneos 

#            i386 x86_64   
/Users/JokerAtBaoFeng/Library/Developer/Xcode/DerivedData/Platinum-bawuiqxkhqixgybjjufqgvmduavh/Build/Products/Release-iphonesimulator

以下のコマンドを使用してframeworkのファイルサポートアーキテクチャを表示できます.
lipo -info Release-iphoneos/Platinum.framework/Platinum 

出力:
Architectures in the fat file: Release-iphoneos/Platinum.framework/Platinum are: armv7 arm64
lipo -info Release-iphonesimulator/Platinum.framework/Platinum 

出力:
Architectures in the fat file: Release-iphonesimulator/Platinum.framework/Platinum are: i386 x86_64
次のコマンドで2つのframeworkをマージし、Release-iphoneos/Platinum.framework/Platinumファイルを置き換えます.このファイルはマージ後のファイルです.
lipo -create Release-iphoneos/Platinum.framework/Platinum Release-iphonesimulator/Platinum.framework/Platinum -output Release-iphoneos/Platinum.framework/Platinum

このとき、Release-iphoneos/Platinum.frameworkを使用して使用するプロジェクトをインポートすることができます.ああ、そうだ.frameworkの実行にはNeptune.frameworkに依存する必要があるので、自分のプロジェクトをインポートするときは、carthageでダウンロードしたNeptune.frameworkを一括してインポートすることを覚えておいてください.
連結後のframeworkでサポートされているアーキテクチャを再度表示します.
lipo -info Release-iphoneos/Platinum.framework/Platinum

出力:Architectures in the fat file:Release-iphoneos/platinum.framework/Platinum are: i386 x86_64 armv7 arm64 i386 x86_64 armv7 arm64を同時にサポートしていることがわかります.
Platinum.frameworkとNeptune.frameworkの使用
この2つのframeworkファイルを直接プロジェクトにドラッグ&ドロップし、プロンプトでCopy Items if neededを選択してfinishedをクリックしてインポートを完了できます.
次に、プロジェクト対応ターゲットの下のBuild Phases|Link Binary With Librariesの下に、PlatinumNeptuneの両方のframeworkがリストに含まれていることを確認します.
iOSの新しいバージョンではダイナミックリンクライブラリがサポートされていますが、上記の手順ではデフォルトでダイナミックframeworkが生成されます.また、TargetのGeneral|Embedded Binariesに上記の2つのframeworkを同様に追加して、アプリケーションをインストールすると同時に、対応するダイナミックライブラリをマシンにコピーする必要があります.そうしないと、マシンに対応するframeworkが欠けているため、エラーが発生します.
プロジェクトでframeworkのヘッダファイルを使用するには、二重引用符ではなく、尖った括弧"header.h"を使用する必要があります.
これにより、自分でコンパイルしたframeworkを使用することができます.
ライブラリの熟知プロセス
まず,インタフェース呼び出し方式を理解するために,サードパーティライブラリの使用である.幸いなことに、ライブラリにはいくつかの例のプログラムが提供されていて、まず3日間ゆっくり見ました.メディアコントローラの一例をプロジェクトに移植し、近隣のデバイスを検索する機能のみを実現した.しかし、これは良い冒頭で、私にとってかなりの励ましの役割を果たしています.開発は主にMicroMediaControllerのコードを参照して行われる.
私は良質なC++ライブラリの学習に対して、本当に1種の目を楽しませる体験であることを発見して、もちろんC++の細部を理解するのはやはりかなり苦痛です.
このPlatinumライブラリはdlnaプロトコルに従って作成されるべきで、関連するドキュメントは少なく、プロジェクトは自己注釈型に属している.つまり、コードの中の注釈はドキュメントの大部分であるが、このライブラリを学ぶには、dlanプロトコルを詳しく見る必要がある.そうしないと、プログラムを修正しても、最初に設定した機能目標を達成し、いくつかの機能を拡張したいと思っている.これらのパラメータはプロトコルで規定されているため、エッジパラメータは伝達されません.
インタフェースの閉鎖の過程で、他の人の閉鎖方法を参考にして本当に多くのことを学ぶことができることを発見して、割合私はObjective-CでC++インタフェースを密封する過程で、Platinumプロジェクトディレクトリの下でPlatinum/Source/Extras/ObjectiveC/MediaServerの包装方法を参考にしました.
未完、続き...
#issue1
アワの箱を識別する時、いつも識別できなくて、Platinumの中の部分のコードを修正して、そして再コンパイルした後にプロジェクトを導入して、正常に識別することができます:
変更前
PltCtrlPoint.cpp
class PLT_DeviceReadyIterator
{
public:
    PLT_DeviceReadyIterator() {}
    NPT_Result operator()(PLT_DeviceDataReference& device) const {
        NPT_Result res = device->m_Services.ApplyUntil(
            PLT_ServiceReadyIterator(), 
            NPT_UntilResultNotEquals(NPT_SUCCESS));
        if (NPT_FAILED(res)) return res;

        res = device->m_EmbeddedDevices.ApplyUntil(
            PLT_DeviceReadyIterator(),
            NPT_UntilResultNotEquals(NPT_SUCCESS));
        if (NPT_FAILED(res)) return res;

        // a device must have at least one service or embedded device 
        // otherwise it's not ready
        if (device->m_Services.GetItemCount() == 0 &&
            device->m_EmbeddedDevices.GetItemCount() == 0) {
            return NPT_FAILURE;
        }

        return NPT_SUCCESS;
    }
};

変更後
PltCtrlPoint.cpp
class PLT_DeviceReadyIterator
{
public:
    PLT_DeviceReadyIterator() {}
    NPT_Result operator()(PLT_DeviceDataReference& device) const {
        NPT_Result res = device->m_Services.ApplyUntil(
            PLT_ServiceReadyIterator(), 
            NPT_UntilResultNotEquals(NPT_SUCCESS));
//        if (NPT_FAILED(res)) return res;

        res = device->m_EmbeddedDevices.ApplyUntil(
            PLT_DeviceReadyIterator(),
            NPT_UntilResultNotEquals(NPT_SUCCESS));
//        if (NPT_FAILED(res)) return res;


        if(NPT_FAILED(res) && NPT_FAILED(res))  return res;

        // a device must have at least one service or embedded device 
        // otherwise it's not ready
        if (device->m_Services.GetItemCount() == 0 &&
            device->m_EmbeddedDevices.GetItemCount() == 0) {
            return NPT_FAILURE;
        }

        return NPT_SUCCESS;
    }
};

修正理由
検索した小米の箱について、コードは次の関数の55行を通過できないことに気づきました.
PltCtrlPoint.cpp
/*----------------------------------------------------------------------
|   PLT_CtrlPoint::ProcessGetSCPDResponse
+---------------------------------------------------------------------*/
NPT_Result
PLT_CtrlPoint::ProcessGetSCPDResponse(NPT_Result                    res, 
                                      const NPT_HttpRequest&        request,
                                      const NPT_HttpRequestContext& context,
                                      NPT_HttpResponse*             response,
                                      PLT_DeviceDataReference&      device)
{
    NPT_COMPILER_UNUSED(context);

    NPT_AutoLock lock(m_Lock);

    PLT_DeviceReadyIterator device_tester;
    NPT_String              scpd;
    PLT_DeviceDataReference root_device;
    PLT_Service*            service;

    NPT_String prefix = NPT_String::Format("PLT_CtrlPoint::ProcessGetSCPDResponse for a service of device \"%s\" @ %s (result = %d, status = %d)", 
        (const char*)device->GetFriendlyName(), 
        (const char*)request.GetUrl().ToString(),
        res,
        response?response->GetStatusCode():0);

    // verify response was ok
    NPT_CHECK_LABEL_FATAL(res, bad_response);
    NPT_CHECK_POINTER_LABEL_FATAL(response, bad_response);

    PLT_LOG_HTTP_RESPONSE(NPT_LOG_LEVEL_FINER, prefix, response);

    // make sure root device hasn't disappeared
    NPT_CHECK_LABEL_WARNING(FindDevice(device->GetUUID(), root_device, true),
                            bad_response);

    res = device->FindServiceBySCPDURL(request.GetUrl().ToRequestString(), service);
    NPT_CHECK_LABEL_SEVERE(res, bad_response);

    // get response body
    res = PLT_HttpHelper::GetBody(*response, scpd);
    NPT_CHECK_LABEL_FATAL(res, bad_response);

    // DIAL support
    if (root_device->GetType().Compare("urn:dial-multiscreen-org:device:dial:1") == 0) {
        AddDevice(root_device);
        return NPT_SUCCESS;
    }

    // set the service scpd
    res = service->SetSCPDXML(scpd);
    NPT_CHECK_LABEL_SEVERE(res, bad_response);

    // if root device is ready, notify listeners about it and embedded devices
    if (NPT_SUCCEEDED(device_tester(root_device))) {
        AddDevice(root_device);
    }

    return NPT_SUCCESS;

bad_response:
    NPT_LOG_SEVERE_2("Bad SCPD response for device \"%s\":%s", 
        (const char*)device->GetFriendlyName(),
        (const char*)scpd);

    if (!root_device.IsNull()) RemoveDevice(root_device);
    return res;
}

#issue2
個人的に小米箱はdlanプロトコルの実現部分の静音制御命令に少し出入りしているようだが、サンプルプログラムを使用して小米箱に静音命令を送信したところ、設備を静音させるしかないが、設備を音に戻すことができないことが分かった.この問題はさらに確認する必要がある.