无法从Gracenote Mobile Client迁移到GNSDK for Mobile

时间:2017-11-11 02:39:43

标签: java android mobile gracenote

我正在努力将我的Android应用程序从旧版Gracenote移动客户端迁移到更新的GNSDK for Mobile SDK,我遇到了一些障碍:

  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中取消指纹和歌曲查找操作?

1 个答案:

答案 0 :(得分:0)

事实证明,您可以使用以下三个GnMusicIdStream API调用识别GNSDK for Android中的给定PCM阵列:

  1. GnMusicIdStream.audioProcessStart(sampleRateHz,pcmBitcount,channelCount)为传入的PCM准备识别引擎
  2. GnMusicIdStream.audioProcess(pcmArray,pcmArray.length)传入要识别的PCM阵列
  3. GnMusicIdStream.identifyAlbumAsync()生成指纹,然后将其用于查找操作。这将导致回传给传递给GnMusicIdStream实例的IGnMusicIdStreamEvents对象,而musicIdStreamAlbumResult()将传递任何结果。
  4. 据我所知,使用这种方法你不需要明确地等待指纹生成等 - 你只需按顺序调用这三种方法然后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响应对象的有趣观点(我不确定下面提到的返回值的可空性合同,所以要注意nullpointerexceptions):

    • gnResponseAlbums.resultCount()如果没有明确错误但是没有找到匹配项,则为0。

    • 可以使用albumResponse.trackMatched()

    • 检索匹配的GnTrack
    • 可以使用albumResponse.trackMatched()。title()。display()

    • 将曲目标题检索为字符串
    • 可以使用albumResponse.artist()检索曲目艺术家.name()。display()

    • 可以使用albumResponse.trackMatched()。currentPosition()提取当前曲目时间位置,这在确定歌曲结束的时间时似乎非常准确{endTime = currentTime + duration - currentPosition}

    • 可以使用albumResponse.trackMatched()提取曲目的持续时间。duration()

    • 可以使用albumResponse.coverArt()。asset(GnImageSize.kImageSizeSmall).urlHttp()提取封面艺术网址。

    我没有幸运通过albumResponse.coverArt()。asset(GnImageSize.kImageSizeSmall).imageDataBase64()将图像捆绑为base64字符串,但GNSDK提供了一个简单的GnAssetFetch类,可以使用它下载封面艺术数据如下

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

    对于取消正在进行的操作,可以使用GnMusicIdStream实例的identifyCancel()方法。如果取消将在IGnMusicIdStreamEvents回调方法中发生,则应使用提供的IGnCancellable取消器。