Files
Payload-SDK/samples/sample_c/module_sample/widget/test_widget_speaker.c
2022-05-30 12:09:41 +08:00

797 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
********************************************************************
* @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 DJIs 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)
/*! Attention: replace your audio device name here. */
#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_audio.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)
/* The speaker initialization parameters */
#define WIDGET_SPEAKER_DEFAULT_VOLUME (30)
#define EKHO_INSTALLED (1)
/* 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 *s_audioFile = NULL;
static FILE *s_ttsFile = NULL;
static bool s_isDecodeFinished = true;
/* Private functions declaration ---------------------------------------------*/
static void SetSpeakerState(E_DjiWidgetSpeakerState speakerState);
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;
}
returnCode = osalHandler->MutexLock(s_speakerMutex);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
return returnCode;
}
s_speakerState.state = DJI_WIDGET_SPEAKER_STATE_IDEL;
s_speakerState.workMode = DJI_WIDGET_SPEAKER_WORK_MODE_VOICE;
s_speakerState.playMode = DJI_WIDGET_SPEAKER_PLAY_MODE_SINGLE_PLAY;
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
return returnCode;
}
returnCode = SetVolume(WIDGET_SPEAKER_DEFAULT_VOLUME);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Set speaker volume 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) {
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...");
s_isDecodeFinished = true;
#endif
return EXIT_SUCCESS;
}
static T_DjiReturnCode DjiTest_PlayAudioData(void)
{
char cmdStr[128];
memset(cmdStr, 0, sizeof(cmdStr));
USER_LOG_INFO("Start Playing...");
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));
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_IN_TTS_CONVERSION);
#ifdef EKHO_INSTALLED
/*! 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);
#else
snprintf(cmdStr, sizeof(cmdStr), "tts_offline_sample '%s' %s", data,
WIDGET_SPEAKER_TTS_OUTPUT_FILE_NAME);
DjiUserUtil_RunSystemCmd(cmdStr);
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_PLAYING);
USER_LOG_INFO("Start TTS Playing...");
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_TTS_OUTPUT_FILE_NAME);
#endif
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) {
USER_LOG_INFO("MD5 sum check success");
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 void SetSpeakerState(E_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);
}
s_speakerState.state = speakerState;
returnCode = osalHandler->MutexUnlock(s_speakerMutex);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
}
}
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)
{
uint32_t pid;
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
pid = DjiTest_GetVoicePlayProcessId();
if (pid != 0) {
DjiTest_KillVoicePlayProcess(pid);
}
osalHandler->TaskSleepMs(5);
USER_LOG_INFO("Start widget speaker play");
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_PLAYING);
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.");
s_ttsFile = fopen(WIDGET_SPEAKER_TTS_FILE_NAME, "wb");
if (s_ttsFile == NULL) {
USER_LOG_ERROR("Open tts file error.");
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_TRANSMITTING);
}
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_TRANSMIT) {
USER_LOG_INFO("Transmit tts file, offset: %d, size: %d", offset, size);
if (s_ttsFile != NULL) {
fseek(s_ttsFile, offset, SEEK_SET);
writeLen = fwrite(buf, 1, size, s_ttsFile);
if (writeLen != size) {
USER_LOG_ERROR("Write tts file error %d", writeLen);
}
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_TRANSMITTING);
}
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_FINISH) {
USER_LOG_INFO("Close tts file.");
if (s_ttsFile != NULL) {
fclose(s_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");
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_IDEL);
}
}
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) {
s_isDecodeFinished = false;
USER_LOG_INFO("Create voice file.");
s_audioFile = fopen(WIDGET_SPEAKER_AUDIO_OPUS_FILE_NAME, "wb");
if (s_audioFile == NULL) {
USER_LOG_ERROR("Create tts file error.");
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_TRANSMITTING);
}
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_TRANSMIT) {
USER_LOG_INFO("Transmit voice file, offset: %d, size: %d", offset, size);
if (s_audioFile != NULL) {
fseek(s_audioFile, offset, SEEK_SET);
writeLen = fwrite(buf, 1, size, s_audioFile);
if (writeLen != size) {
USER_LOG_ERROR("Write tts file error %d", writeLen);
}
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_TRANSMITTING);
}
} else if (event == DJI_WIDGET_TRANSMIT_DATA_EVENT_FINISH) {
USER_LOG_INFO("Close voice file.");
if (s_audioFile != NULL) {
fclose(s_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");
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
}
if (s_speakerState.state != DJI_WIDGET_SPEAKER_STATE_PLAYING) {
SetSpeakerState(DJI_WIDGET_SPEAKER_STATE_IDEL);
}
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) {
USER_LOG_WARN("Waiting opus decoder finished...");
while (s_isDecodeFinished == false) {
osalHandler->TaskSleepMs(1);
}
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);
}
}
osalHandler->TaskSleepMs(1000);
} else {
if (s_speakerState.workMode == DJI_WIDGET_SPEAKER_WORK_MODE_VOICE) {
USER_LOG_WARN("Waiting opus decoder finished...");
while (s_isDecodeFinished == false) {
osalHandler->TaskSleepMs(1);
}
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);
}
if (s_speakerState.playMode == DJI_WIDGET_SPEAKER_PLAY_MODE_SINGLE_PLAY) {
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****/