【问题标题】:Call recording with OpenSL使用 OpenSL 进行通话录音
【发布时间】:2017-05-27 16:17:52
【问题描述】:

自从我的 Galaxy S5 更新了棒棒糖后,我尝试修复我的应用程序中的通话录音。作为基础,我从这里使用 google 示例项目:Sample

这是代码的主要部分:

AudioRecorder::AudioRecorder(SampleFormat *sampleFormat, SLEngineItf slEngine) :freeQueue_(nullptr), recQueue_(nullptr), devShadowQueue_(nullptr), callback_(nullptr)

SLresult result;
sampleInfo_ = *sampleFormat;
SLAndroidDataFormat_PCM_EX format_pcm;
ConvertToSLSampleFormat(&format_pcm, &sampleInfo_);

gFp = fopen("/storage/emulated/0/file.pcm", "w");

// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
                                  SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audioSrc = {&loc_dev, NULL};


// configure audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
        SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
        DEVICE_SHADOW_BUFFER_QUEUE_LEN};

SLDataSink audioSnk = {&loc_bq, &format_pcm};

// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                             SL_IID_ANDROIDCONFIGURATION};

const SLboolean req[2] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};

result = (*slEngine)->CreateAudioRecorder(slEngine,
                                          &recObjectItf_,
                                          &audioSrc,
                                          &audioSnk,
                                          2,
                                          id, req);
SLASSERT(result);

// Configure the voice recognition preset which has no
// signal processing for lower latency.
SLAndroidConfigurationItf inputConfig;
result = (*recObjectItf_)->GetInterface(recObjectItf_,
                                        SL_IID_ANDROIDCONFIGURATION,
                                        &inputConfig);

SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
result = (*inputConfig)->SetConfiguration(inputConfig,
                                          SL_ANDROID_KEY_RECORDING_PRESET,
                                          &presetValue,
                                          sizeof(SLint32));
SLASSERT(result);


result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE);
SLASSERT(result);

result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_);
SLASSERT(result);

result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                                        &recBufQueueItf_);
SLASSERT(result);

result = (*recBufQueueItf_)->RegisterCallback(recBufQueueItf_, bqRecorderCallback, this);
SLASSERT(result);

devShadowQueue_ = new AudioQueue(DEVICE_SHADOW_BUFFER_QUEUE_LEN);
assert(devShadowQueue_);

这是我的问题,这段代码不记录通话的另一端,在输出文件中我只能听到麦克风的声音。我尝试更改参数但结果相同。有谁知道我做错了什么?

【问题讨论】:

  • 你好@rafal-depta,你有什么解决方案可以在android中进行相同的或通话录音吗?任何帮助都会非常显着。提前谢谢你。
  • 您好@CchanchalShelar 来解决这个问题您需要使用 Android NDK 在 C++ 中编写一些代码。
  • 谢谢@rafal-depta 的提示,有什么可能的参考吗?
  • 您好,请您提供 cpp 文件的更新代码。任何帮助都将是可观的。
  • 我也没有找到 AudioQueue 的 cpp 文件或类,请帮我找到它。提前致谢...

标签: android android-ndk audio-recording voice-recording


【解决方案1】:

我找到了修复 Galaxy S5 通话录音的解决方案。

主要是这样称呼: status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) 在通话开始时的循环中。

首先得到想要的函数:

open_media = dlopen("/system/lib/libmedia.so", RTLD_LAZY);

set_parameters = (int (*)(int, void *)) dlsym(open_media,
                                                  "_ZN7android11AudioSystem13setParametersEiRKNS_7String8E");

接下来我们需要audio_io_handle_tString8& 对象:

  1. audio_io_handle_t- 是音频会话 id 增加 1,您可以从 AudioRecord.getAudioSessionId 获取
  2. String8&这个比较难:

    //First inicialize function 
    create_string = (void (*)(void *, const char *)) dlsym(open_util, 
    "_ZN7android7String8C2EPKc");
    
    //next call this function to convert string to required object 
    create_string(&str8, str);
    

当我们拥有所有需要的部分时,我们可以调用 setParameters 函数:

//remember to call this in loop when recording is starting
set_parameters(id + 1, &str8);

变量声明的样子:

int (*set_parameters)(int, void *);

void (*create_string)(void *, const char *);

void *str8 = 0;
const char *str = "input_source=4";

@ChanchalShelar


@彼得@AkshatVajpayee

这是我的 .cpp 文件的外观:

void *open_media;
void *open_util;

int (*set_parameters)(int, void *);

void (*create_string)(void *, const char *);

void *str8 = 0;
const char *str = "input_source=4";


extern "C" {
    JNIEXPORT bool JNICALL
    Java_com_sample_NativeAudio_init(JNIEnv *env, jclass);
    JNIEXPORT int JNICALL
    Java_com_sample_NativeAudio_setParameters(JNIEnv *env, jclass, int id);
}


void get_string8() {
    create_string = (void (*)(void *, const char *)) dlsym(open_util, "_ZN7android7String8C2EPKc");

    if (!create_string) {
        LOGD("There is no create_string function");
    } else {
        LOGD("create_string function OK");
    }

    create_string(&str8, str);
    if (!str8) {
        LOGD("Filed to create str8");
    } else {
        LOGD("create str8 success");
    }

}

JNIEXPORT int JNICALL Java_com_sample_NativeAudio_setParameters(JNIEnv *env,
                                                                  jclass     type, int id) {
    if (set_parameters) {
        return set_parameters(id + 1, &str8);
    }

    return 0;
}


JNIEXPORT bool JNICALL Java_com_sample_NativeAudio_init(JNIEnv *env, jclass type) {

    open_util = dlopen("/system/lib/libutils.so", RTLD_LAZY);

    if (open_util) {
        get_string8();
    } else {
        return false;
    }

    open_media = dlopen("/system/lib/libmedia.so", RTLD_LAZY);

    if (open_media) {
        set_parameters = (int (*)(int, void *)) dlsym(open_media,
                                              "_ZN7android11AudioSystem13setParametersEiRKNS_7String8E");
    } else {
        return false;
    }

    return true;
}

【讨论】:

  • @androiddeveloper 这里:github.com/ViktorDegtyarev/CallRecLib/tree/master 是解决方案。描述中是讨论链接
  • @RafałDepta 在这种情况下,很遗憾我已经对其进行了测试,但它不起作用。我不知道它在哪些设备上有效,但在我测试过的所有设备上,它都不起作用。
  • @androiddeveloper 不幸的是我不能做更多的事情
【解决方案2】:

您需要使用 ndk。以下是需要完成的功能示例。

加载 libmedia.so 和 libutils.so

int load(JNIEnv *env, jobject thiz) {
    void *handleLibMedia;
    void *handleLibUtils;
    int result = -1;
    lspr func = NULL;

    pthread_t newthread = (pthread_t) thiz;

    handleLibMedia = dlopen("libmedia.so", RTLD_NOW | RTLD_GLOBAL);
    if (handleLibMedia != NULL) {
        func = dlsym(handleLibMedia, "_ZN7android11AudioSystem13setParametersEiRKNS_7String8E");
        if (func != NULL) {
            result = 0;
        }
        audioSetParameters = (lasp) func;
    } else {
        result = -1;
    }

    handleLibUtils = dlopen("libutils.so", RTLD_NOW | RTLD_GLOBAL);
    if (handleLibUtils != NULL) {
        fstr = dlsym(handleLibUtils, "_ZN7android7String8C2EPKc");
        if (fstr == NULL) {
            result = -1;
        }
    } else {
        result = -1;
    }

    cmd = CM_D;

    int resultTh = pthread_create(&newthread, NULL, taskAudioSetParam, NULL);

    return result;}

函数集参数

int setParam(jint i, jint as) {
pthread_mutex_lock(&mt);

audioSession = (int) (as + 1);

kvp = "input_source=4";
kvps = toString8(kvp);

cmd = (int) i;

pthread_cond_signal(&cnd);
pthread_mutex_unlock(&mt);

return 0;}

任务音频设置参数

void *taskAudioSetParam(void *threadid) {
    while (1) {
        pthread_mutex_lock(&mt);
        if (cmd == CM_D) {
            pthread_cond_wait(&cnd, &mt);
        } else if (audioSetParameters != NULL) {
             audioSetParameters(audioSession, kvps);
        }
        pthread_mutex_unlock(&mt);
    }
}

有一个库和一个使用例子https://github.com/ViktorDegtyarev/CallRecLib

【讨论】:

  • 您好,我想知道您的库是否仍然有效。因为我注意到您的应用使用了 arc 的 so 文件。
  • 我是ndk 的新手,我已经在lib 上面尝试过,但它不起作用,任何帮助都会被接受。谢谢
猜你喜欢
  • 2013-10-02
  • 2018-01-17
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 2016-04-29
  • 2011-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多