2017-11-11 192 views
0

我正在從傳統Gracenote公司Mobile客戶端的移動SDK更新的GNSDK遷移我的Android應用程序,我已經打了幾個碰壁:麻煩從Gracenote公司Mobile客戶端遷移到GNSDK移動

  1. 在移動客戶端中,我使用GNOperations.recognizeMIDStreamFromRadio(GNSearchResultReady,GNConfig,samplePCMBuffer) 在PCM緩衝區上啓動指紋和查找操作。我的應用程序只能向Gracenote提供預先錄製的音頻(而不是簡單地將Gracenote指向流式音頻源),理想情況下爲原始PCM,但如果需要可以將其編碼爲標準壓縮格式。我應該使用GNSDK for Mobile API對提供的預先錄製的音頻數據執行相同的指紋和查找操作,希望它仍然是原始PCM?
  2. 類GnMusicId看起來像它可能是一個方便的通用指紋生成器和查詢發行者類,所以它可能是上面#1的答案。但是,我還沒有找到一種方法來確定何時寫完指紋,因此我們準備發出查詢。如何獲得回調,讓我知道GnMusicId已經完成了從GnMusicId.fingerprintWrite(byte [] audioData,long audioDataSize)方法寫入指紋,並且指紋已準備好用於通過GnMusicId.findAlbums(fingerprintDataGet (),GnFingerprintType.kFingerprintTypeStream6)?
  3. 在移動客戶端中,我能夠使用GNOperations.cancel(GNSearchResultReady)取消正在進行的Gracenote操作 - 我讀過新的架構要求特定的操作由於更模塊化的設計而單獨取消,但是我沒有在GNSDK for Mobile可以執行的各種操作中找到標準取消API - 我應該如何取消GNSDK for Mobile中的指紋和歌曲查找操作?

回答

0

原來可以識別給定PCM陣列GNSDK爲Android以下三個GnMusicIdStream API調用:

  1. GnMusicIdStream.audioProcessStart(sampleRateHz,pcmBitcount,信道計數)準備識別引擎的進入PCM
  2. GnMusicIdStream.audioProcess(pcmArray,pcmArray.length)到要認識到
  3. GnMusicIdStream.identifyAlbumAsync()來生成指紋,然後用它來查找操作PCM陣列中傳遞。這將導致傳遞給GnMusicIdStream實例的IGnMusicIdStreamEvents對象的回調,並且musicIdStreamAlbumResult()將提供任何結果。

就我所見,使用這種方法你不需要等待指紋的生成等顯式 - 你只需要按順序調用這三個方法,然後GNSDK處理剩下的,最終將發出一個回電話。完整ID操作結束這樣看:

try { 


     mGnMusicIdStream = new GnMusicIdStream(mGnUser, GnMusicIdStreamPreset.kPresetRadio, new IGnMusicIdStreamEvents() { 
      @Override 
      public void musicIdStreamProcessingStatusEvent(GnMusicIdStreamProcessingStatus gnMusicIdStreamProcessingStatus, IGnCancellable iGnCancellable) { 
       Log.d(TAG,"gracenote gnsdk -- musicIdStreamProcessingStatusEvent(); event is: "+gnMusicIdStreamProcessingStatus); 
      } 

      @Override 
      public void musicIdStreamIdentifyingStatusEvent(GnMusicIdStreamIdentifyingStatus gnMusicIdStreamIdentifyingStatus, IGnCancellable iGnCancellable) { 
       Log.d(TAG,"gracenote gnsdk -- musicIdStreamIdentifyingStatusEvent(); event is: "+gnMusicIdStreamIdentifyingStatus); 
      } 

      @Override 
      public void musicIdStreamAlbumResult(GnResponseAlbums gnResponseAlbums, IGnCancellable iGnCancellable) { 

       Log.d(TAG,"gracenote gnsdk -- musicIdStreamAlbumResult(); responsealbums matches: "+gnResponseAlbums.resultCount()); 

       if (gnResponseAlbums.resultCount() > 0) { 
        try { 
         final GnAlbum albumResponse = gnResponseAlbums.albums().at(0).next(); 

         final GnTrack trackResponse = albumResponse.trackMatched(); 

         if (trackResponse != null) { 
          mEvent.postOnGNSearchResult(new ISongRecognitionResponse() { 
           @Override 
           public 
           @NonNull 
           String extractTrackTitle() { 
            // seems that track title comes reliably from GnTrack and much of the rest is locked 
            // up in the GnAlbum? 
            if (trackResponse.title() != null) { 
             return trackResponse.title().display(); 
            } else { 
             return ""; 
            } 
           } 

           @Override 
           public 
           @NonNull 
           String extractTrackArtist() { 
            if (albumResponse.artist() != null) { 
             if(BuildConfig.RULE_DEBUG_LEVEL>0) 
              Log.d(TAG,"gnsdk -- album artist says "+albumResponse.artist().name().display()); 
             return albumResponse.artist().name().display(); 
            } else { 
             return ""; 
            } 
           } 

           @Override 
           public long extractTrackPosition() { 
            return trackResponse.currentPosition(); 
           } 

           @Override 
           public long extractTrackDuration() { 
            return trackResponse.duration(); 
           } 

           @Override 
           public byte[] extractCoverArtImageData() { 
            // seems that base64 string of the image is not always/commonly available 
            // at least as we're trying to access it here. The sample app downloads the image 
            // asynchronously from the URL, which seems more reliable 
            String img64 = albumResponse.coverArt().asset(GnImageSize.kImageSizeSmall).imageDataBase64(); //trackResponse.content(GnContentType.kContentTypeImageCover).asset(GnImageSize.kImageSize220).imageDataBase64(); 

            if(img64 != null && !img64.isEmpty()) { 
             return Base64.decode(img64, Base64.DEFAULT); 
            }else{ 
             return null; 
            } 
           } 

           @NonNull 
           @Override 
           public String extractCoverArtImageURL() { 
            // beware: asking for specific image sizes has been known to cause 
            // no cover art to come back even if there might be cover art at another size. 
            // The sample app uses the categorical size qualifier constant kImageSizeSmall 
            String httpURL = albumResponse.coverArt().asset(GnImageSize.kImageSizeSmall).urlHttp(); 

            return httpURL; 
           } 
          }); 
         }//end if track response data is non-null 
         else { 
          mEvent.postOnGNSearchResult(null); 
         } 
        }catch(GnException e){ 
         Log.e(TAG, "we received a response clbk, but failed to process it", e); 
        } 
       }//end if greater than 0 results 
       else{ 
        //no results, so pass a null result to indicate a miss 
        mEvent.postOnGNSearchResult(null); 
       } 
      } 

      @Override 
      public void musicIdStreamIdentifyCompletedWithError(GnError gnError) { 
       Log.e(TAG,"gnsdk -- musicIdStreamIdentifyCompletedWithError(); we received a response clbk, but failed to process it"); 
       mEvent.postOnGNSearchFailure(gnError.errorDescription()); 
      } 

      @Override 
      public void statusEvent(GnStatus gnStatus, long l, long l1, long l2, IGnCancellable iGnCancellable) { 
       Log.e(TAG,"gnsdk -- statusEvent(); status is: "+gnStatus); 
      } 
     }); 

     //configure the options on the gnmusicidstream instance 
     mGnMusicIdStream.options().lookupData(GnLookupData.kLookupDataContent, true); 
     mGnMusicIdStream.options().lookupData(GnLookupData.kLookupDataSonicData, true); 
     mGnMusicIdStream.options().lookupMode(GnLookupMode.kLookupModeOnline); 
     mGnMusicIdStream.options().preferResultCoverart(true); 
     mGnMusicIdStream.options().resultSingle(true); 

     //configure audio processing params on gnmusicidstream 
     mGnMusicIdStream.audioProcessStart(sampleRateHz,pcmBitcount,channelCount); 

     //pass the pcm array to the gnmusicidstream for processing 
     mGnMusicIdStream.audioProcess(pcmArray,pcmArray.length); 

     //initiate the lookup operation based on the processed pcm 
     mGnMusicIdStream.identifyAlbumAsync(); 


    }catch(GnException e){ 
     Log.e(TAG,"gnsdk -- failed recognition operation",e); 
    } 

返回數據是怎麼樣的混亂,與提取有關查詢的某些方面,而不是當在查詢時可以爲空或空軌道的元數據的多個潛在途徑其他方法。到目前爲止,我發現關於GnResponseAlbums響應對象有趣的觀點(我不知道下文提到的返回值的空性合同,所以,要當心NullPointerException異常):

  • gnResponseAlbums.resultCount()將如果沒有明確出錯,則爲0,但沒有找到匹配。

  • 匹配的GnTrack可以通過albumResponse檢索。trackMatched()

  • 音軌標題可以檢索與albumResponse.trackMatched()的字符串。標題()。顯示()

  • 軌道藝術家可以與albumResponse.artist()進行檢索。名().display()

  • 當前曲目的時間位置可以通過albumResponse.trackMatched()。currentPosition()來提取,這在確定歌曲結束的時間似乎非常精確{endTime = currentTime +持續時間 - currentPosition}

  • trackResponse.trackMatched()。duration()

  • 封面藝術URL可以通過albumResponse.coverArt()。asset(GnImageSize.kImageSizeSmall).urlHttp()來提取。

我沒有任何運氣得到通過albumResponse.coverArt()捆綁爲一個base64字符串的圖像。資產(GnImageSize.kImageSizeSmall).imageDataBase64(),但GNSDK提供了一個簡單GnAssetFetch類可用於下拉封面數據如下

GnAssetFetch assetData = new GnAssetFetch(mGnUser,coverArtUrl); 
byte[] data = assetData.data(); 

作爲用於消除在正在進行的操作中,可以使用的GnMusicIdStream實例的identifyCancel()方法。如果取消將發生在IGnMusicIdStreamEvents回調方法中,則應該使用提供的IGnCancellable消除器。