2017-11-11 128 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消除器。

相关问题