Qualcomm 远程信息处理 SDK - 用户指南(5)

281 篇文章 30 订阅
150 篇文章 14 订阅

Qualcomm 远程信息处理 SDK - 用户指南(5)


4.1.9 播放 DTMF 音

此示例应用程序演示如何使用音频 API 在活动语音通话期间播放 DTMF 音。请注意,目前仅支持 Rx 方向。

1.获取AudioFactory实例

auto &audioFactory = AudioFactory::getInstance();
  1. 获取 AudioManager 实例并检查音频子系统准备情况
std::promise<ServiceStatus> prom{};
// Get AudioManager instance.
audioManager = audioFactory.getAudioManager([&prom](ServiceStatus serviceStatus) {
    prom.set_value(serviceStatus);
});
if (!audioManager) {
    std::cout << "Failed to get AudioManager instance" << std::endl;
    return;
}
// Check if audio subsystem is ready
// If audio subsystem is not ready, wait for it to be ready
ServiceStatus managerStatus = audioManager->getServiceStatus();
if (managerStatus != ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "\nAudio subsystem is not ready, Please wait ..." << std::endl;
    managerStatus = prom.get_future().get();
}
// Check the service status again
if (managerStatus == ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "Audio Subsytem is Ready << std::endl;
} else {
    std::cout << "ERROR - Unable to initialize audio subsystem" << std::endl;
    return;
}
  1. 创建音频流(与语音通话会话关联)
// Callback which provides response to createStream
void createStreamCallback(std::shared_ptr<IAudioStream> &stream, ErrorCode error) {
    if (error != ErrorCode::SUCCESS) {
        std::cout << "createStream() failed with error" << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "createStream() succeeded." << std::endl;
    audioVoiceStream = std::dynamic_pointer_cast<IAudioVoiceStream>(stream);
}
StreamConfig config;
config.type = StreamType::VOICE_CALL;
config.slotId = DEFAULT_SLOT_ID;
config.sampleRate = 16000;
config.format = AudioFormat::PCM_16BIT_SIGNED;
config.channelTypeMask = ChannelType::LEFT;
/*For StreamType::VOICE_CALL, sink and source device are required to be passed.
  First device should be sink (speaker) and then source (mic) should be passed
  for stream creation.*/
config.deviceTypes.emplace_back(DeviceType::DEVICE_TYPE_SPEAKER);
config.deviceTypes.emplace_back(DeviceType::DEVICE_TYPE_MIC);
status = audioManager->createStream(config, createStreamCallback);
  1. 开始语音通话会话
// Callback which provides response to startAudio
void startAudioCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "startAudio() failed with error " << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "startAudio() succeeded." << std::endl;
}
status = audioVoiceStream->startAudio(startAudioCallback);
  1. 播放 DTMF 音
// Implement a response function to get the request status
void playDtmfCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "playDtmfTone() failed with error" << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "playDtmfTone() succeeded." << std::endl;
}
// Play the DTMF tone with required configuration
status = audioVoiceStream->playDtmfTone(dtmfTone, duration, gain, playDtmfCallback);
  1. 停止语音通话会话
// Callback which provides response to stopAudio
void stopAudioCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "stopAudio() failed with error " << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "stopAudio() succeeded." << std::endl;
}
status = audioVoiceStream->stopAudio(stopAudioCallback);
  1. 处理与语音通话会话关联的音频流
// Implement a response callback method to get the request status
void deleteStreamCallback(ErrorCode error) {
    if (error != ErrorCode::SUCCESS) {
        std::cout << "deleteStream() failed with error" << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "deleteStream() succeeded." << std::endl;
    audioVoiceStream->reset();
}
status = audioManager->deleteStream(std::dynamic_pointer_cast<IAudioStream>(audioVoiceStream),
                                deleteStreamCallback);

4.1.10 检测 DTMF 音

此示例应用程序演示如何使用音频 API 在活动语音通话期间检测 DTMF 音调。请注意,当前仅支持 Rx 方向。

1.获取AudioFactory实例

auto &audioFactory = AudioFactory::getInstance();
  1. 获取 AudioManager 实例并检查音频子系统准备情况
std::promise<ServiceStatus> prom{};
// Get AudioManager instance
audioManager = audioFactory.getAudioManager([&prom](ServiceStatus serviceStatus) {
    prom.set_value(serviceStatus);
});
if (!audioManager) {
    std::cout << "Failed to get AudioManager instance" << std::endl;
    return;
}
// Check if audio subsystem is ready
// If audio subsystem is not ready, wait for it to be ready
ServiceStatus managerStatus = audioManager->getServiceStatus();
if (managerStatus != ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "\nAudio subsystem is not ready, Please wait ..." << std::endl;
    managerStatus = prom.get_future().get();
}
// Check the service status again
if (managerStatus == ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "Audio Subsytem is Ready << std::endl;
} else {
    std::cout << "ERROR - Unable to initialize audio subsystem" << std::endl;
    return;
}
  1. 如果SDK无法初始化音频子系统,则退出应用程序
if(isReady) {
    std::cout << " *** Audio subsystem is ready *** " << std::endl;
} else {
    std::cout << " *** ERROR - Unable to initialize audio subsystem " << std::endl;
    return 1;
}
  1. 创建音频流(与语音通话会话关联)
// Callback which provides response to createStream
void createStreamCallback(std::shared_ptr<IAudioStream> &stream, ErrorCode error) {
    if (error != ErrorCode::SUCCESS) {
        std::cout << "createStream() failed with error" << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "createStream() succeeded." << std::endl;
    audioVoiceStream = std::dynamic_pointer_cast<IAudioVoiceStream>(stream);
}
StreamConfig config;
config.type = StreamType::VOICE_CALL;
config.slotId = DEFAULT_SLOT_ID;
config.sampleRate = 16000;
config.format = AudioFormat::PCM_16BIT_SIGNED;
config.channelTypeMask = ChannelType::LEFT;
/*For StreamType::VOICE_CALL, sink and source device are required to be passed.
  First device should be sink (speaker) and then source (mic) should be passed
  for stream creation.*/
config.deviceTypes.emplace_back(DeviceType::DEVICE_TYPE_SPEAKER);
config.deviceTypes.emplace_back(DeviceType::DEVICE_TYPE_MIC);
status = audioManager->createStream(config, createStreamCallback);
  1. 开始语音通话会话
// Callback which provides response to startAudio
void startAudioCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "startAudio() failed with error " << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "startAudio() succeeded." << std::endl;
}
status = audioVoiceStream->startAudio(startAudioCallback);

  1. 注册监听器以获取有关 DTMF 音检测的通知
// Callback which provides response to registerListener
void registerListenerCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "registerListener() failed with error " << static_cast<int>(error)
                            << std::endl;
        return;
    }
    std::cout << "registerListener() succeeded." << std::endl;
}
// Instantiate MyVoiceListener
auto myDtmfToneListener = std::make_shared<MyVoiceListener>();
// Register the listener
status = audioVoiceStream->registerListener(myDtmfToneListener, registerListenerCallback);
  1. 取消注册监听器以停止接收通知
status = audioVoiceStream->deRegisterListener(myDtmfToneListener);

  1. 停止语音通话会话
// Callback which provides response to stopAudio
void stopAudioCallback(ErrorCode error)
{
    if (error != ErrorCode::SUCCESS) {
        std::cout << "stopAudio() failed with error " << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "stopAudio() succeeded." << std::endl;
}
status = audioVoiceStream->stopAudio(stopAudioCallback);
  1. 处理与语音通话会话关联的音频流
// Implement a response callback method to get the request status
void deleteStreamCallback(ErrorCode error) {
    if (error != ErrorCode::SUCCESS) {
        std::cout << "deleteStream() failed with error" << static_cast<int>(error) << std::endl;
        return;
    }
    std::cout << "deleteStream() succeeded." << std::endl;
    audioVoiceStream->reset();
}
status = audioManager->deleteStream(std::dynamic_pointer_cast<IAudioStream>(audioVoiceStream),
                                deleteStreamCallback);

4.1.11 转码示例

此示例应用程序演示了如何使用音频 API 对音频样本进行转码。

1.获取AudioFactory实例

auto &audioFactory = AudioFactory::getInstance();
  1. 获取 AudioManager 实例并检查音频子系统准备情况
std::promise<ServiceStatus> prom{};
// Get AudioManager instance
audioManager = audioFactory.getAudioManager([&prom](ServiceStatus serviceStatus) {
    prom.set_value(serviceStatus);
});
if (!audioManager) {
    std::cout << "Failed to get AudioManager object" << std::endl;
    return;
}
// Check if audio subsystem is ready
// If audio subsystem is not ready, wait for it to be ready
ServiceStatus managerStatus = audioManager->getServiceStatus();
if (managerStatus != ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "\nAudio subsystem is not ready, Please wait ..." << std::endl;
    managerStatus = prom.get_future().get();
}
// Check the service status again
if (managerStatus == ServiceStatus::SERVICE_AVAILABLE) {
    std::cout << "Audio Subsytem is Ready << std::endl;
} else {
    std::cout << "ERROR - Unable to initialize audio subsystem" << std::endl;
    return;
}
  1. 创建音频转码器
FormatInfo inputConfig_;
FormatInfo outputConfig_;
// input and output parameters are configured for AMRWB_PLUS
// to PCM_16BIT_SIGNED transcoding operation as an example.
AmrwbpParams inputParams{};
inputConfig_.sampleRate = SAMPLE_RATE;
inputConfig_.mask = CHANNEL_MASK;
inputConfig_.format = AudioFormat::AMRWB_PLUS;
inputParams.bitWidth = 16;
inputParams.frameFormat = AmrwbpFrameFormat::FILE_STORAGE_FORMAT;
inputConfig_.params = &inputParams;
inputConfig_.sampleRate = SAMPLE_RATE;
outputConfig_.mask = CHANNEL_MASK;
outputConfig_.format = AudioFormat::PCM_16BIT_SIGNED;
outputConfig_.params = nullptr;
audioManager->createTranscoder(inputConfig_, outputConfig_,
[&p,this](std::shared_ptr<telux::audio::ITranscoder> &transcoder,
    telux::common::ErrorCode error) {
    if (error == telux::common::ErrorCode::SUCCESS) {
        transcoder_ = transcoder;
        registerListener();
        p.set_value(true);
    } else {
        p.set_value(false);
        std::cout << "failed to create transcoder" <<std::endl;
    }
});
if (p.get_future().get()) {
    std::cout<< "Transcoder Created" << std::endl;
}

4.1 为写操作分配音频缓冲区

// Get an audio buffer for write operation (we can get more than one)
auto audioBuffer = transcoder_->getWriteBuffer();
if (audioBuffer != nullptr) {
    // Setting the size of buffer that need to be supplied for write operation as the minimum
    // size required by transcoder. In any case if size returned is 0, using the Maximum
    // Buffer Size, any buffer size between min and max can be used
    size = audioBuffer->getMinSize();
    if (size == 0) {
        size =  audioBuffer->getMaxSize();
    }
    audioBuffer->setDataSize(size);
} else {
    std::cout << "Failed to get Audio Buffer for write operation " << std::endl;
}

4.2 为读操作分配音频缓冲区

// Get an audio buffer for read operation (we can get more than one)
auto audioBuffer = transcoder_->getReadBuffer();
if (audioBuffer != nullptr) {
    // Setting the size of buffer that need to be supplied for read operation as the minimum
    // size required by transcoder. In any case if size returned is 0, using the Maximum
    // Buffer Size, any buffer size between min and max can be used
    size = audioBuffer->getMinSize();
    if (size == 0) {
        size =  audioBuffer->getMaxSize();
    }
    audioBuffer->setDataSize(size);
} else {
    std::cout << "Failed to get Audio Buffer for read operation " << std::endl;
}
  1. 在一个线程中启动写操作进行转码
// Callback which provides response to write operation
void writeCallback(std::shared_ptr<IAudioBuffer> buffer,
    uint32_t bytes, ErrorCode error) {
    std::cout << "Bytes Written : " << bytes << std::endl;
    if (error != ErrorCode::SUCCESS || buffer->getDataSize() != bytes) {
        // Application needs to resend the Bitstream buffer from leftover position if bytes
        // consumed are not equal to requested number of bytes to be written.
        pipeLineEmpty_ = false;
    }
    buffer->reset();
    writeBuffers_.push(buffer);
    cv_.notify_all();
    return;
}
// Indiction Received only when callback returns with error that bytes written are not equal to
// bytes requested to write. It notifies that pipeline is ready to accept new buffer to write.
void onReadyForWrite() {
    pipeLineEmpty_ = true;
}
// Write request for transcoding
auto writeCb = std::bind(&TranscoderApp::writeCallback, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3);
telux::common::Status status = telux::common::Status::FAILED;
// EOF_REACHED denotes flag which indicated EOF is reached
// EOF_NOT_REACHED denotes flag which indicated EOF is not reached
if (EOF_REACHED) {
    status = transcoder_->write(audioBuffer, EOF_REACHED,  writeCb);
} else {
    status = transcoder_->write(audioBuffer, EOF_NOT_REACHED,  writeCb);
}
if (status != telux::common::Status::SUCCESS) {
    std::cout << "write() failed with error" << static_cast<unsigned int>(status) << std::endl;
} else {
    std::cout << "Request to transcode buffers sent " << std::endl;
}

6.在另一个线程中启动读操作进行转码

// Callback which provides response to read operation
void readCallback(std::shared_ptr<telux::audio::IAudioBuffer> buffer,
    uint32_t isLastBuffer, telux::common::ErrorCode error) {
    if (isLastBuffer) {
        // Stop reading from now onwards as this is the last transcoded buffer
    }
    if (error != telux::common::ErrorCode::SUCCESS) {
        std::cout << "read() returned with error " << static_cast<unsigned int>(error)
                << std::endl;
    } else {
        // readed buffer can be stored on a file if required.
    }
    buffer->reset();
    readBuffers_.push(buffer);
    cv_.notify_all();
    return;
}
// Read request for transcoding
auto readCb =  std::bind(&TranscoderApp::readCallback, this,
        std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
telux::common::Status status = transcoder_->read(audioBuffer, bytesToRead, readCb);
if (status != telux::common::Status::SUCCESS) {
    std::cout << "read() failed with error" << static_cast<unsigned int>(status) << std::endl;
}
  1. 拆除音频转码器实例
// Tear down is supposed to be called after the last buffer is received
// for write operation. It is supposed to be called after every transcoding
// operation as transcoder instance can not be used for multiple transcoding
// operations.
std::promise<bool> p;
auto status = transcoder_->tearDown([&p](telux::common::ErrorCode error) {
    if (error == telux::common::ErrorCode::SUCCESS) {
        p.set_value(true);
    } else {
        p.set_value(false);
        std::cout << "Failed to tear down" << std::endl;
    }
});
if (status == telux::common::Status::SUCCESS) {
    std::cout << "Request to Teardown transcoder sent" << std::endl;
} else {
    std::cout << "Request to Teardown transcoder failed" << std::endl;
}
if (p.get_future().get()) {
    transcoder_ = nullptr;
    std::cout << "Tear Down successful !!" << std::endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值