您的位置:首页 > 移动开发 > Android开发

Echoprint系列--Android编译与调用

2016-02-21 21:35 483 查看
Echoprint系列--编译中编译了源代码,这次将Echoprint移植到Android平台并測试识别歌曲功能。

一、编译库

1、环境准备

Android NDK,我的是android-ndk-r10e改动源代码,把src中的.cxx的文件重命名为.cpp。把src文件夹重命名为jniBoost源代码。在PC上编译的时候也安装boost的,我的时boost_1_58_0,复制到jni文件夹

2、编写编译配置文件

打开源代码中的main.cpp,看到核心部分就是codegen_response_t *codegen_file(char* filename, int start_offset, int duration, int tag)
Notes about libcodegen:

Code generation takes a buffer of floating point PCM data sampled at 11025 Hz and mono.

Codegen * pCodegen = new Codegen(const float* pcm, uint numSamples, int start_offset);

pcm: a buffer of floats, mono, 11025 Hz
numSamples: the number of samples
start_offset: creates a hint to the server on where the sample is taken from in the original file if known

string code = pCodegen->getCodeString();
The code string is just a base64 encoding of a zlib compression of the original code string, which is a hex encoded series of ASCII numbers. See API/fp.py in echoprint-server for decoding help.

You only need to query for 20 seconds of audio to get a result.
打开Android Studio创建一个Android项目。新建一个文件名称为Codegen.java,在里面写入
native String codegen(float data[], int numSamples);
这次在移动设备上识别的是通过麦克风录音。所以參数不一样的,使用javah将Codegen.java生成头文件zhangjiedeMacBook-Pro:java zhangjie$ javah -classpath . -jni cc.jwzhangjie.echoprintandroid.Codegen在终端的当前文件夹会生成一个cc_jwzhangjie_echoprintandroid_Codegen.h在libs同文件夹创建一个jni文件夹,把cc_jwzhangjie_echoprintandroid_Codegen.h拷贝进去,然后创建cc_jwzhangjie_echoprintandroid_Codegen.cpp文件,内容例如以下:
#include <string.h>
#include "cc_jwzhangjie_echoprintandroid_Codegen.h"
#include "Codegen.h"

JNIEXPORT jstring JNICALL Java_cc_jwzhangjie_echoprintandroid_Codegen_codegen
(JNIEnv *env, jobject thiz, jfloatArray pcmData, jint numSamples){
float *data = (float *)env->GetFloatArrayElements(pcmData, 0);
Codegen c = Codegen(data, (unsigned int)numSamples, 0);
const char *code = c.getCodeString().c_str();
env->ReleaseFloatArrayElements(pcmData, data, 0);
return env->NewStringUTF(code);
}
在jni文件夹以下创建Android.mk和Application.mk。内容分别例如以下:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := echoprint-jni

LOCAL_SRC_FILES  := cc_jwzhangjie_echoprintandroid_Codegen.cpp \
Codegen.cpp \
Whitening.cpp \
SubbandAnalysis.cpp \
MatrixUtility.cpp \
Fingerprint.cpp \
Base64.cpp \
AudioStreamInput.cpp \
AudioBufferInput.cpp

LOCAL_LDLIBS     := -llog\
-lz

LOCAL_C_INCLUDES := . \
./boost_1_58_0

LOCAL_CPPFLAGS   += -fexceptions

include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := gnustl_static
APP_ABI := armeabi armeabi-v7a
把之前命名jni文件中面的内容复制到项目中的jni以下,在终端下输入:zhangjiedeMacBook-Pro:jni zhangjie$ ndk-build[armeabi] Compile++ thumb: echoprint-jni <= cc_jwzhangjie_echoprintandroid_Codegen.cpp[armeabi] Compile++ thumb: echoprint-jni <= Codegen.cpp[armeabi] Compile++ thumb: echoprint-jni <= Whitening.cpp[armeabi] Compile++ thumb: echoprint-jni <= SubbandAnalysis.cpp[armeabi] Compile++ thumb: echoprint-jni <= MatrixUtility.cpp[armeabi] Compile++ thumb: echoprint-jni <= Fingerprint.cpp[armeabi] Compile++ thumb: echoprint-jni <= Base64.cpp[armeabi] Compile++ thumb: echoprint-jni <= AudioStreamInput.cpp[armeabi] Compile++ thumb: echoprint-jni <= AudioBufferInput.cpp[armeabi] SharedLibrary : libechoprint-jni.so[armeabi] Install : libechoprint-jni.so => libs/armeabi/libechoprint-jni.so[armeabi-v7a] Compile++ thumb: echoprint-jni <= cc_jwzhangjie_echoprintandroid_Codegen.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= Codegen.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= Whitening.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= SubbandAnalysis.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= MatrixUtility.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= Fingerprint.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= Base64.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= AudioStreamInput.cpp[armeabi-v7a] Compile++ thumb: echoprint-jni <= AudioBufferInput.cpp[armeabi-v7a] SharedLibrary : libechoprint-jni.so[armeabi-v7a] Install : libechoprint-jni.so => libs/armeabi-v7a/libechoprint-jni.so如今成功编译出libechoprint-jni.so文件

二、调用库

Codegen.java这个类用来调用so将ccm生成code
package cc.jwzhangjie.echoprintandroid;

/**
* Created by zhangjie on 15/6/9.
*/
public class Codegen {

private final float normalizingValue = Short.MAX_VALUE;

native String codegen(float data[], int numSamples);

static
{
System.loadLibrary("echoprint-jni");
}

/**
* Invoke the echoprint native library and generate the fingerprint code.<br>
* Echoprint REQUIRES PCM encoded audio with the following parameters:<br>
* Frequency: 11025 khz<br>
* Data: MONO - PCM enconded float array
*
* @param data PCM encoded data as floats [-1, 1]
* @param numSamples number of PCM samples at 11025 KHz
* @return The generated fingerprint as a compressed - base64 string.
*/
public String generate(float data[], int numSamples)
{
return codegen(data, numSamples);
}

/**
* Invoke the echoprint native library and generate the fingerprint code.<br>
* Since echoprint requires the audio data to be an array of floats in the<br>
* range [-1, 1] this method will normalize the data array transforming the<br>
* 16 bit signed shorts into floats.
*
* @param data PCM encoded data as shorts
* @param numSamples number of PCM samples at 11025 KHz
* @return The generated fingerprint as a compressed - base64 string.
*/
public String generate(short data[], int numSamples)
{
// echoprint expects data as floats, which is the native value for
// core audio data, and I guess ffmpeg
// Android records data as 16 bit shorts, so we need to normalize the
// data before sending it to echoprint
float normalizeAudioData[] = new float[numSamples];
for (int i = 0; i < numSamples - 1; i++)
normalizeAudioData[i] = data[i] / normalizingValue;

return this.codegen(normalizeAudioData, numSamples);
}
}
AudioFingerprinter.java这个主要录音,首先要到 http://www.mooma.sh/api.html 申请一个api_key
package cc.jwzhangjie.echoprintandroid;import android.app.Activity;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.util.Log;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import org.json.JSONArray;import org.json.JSONObject;import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.util.Hashtable;public class AudioFingerprinter implements Runnable {public final static String META_SCORE_KEY = "meta_score";public final static String SCORE_KEY = "score";public final static String ALBUM_KEY = "release";public final static String TITLE_KEY = "track";public final static String TRACK_ID_KEY = "track_id";public final static String ARTIST_KEY = "artist";// Instead now using the MooMash API (http://www.mooma.sh/api.html).//   之前的Api接口已经弃用,如今Echoprint使用MooMash API。能够到http://www.mooma.sh/api.html申请一个api_keyprivate final String SERVER_URL = "http://api.mooma.sh/v1/song/identify?api_key=YOURMOOMASHAPIKEYHERE&code=";private final int FREQUENCY = 11025;private final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;private final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;private Thread thread;private volatile boolean isRunning = false;AudioRecord mRecordInstance = null;private short audioData[];private int bufferSize;private int secondsToRecord;private volatile boolean continuous;private AudioFingerprinterListener listener;/*** Constructor for the class** @param listener is the AudioFingerprinterListener that will receive the callbacks*/public AudioFingerprinter(AudioFingerprinterListener listener) {this.listener = listener;}/*** Starts the listening / fingerprinting process using the default parameters:<br>* A single listening pass of 20 seconds*/public void fingerprint() {// set dafault listening time to 20 secondsthis.fingerprint(20);}/*** Starts a single listening / fingerprinting pass** @param seconds the seconds of audio to record.*/public void fingerprint(int seconds) {// no continuous listeningthis.fingerprint(seconds, false);}/*** Starts the listening / fingerprinting process** @param seconds the number of seconds to record per pass* @param continuous if true, the class will start a new fingerprinting pass after each pass*/public void fingerprint(int seconds, boolean continuous) {if (this.isRunning)return;this.continuous = continuous;// cap to 30 seconds max, 10 seconds min.this.secondsToRecord = Math.max(Math.min(seconds, 30), 10);// start the recording threadthread = new Thread(this);thread.start();}/*** stops the listening / fingerprinting process if there's one in process*/public void stop() {this.continuous = false;if (mRecordInstance != null)mRecordInstance.stop();}/*** The main thread<br>* Records audio and generates the audio fingerprint, then it queries the server for a match and forwards the results to the listener.*/public void run() {this.isRunning = true;try {// create the audio buffer// get the minimum buffer sizeint minBufferSize = AudioRecord.getMinBufferSize(FREQUENCY, CHANNEL, ENCODING);// and the actual buffer size for the audio to record// frequency * seconds to record.bufferSize = Math.max(minBufferSize, this.FREQUENCY * this.secondsToRecord);audioData = new short[bufferSize];// start recordermRecordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC,FREQUENCY, CHANNEL,ENCODING, minBufferSize);willStartListening();mRecordInstance.startRecording();boolean firstRun = true;do {try {willStartListeningPass();long time = System.currentTimeMillis();// fill audio buffer with mic data.int samplesIn = 0;do {samplesIn += mRecordInstance.read(audioData, samplesIn, bufferSize - samplesIn);if (mRecordInstance.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED)break;}while (samplesIn < bufferSize);Log.e("Fingerprinter", "Audio recorded: " + (System.currentTimeMillis() - time) + " millis");// see if the process was stopped.if (mRecordInstance.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED || (!firstRun && !this.continuous))break;// create an echoprint codegen wrapper and get the codetime = System.currentTimeMillis();Codegen codegen = new Codegen();String code = codegen.generate(audioData, samplesIn);Log.e("Fingerprinter", "Codegen created in: " + (System.currentTimeMillis() - time) + " millis");if (code.length() == 0) {// no code?// not enough audio data?continue;}didGenerateFingerprintCode(code);// fetch data from echonesttime = System.currentTimeMillis();String urlstr = SERVER_URL + code;URL url = new URL(SERVER_URL+code);HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();InputStream instream = new BufferedInputStream(urlConnection.getInputStream());String  result = convertStreamToString(instream);instream.close();Log.e("Fingerprinter", "Results fetched in: " + (System.currentTimeMillis() - time) + " millis");// On successful recognition the MooMash API returns a JSON structure such as:// {"response":{"songs":[{"artist_id":"","artist_name":"P!nk","id":"","score":54,"title":"Don't Let Me Get Me","message":"OK"}],"status":{"version":"1.0","message":"Success","code":0}}}Log.e("AudioFingerprinter", "run - result: " + result);// parse JSONJSONObject jobj = new JSONObject(result);if (jobj.has("response")) {JSONObject responseObject = jobj.getJSONObject("response");if (responseObject.has("songs")) {JSONArray songsArray = responseObject.getJSONArray("songs");if (songsArray.length() > 0) {JSONObject songObject = songsArray.getJSONObject(0);Hashtable<String, String> match = new Hashtable<String, String>();match.put("artist_name", songObject.getString("artist_name"));match.put("title", songObject.getString("title"));didFindMatchForCode(match, code);} else {didNotFindMatchForCode(code);}}} else {didFailWithException(new Exception("result JSON parsing error"));}firstRun = false;didFinishListeningPass();} catch (Exception e) {e.printStackTrace();Log.e("Fingerprinter", e.getLocalizedMessage());didFailWithException(e);}}while (this.continuous);} catch (Exception e) {e.printStackTrace();Log.e("Fingerprinter", e.getLocalizedMessage());didFailWithException(e);}if (mRecordInstance != null) {mRecordInstance.stop();mRecordInstance.release();mRecordInstance = null;}this.isRunning = false;didFinishListening();}private static String convertStreamToString(InputStream is) {/** To convert the InputStream to String we use the BufferedReader.readLine()* method. We iterate until the BufferedReader return null which means* there's no more data to read. Each line will appended to a StringBuilder* and returned as String.*/BufferedReader reader = new BufferedReader(new InputStreamReader(is));StringBuilder sb = new StringBuilder();String line = null;try {while ((line = reader.readLine()) != null) {sb.append(line + "\n");}} catch (IOException e) {e.printStackTrace();} finally {try {is.close();} catch (IOException e) {e.printStackTrace();}}return sb.toString();}private String messageForCode(int code) {try {String codes[] = {"NOT_ENOUGH_CODE", "CANNOT_DECODE", "SINGLE_BAD_MATCH","SINGLE_GOOD_MATCH", "NO_RESULTS", "MULTIPLE_GOOD_MATCH_HISTOGRAM_INCREASED","MULTIPLE_GOOD_MATCH_HISTOGRAM_DECREASED", "MULTIPLE_BAD_HISTOGRAM_MATCH", "MULTIPLE_GOOD_MATCH"};return codes
;} catch (ArrayIndexOutOfBoundsException e) {return "UNKNOWN";}}private void didFinishListening() {Log.v("AudioFingerprinter", "didFinishListening");if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didFinishListening();}});} elselistener.didFinishListening();}private void didFinishListeningPass() {Log.v("AudioFingerprinter", "didFinishListeningPass");if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didFinishListeningPass();}});} elselistener.didFinishListeningPass();}private void willStartListening() {Log.v("AudioFingerprinter", "willStartListening");if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.willStartListening();}});} elselistener.willStartListening();}private void willStartListeningPass() {Log.v("AudioFingerprinter", "willStartListeningPass");if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.willStartListeningPass();}});} elselistener.willStartListeningPass();}private void didGenerateFingerprintCode(final String code) {Log.e("AudioFingerprinter", "didGenerateFingerprintCode - code: " + code);if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didGenerateFingerprintCode(code);}});} elselistener.didGenerateFingerprintCode(code);}private void didFindMatchForCode(final Hashtable<String, String> table, final String code) {Log.v("AudioFingerprinter", "didFindMatchForCode - table: " + table);if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didFindMatchForCode(table, code);}});} elselistener.didFindMatchForCode(table, code);}private void didNotFindMatchForCode(final String code) {Log.v("AudioFingerprinter", "didNotFindMatchForCode");if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didNotFindMatchForCode(code);}});} elselistener.didNotFindMatchForCode(code);}private void didFailWithException(final Exception e) {Log.v("AudioFingerprinter", "didFailWithException - e: " + e.getLocalizedMessage());if (listener == null)return;if (listener instanceof Activity) {Activity activity = (Activity) listener;activity.runOnUiThread(new Runnable() {public void run() {listener.didFailWithException(e);}});} elselistener.didFailWithException(e);}/*** Interface for the fingerprinter listener<br>* Contains the different delegate methods for the fingerprinting process* @author Alex Restrepo**/public interface AudioFingerprinterListener {/*** Called when the fingerprinter process loop has finished*/public void didFinishListening();/*** Called when a single fingerprinter pass has finished*/public void didFinishListeningPass();/*** Called when the fingerprinter is about to start*/public void willStartListening();/*** Called when a single listening pass is about to start*/public void willStartListeningPass();/*** Called when the codegen libary generates a fingerprint code* @param code the generated fingerprint as a zcompressed, base64 string*/public void didGenerateFingerprintCode(String code);/*** Called if the server finds a match for the submitted fingerprint code* @param table a hashtable with the metadata returned from the server* @param code the submited fingerprint code*/public void didFindMatchForCode(Hashtable<String, String> table, String code);/*** Called if the server DOES NOT find a match for the submitted fingerprint code* @param code the submited fingerprint code*/public void didNotFindMatchForCode(String code);/*** Called if there is an error / exception in the fingerprinting process* @param e an exception with the error*/public void didFailWithException(Exception e);}}
MainActivity.java界面类
package cc.jwzhangjie.echoprintandroid;import android.support.v4.app.FragmentActivity;import android.os.Bundle;import android.util.Log;import android.widget.CompoundButton;import android.widget.ToggleButton;import java.util.Hashtable;public class MainActivity extends FragmentActivity implements AudioFingerprinter.AudioFingerprinterListener{private ToggleButton recordMicBtn;private AudioFingerprinter mAudioFingerprinter;private String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mAudioFingerprinter = new AudioFingerprinter(this);recordMicBtn = (ToggleButton)findViewById(R.id.recordMicBtn);recordMicBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {if (isChecked){Log.e(TAG, "开启");mAudioFingerprinter.fingerprint();}else{Log.e(TAG, "关闭");mAudioFingerprinter.stop();}}});}@Overridepublic void didFinishListening() {Log.e(TAG, "录音完毕监听");}@Overridepublic void didFinishListeningPass() {Log.e(TAG, "录音监听完毕");}@Overridepublic void willStartListening() {Log.e(TAG, "录音将要開始监听");}@Overridepublic void willStartListeningPass() {Log.e(TAG, "录音监听開始");}@Overridepublic void didGenerateFingerprintCode(String code) {Log.e(TAG, "生成指纹Code");}@Overridepublic void didFindMatchForCode(Hashtable<String, String> table, String code) {Log.e(TAG, "匹配指纹Code");}@Overridepublic void didNotFindMatchForCode(String code) {Log.e(TAG, "没有匹配的指纹Code");}@Overridepublic void didFailWithException(Exception e) {Log.e(TAG, "失败匹配的指纹Code");}}
结果:[/code]
06-10 14:39:08.496  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 开启06-10 14:39:08.529  12416-21688/cc.jwzhangjie.echoprintandroid E/dalvikvm﹕ GC_FOR_ALLOC freed 1120K, 23% free 6806K/8775K, paused 14ms+2ms, total 34ms06-10 14:39:08.552  12416-21688/cc.jwzhangjie.echoprintandroid V/AudioFingerprinter﹕ willStartListening06-10 14:39:08.552  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 录音将要開始监听06-10 14:39:08.626  12416-21688/cc.jwzhangjie.echoprintandroid V/AudioFingerprinter﹕ willStartListeningPass06-10 14:39:08.626  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 录音监听開始06-10 14:39:28.626  12416-21688/cc.jwzhangjie.echoprintandroid E/Fingerprinter﹕ Audio recorded: 20000 millis06-10 14:39:28.663  12416-21688/cc.jwzhangjie.echoprintandroid E/dalvikvm﹕ GC_FOR_ALLOC freed 437K, 23% free 6806K/8775K, paused 4ms+4ms, total 36ms06-10 14:39:28.666  12416-21688/cc.jwzhangjie.echoprintandroid I/dalvikvm-heap﹕ Grow heap (frag case) to 7.721MB for 882016-byte allocation06-10 14:39:28.959  12416-12423/cc.jwzhangjie.echoprintandroid E/dalvikvm﹕ GC_FOR_ALLOC freed <1K, 21% free 7667K/9671K, paused 2ms+1ms, total 20ms06-10 14:39:28.969  12416-21688/cc.jwzhangjie.echoprintandroid D/Fingerprinter﹕ Codegen created in: 343 millis06-10 14:39:28.969  12416-21688/cc.jwzhangjie.echoprintandroid E/AudioFingerprinter﹕ didGenerateFingerprintCode - code: eJyll21uBC0OhK8E2IA5jvnw_Y-wD5F2530jDfmxUlSJOjPdplxVdqeUdKYHNHmBrReMeMFqL4j1gCzjASX5C9p5QMr9BaoveLOxygvOfsBf580vyOMFai9o-wU2XwDX3yHl_IJiL3h3YfUXxH5Avg__DrJfMOcLznrAH4q9dX-HoS_w9oBUygvePHt_wVvtu78gzgPyPfV3ePdozBfc4PkKf_TI1wNS9hdIfsEfmVNe8NPkr3DKA246PMDtBddqX-GPvJLyAj8PSMlfUPIL_kiV-oK3ns98QC77BXJeoPGC7i94q_09F2y8wOcDSLwX_JE55QUrPyAnecENvO8wn7BfUJK94B76O1R9QbcH_DE2_h-eZ3_B1gfkPF8w9gvmesH_04U_eG5fQdponmz2qGnJzNO87h6Sou_QtnafZdjOeK7ttmvWZbOETS1rn15zGylbPWP3XTG19S5ecvFS926irYqeskO4axqyVrfBfU9Pe2rtJ-Pl2qtqCRxvamfraBJVRjaPtLbOaW1prUeXCh9rK1qkI_luls34QM3jeHfhfnMW815bz7G4Txqz8L0PEFlqv659oLhwwJmzBXfpqnKnhSdtTT2d2j3vtfNO0ylzNR4xlNMV667jqIdmydGdHJndvbS0fVT3lU8xGb3Wn2d1vgtTMFr35A-rZhzVLPoKSIGmUmO4DG393sjCR86xZ5TgY8KrzZFhZ-jZ3iInM1292qTKsFppz4ECT17HhvAhGH1p5LY3t7k1qYTYtj61zRol9bPUxOJYHkM5znKjkXm0w3PiLBq7c1sitUpz9Xa8Tj6fJ205mdet-YGy5fiva__4b1pnhfgJErd07TJD-GvNreqjKMqLKFMyPJyTJnUPHjETohx3Zrkdk0RdcTXTzsJ_9NXoCd-YZ1odvLYsh8tZHZWPM6m3mjRZ_Shl-6ytec9j5WJQVzp7g5yM_AsNb9Ra6IdX62lZOtq12iqhEXXkFbOvRDNy9qJQMtI5JFfum8-yNm1ZmxMqrdF0ssiBPiGO0f-epc1VaGdynXoYaGMi8l7kFKlY2u-jlHe6dmqmmQk19yk1VRSAnaZZDwYS_txzu8_TZup724wP8KvJr2sf6D0QprlZ7RmVjTkjRdms9NapsaFTLIgpaFnjhXkjgUvJsLE0G17cOY8qaVejOlkywvnmaZVK0pXTahBdzrZ1qjbfdV8ppRbI89juWrIKpfcD4YiJB42YqI5TrpaNBKumpQzZC0GL45ZVY-PyaUlirUDEm7gRlcW31-hW5q5t5NZC6UXqRIm0FJi3plEte-dE3aPBvh-JnzhCxMKclUqTUTp9lr61ZU53JAn-W31ch6-lEGctPiB5U_C_r32gj4PXq_cbVPgbOc6NXJtmLFkXDEVGmpX7N4SOwXySpL5qqxPKObb4WjctqkjRPORwvO3VM54s2KLsvQYZ2KU2oUjOERyjQoejg-xOwqO5KJAyFWsQKYRcIsGP7tEQHIFHhAdcT_iyuW1Uhdo0yIFUjnu7Mey0CK2R-FpXXa4JWU_LEYIeWtUleR4aso7gbUo8OBo1o-ewMbrsG9SerZ10qUBMQsU0rhVuyDjsje7uQsisdd9A_gt17iW_rn3ACDB6VxoJiwA0hxZrsNIof1ROCqXGOGOikqwzEQBYcHV0IKvgtpLafenM6FzPxKRIfyifRx4Hc5QxbdBQ9OSS1hzS6qlbJjJPrd9oj2UEYjSOMrUT93i6mWyxhl8LVM-uNqxRymz4lrnAGJUy9YJTZF3lDEMYeo4whAg3i3mi-pIdyObA6MJzsjFv4T9CVjsJ6UzPOoPEJCZ-tlFY8SSMa4Zi38KE9yxO1DQ4j8ExCqfnFDIE_55yCJVkeJMp5FfW26GUi4wuTYwVEgoBDSisXvAfnapxPkDyw8y_r_0DYjKRKnVS-jBWAvoZRHYkjnxF3nMd0RIJWyG4aUBbRkuLQOdXLzrxNzwwNic367CYMeaqObhOtlx5I1X8TPoxI8om7nfDNZ1IQOXXr4fhkM24W2D2Zlgubv4EOl7CgtOzMCGEfWGEnc4PrSCGoaoMxioLyOTL1LWDmOe9sba7uBIflfRwvlgdqlaKGyK8lLCh5M0ApcO84JhkxvYdULpvW6GTsnthnyrsKa0X00o7x90o1NimdEr7wMxI69e1D-wbt3RweFuNLEisa-nO2M0DGKrsY4Nhnxj_obo7JG2pZd1wtUSOojXGAGJm7rACok0WPPY6dgW4o_ilLFLbf4xgE0YqQXrX4MKMomfU0fNirxDYPYaCmNS7N24qd01hO4mNspSlyrCIut10jMrE4OhkH4qvRXgGlUeCAGyMByaa-EmeMViB2CcIfpsyKgdRRJYC9xBomaDddx_Ka7J28pbkjbaQP0g2j7v77rs8Z2KuOI9mlCSmDkIjSv4HO8aIX9c-8B9xCJcT06-10 14:39:28.969  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 生成指纹CodeeJyll21uBC0OhK8E2IA5jvnw_Y-wD5F2530jDfmxUlSJOjPdplxVdqeUdKYHNHmBrReMeMFqL4j1gCzjASX5C9p5QMr9BaoveLOxygvOfsBf580vyOMFai9o-wU2XwDX3yHl_IJiL3h3YfUXxH5Avg__DrJfMOcLznrAH4q9dX-HoS_w9oBUygvePHt_wVvtu78gzgPyPfV3ePdozBfc4PkKf_TI1wNS9hdIfsEfmVNe8NPkr3DKA246PMDtBddqX-GPvJLyAj8PSMlfUPIL_kiV-oK3ns98QC77BXJeoPGC7i94q_09F2y8wOcDSLwX_JE55QUrPyAnecENvO8wn7BfUJK94B76O1R9QbcH_DE2_h-eZ3_B1gfkPF8w9gvmesH_04U_eG5fQdponmz2qGnJzNO87h6Sou_QtnafZdjOeK7ttmvWZbOETS1rn15zGylbPWP3XTG19S5ecvFS926irYqeskO4axqyVrfBfU9Pe2rtJ-Pl2qtqCRxvamfraBJVRjaPtLbOaW1prUeXCh9rK1qkI_luls34QM3jeHfhfnMW815bz7G4Txqz8L0PEFlqv659oLhwwJmzBXfpqnKnhSdtTT2d2j3vtfNO0ylzNR4xlNMV667jqIdmydGdHJndvbS0fVT3lU8xGb3Wn2d1vgtTMFr35A-rZhzVLPoKSIGmUmO4DG393sjCR86xZ5TgY8KrzZFhZ-jZ3iInM1292qTKsFppz4ECT17HhvAhGH1p5LY3t7k1qYTYtj61zRol9bPUxOJYHkM5znKjkXm0w3PiLBq7c1sitUpz9Xa8Tj6fJ205mdet-YGy5fiva__4b1pnhfgJErd07TJD-GvNreqjKMqLKFMyPJyTJnUPHjETohx3Zrkdk0RdcTXTzsJ_9NXoCd-YZ1odvLYsh8tZHZWPM6m3mjRZ_Shl-6ytec9j5WJQVzp7g5yM_AsNb9Ra6IdX62lZOtq12iqhEXXkFbOvRDNy9qJQMtI5JFfum8-yNm1ZmxMqrdF0ssiBPiGO0f-epc1VaGdynXoYaGMi8l7kFKlY2u-jlHe6dmqmmQk19yk1VRSAnaZZDwYS_txzu8_TZup724wP8KvJr2sf6D0QprlZ7RmVjTkjRdms9NapsaFTLIgpaFnjhXkjgUvJsLE0G17cOY8qaVejOlkywvnmaZVK0pXTahBdzrZ1qjbfdV8ppRbI89juWrIKpfcD4YiJB42YqI5TrpaNBKumpQzZC0GL45ZVY-PyaUlirUDEm7gRlcW31-hW5q5t5NZC6UXqRIm0FJi3plEte-dE3aPBvh-JnzhCxMKclUqTUTp9lr61ZU53JAn-W31ch6-lEGctPiB5U_C_r32gj4PXq_cbVPgbOc6NXJtmLFkXDEVGmpX7N4SOwXySpL5qqxPKObb4WjctqkjRPORwvO3VM54s2KLsvQYZ2KU2oUjOERyjQoejg-xOwqO5KJAyFWsQKYRcIsGP7tEQHIFHhAdcT_iyuW1Uhdo0yIFUjnu7Mey0CK2R-FpXXa4JWU_LEYIeWtUleR4aso7gbUo8OBo1o-ewMbrsG9SerZ10qUBMQsU0rhVuyDjsje7uQsisdd9A_gt17iW_rn3ACDB6VxoJiwA0hxZrsNIof1ROCqXGOGOikqwzEQBYcHV0IKvgtpLafenM6FzPxKRIfyifRx4Hc5QxbdBQ9OSS1hzS6qlbJjJPrd9oj2UEYjSOMrUT93i6mWyxhl8LVM-uNqxRymz4lrnAGJUy9YJTZF3lDEMYeo4whAg3i3mi-pIdyObA6MJzsjFv4T9CVjsJ6UzPOoPEJCZ-tlFY8SSMa4Zi38KE9yxO1DQ4j8ExCqfnFDIE_55yCJVkeJMp5FfW26GUi4wuTYwVEgoBDSisXvAfnapxPkDyw8y_r_0DYjKRKnVS-jBWAvoZRHYkjnxF3nMd0RIJWyG4aUBbRkuLQOdXLzrxNzwwNic367CYMeaqObhOtlx5I1X8TPoxI8om7nfDNZ1IQOXXr4fhkM24W2D2Zlgubv4EOl7CgtOzMCGEfWGEnc4PrSCGoaoMxioLyOTL1LWDmOe9sba7uBIflfRwvlgdqlaKGyK8lLCh5M0ApcO84JhkxvYdULpvW6GTsnthnyrsKa0X00o7x90o1NimdEr7wMxI69e1D-wbt3RweFuNLEisa-nO2M0DGKrsY4Nhnxj_obo7JG2pZd1wtUSOojXGAGJm7rACok0WPPY6dgW4o_ilLFLbf4xgE0YqQXrX4MKMomfU0fNirxDYPYaCmNS7N24qd01hO4mNspSlyrCIut10jMrE4OhkH4qvRXgGlUeCAGyMByaa-EmeMViB2CcIfpsyKgdRRJYC9xBomaDddx_Ka7J28pbkjbaQP0g2j7v77rs8Z2KuOI9mlCSmDkIjSv4HO8aIX9c-8B9xCJcT06-10 14:39:40.490  12416-21688/cc.jwzhangjie.echoprintandroid D/Fingerprinter﹕ Results fetched in: 11520 millis06-10 14:39:40.493  12416-21688/cc.jwzhangjie.echoprintandroid V/AudioFingerprinter﹕ run - result: {"response":{"status":{"version":"1.0","message":"Invalid or missing api key (unknown api key)","code":2}}}06-10 14:39:40.496  12416-21688/cc.jwzhangjie.echoprintandroid V/AudioFingerprinter﹕ didFinishListeningPass06-10 14:39:40.496  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 录音监听完毕06-10 14:39:40.520  12416-21688/cc.jwzhangjie.echoprintandroid V/AudioFingerprinter﹕ didFinishListening06-10 14:39:40.520  12416-12416/cc.jwzhangjie.echoprintandroid E/MainActivity﹕ 录音完毕监听
下载地址:包括jni整个项目 http://pan.baidu.com/s/1jGu1yce參考网址: http://www.mooma.sh/api.html http://masl.cis.gvsu.edu/2012/01/25/android-echoprint/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: