NEW: release DJI Payload-SDK version 3.1
Signed-off-by: DJI-Martin <DJI-Martin@dji.com>
This commit is contained in:
708
samples/sample_c/module_sample/widget/test_widget_speaker.c
Normal file
708
samples/sample_c/module_sample/widget/test_widget_speaker.c
Normal file
@ -0,0 +1,708 @@
|
||||
/**
|
||||
********************************************************************
|
||||
* @file test_widget_speaker.c
|
||||
* @brief
|
||||
*
|
||||
* @copyright (c) 2018 DJI. All rights reserved.
|
||||
*
|
||||
* All information contained herein is, and remains, the property of DJI.
|
||||
* The intellectual and technical concepts contained herein are proprietary
|
||||
* to DJI and may be covered by U.S. and foreign patents, patents in process,
|
||||
* and protected by trade secret or copyright law. Dissemination of this
|
||||
* information, including but not limited to data and other proprietary
|
||||
* material(s) incorporated within the information, in any form, is strictly
|
||||
* prohibited without the express written consent of DJI.
|
||||
*
|
||||
* If you receive this source code without DJI’s authorization, you may not
|
||||
* further disseminate the information, and you must immediately remove the
|
||||
* source code and notify DJI of its removal. DJI reserves the right to pursue
|
||||
* legal actions against you for any loss(es) or damage(s) caused by your
|
||||
* failure to do so.
|
||||
*
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#ifdef SYSTEM_ARCH_LINUX
|
||||
|
||||
#include "test_widget_speaker.h"
|
||||
#include "dji_logger.h"
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "utils/util_misc.h"
|
||||
#include "utils/util_md5.h"
|
||||
|
||||
#ifdef OPUS_INSTALLED
|
||||
|
||||
#include <opus.h>
|
||||
|
||||
#endif
|
||||
|
||||
/* Private constants ---------------------------------------------------------*/
|
||||
#define WIDGET_SPEAKER_TASK_STACK_SIZE (2048)
|
||||
|
||||
#define WIDGET_SPEAKER_USB_AUDIO_DEVICE_NAME "alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo"
|
||||
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_FILE_NAME "test_audio.opus"
|
||||
#define WIDGET_SPEAKER_AUDIO_PCM_FILE_NAME "test_audio.pcm"
|
||||
|
||||
#define WIDGET_SPEAKER_TTS_FILE_NAME "test_tts.txt"
|
||||
#define WIDGET_SPEAKER_TTS_OUTPUT_FILE_NAME "tts_sample.wav"
|
||||
#define WIDGET_SPEAKER_TTS_FILE_MAX_SIZE (3000)
|
||||
|
||||
/*The frame size is hardcoded for this sample code but it doesn't have to be*/
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_MAX_PACKET_SIZE (3 * 1276)
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_MAX_FRAME_SIZE (6 * 960)
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_SAMPLE_RATE (16000)
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS (1)
|
||||
#define WIDGET_SPEAKER_AUDIO_OPUS_DECODE_FRAME_SIZE (160)
|
||||
|
||||
/* Private types -------------------------------------------------------------*/
|
||||
|
||||
/* Private values -------------------------------------------------------------*/
|
||||
static T_DjiWidgetSpeakerHandler s_speakerHandler = {0};
|
||||
static T_DjiMutexHandle s_speakerMutex = {0};
|
||||
static T_DjiWidgetSpeakerState s_speakerState = {0};
|
||||
static T_DjiTaskHandle s_widgetSpeakerTestThread;
|
||||
|
||||
static FILE *audioFile = NULL;
|
||||
static FILE *ttsFile = NULL;
|
||||
|
||||
/* Private functions declaration ---------------------------------------------*/
|
||||
static T_DjiReturnCode GetSpeakerState(T_DjiWidgetSpeakerState *speakerState);
|
||||
static T_DjiReturnCode SetWorkMode(E_DjiWidgetSpeakerWorkMode workMode);
|
||||
static T_DjiReturnCode GetWorkMode(E_DjiWidgetSpeakerWorkMode *workMode);
|
||||
static T_DjiReturnCode SetPlayMode(E_DjiWidgetSpeakerPlayMode playMode);
|
||||
static T_DjiReturnCode GetPlayMode(E_DjiWidgetSpeakerPlayMode *playMode);
|
||||
static T_DjiReturnCode StartPlay(void);
|
||||
static T_DjiReturnCode StopPlay(void);
|
||||
static T_DjiReturnCode SetVolume(uint8_t volume);
|
||||
static T_DjiReturnCode GetVolume(uint8_t *volume);
|
||||
static T_DjiReturnCode ReceiveTtsData(E_DjiWidgetTransmitDataEvent event,
|
||||
uint32_t offset, uint8_t *buf, uint16_t size);
|
||||
static T_DjiReturnCode ReceiveAudioData(E_DjiWidgetTransmitDataEvent event,
|
||||
uint32_t offset, uint8_t *buf, uint16_t size);
|
||||
static void *DjiTest_WidgetSpeakerTask(void *arg);
|
||||
static uint32_t DjiTest_GetVoicePlayProcessId(void);
|
||||
static uint32_t DjiTest_KillVoicePlayProcess(uint32_t pid);
|
||||
static T_DjiReturnCode DjiTest_DecodeAudioData(void);
|
||||
static T_DjiReturnCode DjiTest_PlayAudioData(void);
|
||||
static T_DjiReturnCode DjiTest_PlayTtsData(void);
|
||||
static T_DjiReturnCode DjiTest_CheckFileMd5Sum(const char *path, uint8_t *buf, uint16_t size);
|
||||
|
||||
/* Exported functions definition ---------------------------------------------*/
|
||||
T_DjiReturnCode DjiTest_WidgetSpeakerStartService(void)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
s_speakerHandler.GetSpeakerState = GetSpeakerState;
|
||||
s_speakerHandler.SetWorkMode = SetWorkMode;
|
||||
s_speakerHandler.GetWorkMode = GetWorkMode;
|
||||
s_speakerHandler.StartPlay = StartPlay;
|
||||
s_speakerHandler.StopPlay = StopPlay;
|
||||
s_speakerHandler.SetPlayMode = SetPlayMode;
|
||||
s_speakerHandler.GetPlayMode = GetPlayMode;
|
||||
s_speakerHandler.SetVolume = SetVolume;
|
||||
s_speakerHandler.GetVolume = GetVolume;
|
||||
s_speakerHandler.ReceiveTtsData = ReceiveTtsData;
|
||||
s_speakerHandler.ReceiveVoiceData = ReceiveAudioData;
|
||||
|
||||
returnCode = osalHandler->MutexCreate(&s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Create speaker mutex error: 0x%08llX", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
returnCode = DjiWidget_RegSpeakerHandler(&s_speakerHandler);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Register speaker handler error: 0x%08llX", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
if (osalHandler->TaskCreate("user_widget_speaker_task", DjiTest_WidgetSpeakerTask, WIDGET_SPEAKER_TASK_STACK_SIZE,
|
||||
NULL,
|
||||
&s_widgetSpeakerTestThread) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Dji widget speaker test task create error.");
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Private functions definition-----------------------------------------------*/
|
||||
static uint32_t DjiTest_GetVoicePlayProcessId(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char cmdStr[128];
|
||||
uint32_t pid;
|
||||
int ret;
|
||||
|
||||
snprintf(cmdStr, 128, "pgrep ffplay");
|
||||
fp = popen(cmdStr, "r");
|
||||
if (fp == NULL) {
|
||||
USER_LOG_ERROR("fp is null.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = fscanf(fp, "%u", &pid);
|
||||
if (ret <= 0) {
|
||||
USER_LOG_ERROR("get pid error.");
|
||||
pid = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
pclose(fp);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static uint32_t DjiTest_KillVoicePlayProcess(uint32_t pid)
|
||||
{
|
||||
FILE *fp;
|
||||
char cmdStr[128];
|
||||
|
||||
snprintf(cmdStr, 128, "kill %d", pid);
|
||||
fp = popen(cmdStr, "r");
|
||||
if (fp == NULL) {
|
||||
USER_LOG_ERROR("fp is null.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode DjiTest_DecodeAudioData(void)
|
||||
{
|
||||
#ifdef OPUS_INSTALLED
|
||||
FILE *fin;
|
||||
FILE *fout;
|
||||
OpusDecoder *decoder;
|
||||
opus_int16 out[WIDGET_SPEAKER_AUDIO_OPUS_MAX_FRAME_SIZE * WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS];
|
||||
uint8_t cbits[WIDGET_SPEAKER_AUDIO_OPUS_MAX_PACKET_SIZE];
|
||||
int32_t nbBytes;
|
||||
int32_t err;
|
||||
|
||||
/*! Attention: you can use "ffmpeg -i xxx.mp3 -ar 16000 -ac 1 out.wav" and use opus-tools to generate opus file for test */
|
||||
fin = fopen(WIDGET_SPEAKER_AUDIO_OPUS_FILE_NAME, "r");
|
||||
if (fin == NULL) {
|
||||
fprintf(stderr, "failed to open input file: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a new decoder state. */
|
||||
decoder = opus_decoder_create(WIDGET_SPEAKER_AUDIO_OPUS_SAMPLE_RATE, WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS, &err);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fout = fopen(WIDGET_SPEAKER_AUDIO_PCM_FILE_NAME, "w");
|
||||
if (fout == NULL) {
|
||||
fprintf(stderr, "failed to open output file: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
USER_LOG_INFO("Decode Start...");
|
||||
|
||||
while (1) {
|
||||
int i;
|
||||
unsigned char pcm_bytes[WIDGET_SPEAKER_AUDIO_OPUS_MAX_FRAME_SIZE * WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS * 2];
|
||||
int frame_size;
|
||||
|
||||
/* Read a 16 bits/sample audio frame. */
|
||||
nbBytes = fread(cbits, 1, WIDGET_SPEAKER_AUDIO_OPUS_DECODE_FRAME_SIZE, fin);
|
||||
if (feof(fin))
|
||||
break;
|
||||
|
||||
/* Decode the data. In this example, frame_size will be constant because
|
||||
the encoder is using a constant frame size. However, that may not
|
||||
be the case for all encoders, so the decoder must always check
|
||||
the frame size returned. */
|
||||
frame_size = opus_decode(decoder, cbits, nbBytes, out, WIDGET_SPEAKER_AUDIO_OPUS_MAX_FRAME_SIZE, 0);
|
||||
if (frame_size < 0) {
|
||||
fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
USER_LOG_DEBUG("decode data to file: %d\r\n", frame_size * WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS);
|
||||
/* Convert to little-endian ordering. */
|
||||
for (i = 0; i < WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS * frame_size; i++) {
|
||||
pcm_bytes[2 * i] = out[i] & 0xFF;
|
||||
pcm_bytes[2 * i + 1] = (out[i] >> 8) & 0xFF;
|
||||
}
|
||||
/* Write the decoded audio to file. */
|
||||
fwrite(pcm_bytes, sizeof(short), frame_size * WIDGET_SPEAKER_AUDIO_OPUS_CHANNELS, fout);
|
||||
}
|
||||
|
||||
/*Destroy the encoder state*/
|
||||
opus_decoder_destroy(decoder);
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
|
||||
USER_LOG_INFO("Decode Finished...");
|
||||
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode DjiTest_PlayAudioData(void)
|
||||
{
|
||||
char cmdStr[128];
|
||||
|
||||
memset(cmdStr, 0, sizeof(cmdStr));
|
||||
|
||||
snprintf(cmdStr, sizeof(cmdStr), "ffplay -nodisp -autoexit -ar 16000 -ac 1 -f s16le -i %s 2>/dev/null",
|
||||
WIDGET_SPEAKER_AUDIO_PCM_FILE_NAME);
|
||||
|
||||
return DjiUserUtil_RunSystemCmd(cmdStr);
|
||||
}
|
||||
|
||||
static T_DjiReturnCode DjiTest_PlayTtsData(void)
|
||||
{
|
||||
FILE *txtFile;
|
||||
uint8_t data[WIDGET_SPEAKER_TTS_FILE_MAX_SIZE] = {0};
|
||||
int32_t readLen;
|
||||
char cmdStr[WIDGET_SPEAKER_TTS_FILE_MAX_SIZE + 128];
|
||||
|
||||
txtFile = fopen(WIDGET_SPEAKER_TTS_FILE_NAME, "r");
|
||||
if (txtFile == NULL) {
|
||||
fprintf(stderr, "failed to open input file: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
readLen = fread(data, 1, WIDGET_SPEAKER_TTS_FILE_MAX_SIZE, txtFile);
|
||||
if (readLen <= 0) {
|
||||
USER_LOG_ERROR("Read tts file failed, error code: %d", readLen);
|
||||
fclose(txtFile);
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_NOT_FOUND;
|
||||
}
|
||||
|
||||
fclose(txtFile);
|
||||
|
||||
USER_LOG_INFO("Read tts file success, len: %d", readLen);
|
||||
USER_LOG_INFO("Content: %s", data);
|
||||
|
||||
memset(cmdStr, 0, sizeof(cmdStr));
|
||||
|
||||
/*! Attention: you can use other tts opensource function to convert txt to speech, example used ekho v7.5 */
|
||||
snprintf(cmdStr, sizeof(cmdStr), " ekho %s -s 20 -p 20 -a 100", data);
|
||||
|
||||
return DjiUserUtil_RunSystemCmd(cmdStr);
|
||||
}
|
||||
|
||||
static T_DjiReturnCode DjiTest_CheckFileMd5Sum(const char *path, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
MD5_CTX md5Ctx;
|
||||
uint32_t readFileTotalSize = 0;
|
||||
uint16_t readLen;
|
||||
T_DjiReturnCode returnCode;
|
||||
uint8_t readBuf[1024];
|
||||
uint8_t md5Sum[16];
|
||||
FILE *file = NULL;;
|
||||
|
||||
UtilMd5_Init(&md5Ctx);
|
||||
|
||||
file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
USER_LOG_ERROR("Open tts file error.");
|
||||
}
|
||||
|
||||
while (1) {
|
||||
returnCode = fseek(file, readFileTotalSize, SEEK_SET);
|
||||
if (returnCode != 0) {
|
||||
USER_LOG_INFO("fseek file error");
|
||||
}
|
||||
|
||||
readLen = fread(readBuf, 1, sizeof(readBuf), file);
|
||||
if (readLen > 0) {
|
||||
readFileTotalSize += readLen;
|
||||
UtilMd5_Update(&md5Ctx, readBuf, readLen);
|
||||
}
|
||||
|
||||
if (feof(file))
|
||||
break;
|
||||
}
|
||||
|
||||
UtilMd5_Final(&md5Ctx, md5Sum);
|
||||
fclose(file);
|
||||
|
||||
if (size == sizeof(md5Sum)) {
|
||||
if (memcmp(md5Sum, buf, sizeof(md5Sum)) == 0) {
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
} else {
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
|
||||
}
|
||||
} else {
|
||||
USER_LOG_ERROR("MD5 sum length error");
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode GetSpeakerState(T_DjiWidgetSpeakerState *speakerState)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
*speakerState = s_speakerState;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode SetWorkMode(E_DjiWidgetSpeakerWorkMode workMode)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
USER_LOG_INFO("Set widget speaker work mode: %d", workMode);
|
||||
s_speakerState.workMode = workMode;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode GetWorkMode(E_DjiWidgetSpeakerWorkMode *workMode)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
*workMode = s_speakerState.workMode;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode SetPlayMode(E_DjiWidgetSpeakerPlayMode playMode)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
USER_LOG_INFO("Set widget speaker play mode: %d", playMode);
|
||||
s_speakerState.playMode = playMode;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode GetPlayMode(E_DjiWidgetSpeakerPlayMode *playMode)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
*playMode = s_speakerState.playMode;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode StartPlay(void)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
USER_LOG_INFO("Start widget speaker play");
|
||||
s_speakerState.state = DJI_WIDGET_SPEAKER_STATE_PLAYING;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode StopPlay(void)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
uint32_t pid;
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
USER_LOG_INFO("Stop widget speaker play");
|
||||
s_speakerState.state = DJI_WIDGET_SPEAKER_STATE_IDEL;
|
||||
|
||||
pid = DjiTest_GetVoicePlayProcessId();
|
||||
if (pid != 0) {
|
||||
DjiTest_KillVoicePlayProcess(pid);
|
||||
}
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode SetVolume(uint8_t volume)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
char cmdStr[128];
|
||||
int32_t ret = 0;
|
||||
float realVolume;
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
realVolume = 1.5f * (float) volume;
|
||||
USER_LOG_INFO("Set widget speaker volume: %d", volume);
|
||||
s_speakerState.volume = volume;
|
||||
|
||||
memset(cmdStr, 0, sizeof(cmdStr));
|
||||
snprintf(cmdStr, sizeof(cmdStr), "pactl set-sink-volume %s %d%%", WIDGET_SPEAKER_USB_AUDIO_DEVICE_NAME,
|
||||
(int32_t) realVolume);
|
||||
|
||||
returnCode = DjiUserUtil_RunSystemCmd(cmdStr);
|
||||
if (returnCode < 0) {
|
||||
USER_LOG_ERROR("Set widget speaker volume error: %d", ret);
|
||||
}
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode GetVolume(uint8_t *volume)
|
||||
{
|
||||
T_DjiReturnCode returnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
returnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
*volume = s_speakerState.volume;
|
||||
|
||||
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode ReceiveTtsData(E_DjiWidgetTransmitDataEvent event,
|
||||
uint32_t offset, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
uint16_t writeLen;
|
||||
T_DjiReturnCode returnCode;
|
||||
|
||||
if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_START) {
|
||||
USER_LOG_INFO("Create tts file.");
|
||||
ttsFile = fopen(WIDGET_SPEAKER_TTS_FILE_NAME, "wb");
|
||||
if (ttsFile == NULL) {
|
||||
USER_LOG_ERROR("Open tts file error.");
|
||||
}
|
||||
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_TRANSMIT) {
|
||||
USER_LOG_INFO("Transmit tts file, offset: %d, size: %d", offset, size);
|
||||
if (ttsFile != NULL) {
|
||||
fseek(ttsFile, offset, SEEK_SET);
|
||||
writeLen = fwrite(buf, 1, size, ttsFile);
|
||||
if (writeLen != size) {
|
||||
USER_LOG_ERROR("Write tts file error %d", writeLen);
|
||||
}
|
||||
}
|
||||
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_FINISH) {
|
||||
USER_LOG_INFO("Close tts file.");
|
||||
if (ttsFile != NULL) {
|
||||
fclose(ttsFile);
|
||||
}
|
||||
|
||||
returnCode = DjiTest_CheckFileMd5Sum(WIDGET_SPEAKER_TTS_FILE_NAME, buf, size);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("File md5 sum check failed");
|
||||
}
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static T_DjiReturnCode ReceiveAudioData(E_DjiWidgetTransmitDataEvent event,
|
||||
uint32_t offset, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
uint16_t writeLen;
|
||||
T_DjiReturnCode returnCode;
|
||||
|
||||
if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_START) {
|
||||
USER_LOG_INFO("Create voice file.");
|
||||
audioFile = fopen(WIDGET_SPEAKER_AUDIO_OPUS_FILE_NAME, "wb");
|
||||
if (audioFile == NULL) {
|
||||
USER_LOG_ERROR("Create tts file error.");
|
||||
}
|
||||
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_TRANSMIT) {
|
||||
USER_LOG_INFO("Transmit voice file, offset: %d, size: %d", offset, size);
|
||||
if (audioFile != NULL) {
|
||||
fseek(audioFile, offset, SEEK_SET);
|
||||
writeLen = fwrite(buf, 1, size, audioFile);
|
||||
if (writeLen != size) {
|
||||
USER_LOG_ERROR("Write tts file error %d", writeLen);
|
||||
}
|
||||
}
|
||||
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_FINISH) {
|
||||
USER_LOG_INFO("Close voice file.");
|
||||
if (audioFile != NULL) {
|
||||
fclose(audioFile);
|
||||
}
|
||||
|
||||
returnCode = DjiTest_CheckFileMd5Sum(WIDGET_SPEAKER_AUDIO_OPUS_FILE_NAME, buf, size);
|
||||
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("File md5 sum check failed");
|
||||
}
|
||||
|
||||
DjiTest_DecodeAudioData();
|
||||
}
|
||||
|
||||
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef __CC_ARM
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
||||
#pragma GCC diagnostic ignored "-Wreturn-type"
|
||||
#endif
|
||||
|
||||
static void *DjiTest_WidgetSpeakerTask(void *arg)
|
||||
{
|
||||
T_DjiReturnCode djiReturnCode;
|
||||
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
|
||||
|
||||
USER_UTIL_UNUSED(arg);
|
||||
|
||||
while (1) {
|
||||
osalHandler->TaskSleepMs(10);
|
||||
|
||||
if (s_speakerState.state == DJI_WIDGET_SPEAKER_STATE_PLAYING) {
|
||||
if (s_speakerState.playMode == DJI_WIDGET_SPEAKER_PLAY_MODE_LOOP_PLAYBACK) {
|
||||
if (s_speakerState.workMode == DJI_WIDGET_SPEAKER_WORK_MODE_VOICE) {
|
||||
djiReturnCode = DjiTest_PlayAudioData();
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Play audio data failed, error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
} else {
|
||||
djiReturnCode = DjiTest_PlayTtsData();
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Play tts data failed, error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (s_speakerState.workMode == DJI_WIDGET_SPEAKER_WORK_MODE_VOICE) {
|
||||
djiReturnCode = DjiTest_PlayAudioData();
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Play audio data failed, error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
} else {
|
||||
djiReturnCode = DjiTest_PlayTtsData();
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("Play tts data failed, error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
}
|
||||
|
||||
djiReturnCode = osalHandler->MutexLock(s_speakerMutex);
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("lock mutex error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
|
||||
s_speakerState.state = DJI_WIDGET_SPEAKER_STATE_IDEL;
|
||||
|
||||
djiReturnCode = osalHandler->MutexUnlock(s_speakerMutex);
|
||||
if (djiReturnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
|
||||
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", djiReturnCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __CC_ARM
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/****************** (C) COPYRIGHT DJI Innovations *****END OF FILE****/
|
53
samples/sample_c/module_sample/widget/test_widget_speaker.h
Normal file
53
samples/sample_c/module_sample/widget/test_widget_speaker.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
********************************************************************
|
||||
* @file test_widget_speaker.h
|
||||
* @brief This is the header file for "test_widget_speaker.c", defining the structure and
|
||||
* (exported) function prototypes.
|
||||
*
|
||||
* @copyright (c) 2018 DJI. All rights reserved.
|
||||
*
|
||||
* All information contained herein is, and remains, the property of DJI.
|
||||
* The intellectual and technical concepts contained herein are proprietary
|
||||
* to DJI and may be covered by U.S. and foreign patents, patents in process,
|
||||
* and protected by trade secret or copyright law. Dissemination of this
|
||||
* information, including but not limited to data and other proprietary
|
||||
* material(s) incorporated within the information, in any form, is strictly
|
||||
* prohibited without the express written consent of DJI.
|
||||
*
|
||||
* If you receive this source code without DJI’s authorization, you may not
|
||||
* further disseminate the information, and you must immediately remove the
|
||||
* source code and notify DJI of its removal. DJI reserves the right to pursue
|
||||
* legal actions against you for any loss(es) or damage(s) caused by your
|
||||
* failure to do so.
|
||||
*
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef TEST_WIDGET_SPEAKER_H
|
||||
#define TEST_WIDGET_SPEAKER_H
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "dji_widget.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef SYSTEM_ARCH_LINUX
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
T_DjiReturnCode DjiTest_WidgetSpeakerStartService(void);
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TEST_WIDGET_SPEAKER_H
|
||||
/************************ (C) COPYRIGHT DJI Innovations *******END OF FILE******/
|
@ -7,6 +7,10 @@
|
||||
"floating_window": {
|
||||
"is_enable": true
|
||||
},
|
||||
"speaker": {
|
||||
"is_enable_tts": true,
|
||||
"is_enable_voice": true
|
||||
},
|
||||
"widget_list": [
|
||||
{
|
||||
"widget_index": 0,
|
||||
|
@ -7,6 +7,10 @@
|
||||
"floating_window": {
|
||||
"is_enable": true
|
||||
},
|
||||
"speaker": {
|
||||
"is_enable_tts": true,
|
||||
"is_enable_voice": true
|
||||
},
|
||||
"widget_list": [
|
||||
{
|
||||
"widget_index": 0,
|
||||
|
Reference in New Issue
Block a user