OpusFilePlay.c 10.5 KB
#include "JZsdkLib.h"

#include "../../Megaphone.h"
#include "../Megaphone_Opus.h"
#include "version_choose.h"
#include "BaseConfig.h"

#include "AudioDeal/AudioDeal.h"

#include "opus.h" 

#define OPUS_MAX_FRAME_SIZE     (6 * 960)
#define OPUS_CHANNELS           (1)
#define OPUS_MAX_PACKET_SIZE    (3 * 1276)

#define PCM_PLAY_FILE_NAME  "/root/test_audio.pcm" //用于播放的pcm

#define PCM_RATE        16000  //解码得到的pcm码率 目前仅支持16000码率
static int g_opus_decodeBitrate = 16000; //解码码率

static int g_Opus_play_Flag = JZ_FLAGCODE_OFF; //opus的播放标志位
static int g_Opus_decode_Flag = JZ_FLAGCODE_OFF; //opus的解码标志位
static T_JZTaskHandle g_DecodeOpus_task = NULL;
static T_JZTaskHandle g_OpusPlay_task = NULL;

/***************************************************************************************************************
 * 
 *  播放部分
 * 
 * 
****************************************************************************************************************/


static T_JZsdkReturnCode FixedFilePlay()
{
    FILE *PlayFixedFile_pcm_fp = NULL;
    unsigned int nbBytes;
    uint8_t cbits[3 * 1276];
    int timeNum = 0;
    int loop = JZ_FLAGCODE_OFF;
    int loop_interval;

    if(g_Opus_decode_Flag != JZ_FLAGCODE_OFF)
    {
        JZSDK_LOG_ERROR("opus解码超时,无法播放");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    g_Opus_play_Flag = JZ_FLAGCODE_ON;

    JZSDK_LOG_INFO("播放指定位置的opus pcm文件\n");
	PlayFixedFile_pcm_fp = fopen(PCM_PLAY_FILE_NAME, "r");
	if (PlayFixedFile_pcm_fp == NULL) 
    {
        JZSDK_LOG_ERROR("打开固定opus pcm文件失败\n");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 将文件指针移动到文件开头
    if (fseek(PlayFixedFile_pcm_fp, 0, SEEK_SET) != 0) 
    {
        JZSDK_LOG_ERROR("Failed to move file pointer to the beginning of the file");
        fclose(PlayFixedFile_pcm_fp);
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    while (Megaphone_MegDataGenFlag(JZ_FLAGCODE_GET, 0) == JZ_FLAGCODE_ON)
    {
        nbBytes = fread(cbits, 1, 3 * 1276, PlayFixedFile_pcm_fp);
		if(nbBytes > 0)
        {
            AudioDeal_PcmDataInput(PCM_RATE, (unsigned char *)cbits, nbBytes);
        }
		if (feof(PlayFixedFile_pcm_fp))
		{
            //如果循环播放没打开
            Megaphone_param(JZ_FLAGCODE_GET, MEGAPHONE_LOOP, &loop);
            Megaphone_param(JZ_FLAGCODE_GET, MEGAPHONE_LOOP_INTERVAL, &loop_interval);

            if (loop == JZ_FLAGCODE_OFF)
            {
                timeNum = 0;
                
                // //播放结束延迟
                // while ((timeNum <=3000) && (Megaphone_MegDataGenFlag(JZ_FLAGCODE_GET, 0) == JZ_FLAGCODE_ON))
                // {
                //     delayMs(10);
                //     timeNum +=10;
                // }

                break;
            }
            //如果循环播放打开
            else if (loop == JZ_FLAGCODE_ON)
            {
                timeNum = 0;
                JZSDK_LOG_INFO("循环播放opus");
                
                // //播放结束延迟
                // while ((loop == 1) && (Megaphone_MegDataGenFlag(JZ_FLAGCODE_GET, 0) == JZ_FLAGCODE_ON))
                // {
                //     delayMs(10);
                //     timeNum +=10;
                // }

                //重置文件光标 继续播放
                fseek(PlayFixedFile_pcm_fp, 0, SEEK_SET);

                //循环播放延时
                while (loop_interval > 0 && (loop == JZ_FLAGCODE_ON) && (Megaphone_MegDataGenFlag(JZ_FLAGCODE_GET, 0) == JZ_FLAGCODE_ON))
                {
                    delayMs(50);
                    loop_interval -= 50;
                }
                
                continue;
            }    
        }
    }
    
    fclose(PlayFixedFile_pcm_fp);

    g_Opus_play_Flag = JZ_FLAGCODE_OFF;
}

/*
*
*      播放固定位置pcm线程
*
*/
static void *PlayFixedFile_task(void *arg)
{
    Megaphone_MegDataGenFlag(JZ_FLAGCODE_SET, JZ_FLAGCODE_ON);
    Megaphone_MegDataGenFinshFlag(JZ_FLAGCODE_SET, JZ_FLAGCODE_ON);
    
    //广播开始
    Megaphone_status_Broadcast(AUDIO_PLAY_STATUS_OPUS_RECORD);

    int amplifier = JZ_FLAGCODE_ON;
    Megaphone_Amplifier_param(JZ_FLAGCODE_SET, &amplifier);
     
	FixedFilePlay();

    amplifier = JZ_FLAGCODE_OFF;
    Megaphone_Amplifier_param(JZ_FLAGCODE_SET, &amplifier);

    Megaphone_MegDataGenFlag(JZ_FLAGCODE_SET, JZ_FLAGCODE_OFF);
    Megaphone_MegDataGenFinshFlag(JZ_FLAGCODE_SET, JZ_FLAGCODE_OFF);

    //广播关闭
	Megaphone_status_Broadcast(JZ_FLAGCODE_OFF);
}

/*******************************
*
*      播放规定位置的opus文件
*      旧接口,无需定位传入的位置
*
************************************/
T_JZsdkReturnCode OpusFile_PlayFixedFile()
{
    T_JZsdkOsalHandler *OsalHandler = JZsdk_Platform_GetOsalHandler();

    OsalHandler->TaskCreate("PiayFilexdFile", PlayFixedFile_task, 8192, NULL, &g_DecodeOpus_task);

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}



/*************************************************************************************************************/

/*

    解码函数


*/
static T_JZsdkReturnCode OpusDecodeFun(unsigned char *OpusFile)
{
    FILE *fin = NULL;
    FILE *fout = NULL;
    OpusDecoder *decoder;
    opus_int16 out[OPUS_MAX_FRAME_SIZE * OPUS_CHANNELS];
    uint8_t cbits[OPUS_MAX_PACKET_SIZE];
    int32_t nbBytes;
    int32_t err;

    if (g_Opus_decode_Flag != JZ_FLAGCODE_OFF)
    {
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }
    
    g_Opus_decode_Flag = JZ_FLAGCODE_ON;

	printf("Decode Start 解码开始\n");   //解码开始

    //打开解码的opus文件
    //TODO: need delete
    //attention: you can use "ffmpeg -i xxx.mp3 -ar 16000 -ac 1 out.wav" and "./test_opus_tool out.wav out.opus" to generate opus file to test
    fin = fopen(OpusFile, "r");
    if (fin == NULL) {
        JZSDK_LOG_ERROR("fin打开失败");
        goto DecodeFinsh;
    }

    //创建一个解码器
    decoder = opus_decoder_create(PCM_RATE, OPUS_CHANNELS, &err);
    if (err < 0) {
        JZSDK_LOG_ERROR("解码器创建失败 %s",opus_strerror(err));
        goto DecodeFinsh;
    }

    //创建一个opus输出文件
    fout = fopen(PCM_PLAY_FILE_NAME, "w");
    if (fout == NULL) {
        JZSDK_LOG_ERROR("创建opus输出文件失败");
        goto DecodeFinsh;
    }

    printf("opus解码初始化完成\n");

    int frame_size;  

    while (1) 
    {
        int i;        
        opus_int16 TempPcm[OPUS_MAX_FRAME_SIZE * OPUS_CHANNELS];

        frame_size = 0;

        //读取opus内容
        /* Read a 16 bits/sample audio frame. */
        nbBytes = fread(cbits, 1, g_opus_decodeBitrate / 8000 * 40, fin);                          
        if (feof(fin))
        {
            break;
        }

        printf("fread nbBytes=%d\n",nbBytes);
        //printf("s_decodeBitrate=%d",s_decodeBitrate / OPUS_DECODE_BITRATE_8KBPS * OPUS_DECODE_FRAME_SIZE_8KBPS);
        /* 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. */

        //向解码器输入opus内容
        frame_size = opus_decode(decoder, cbits, nbBytes, out, OPUS_MAX_FRAME_SIZE, 0);
        if (frame_size < 0) {
            JZSDK_LOG_ERROR("decoder failed: %s",opus_strerror(frame_size));
            goto DecodeFinsh;
        }

        //解码完成
        printf("decode data to file: %d\r\n", frame_size * OPUS_CHANNELS);
        /* Convert to little-endian ordering. */
        
        for (i = 0; i < OPUS_CHANNELS * frame_size; i++) {
            TempPcm [i] = out[i] & 0xFF | (out[i] >> 8) << 8;
            //TempPcm[i] = PcmNoiseReduction(TempPcm[i]);
        }

        fwrite(TempPcm, sizeof(short), frame_size * OPUS_CHANNELS, fout);

    }

DecodeFinsh:

    //释放解码器
    if (decoder != NULL)
    {
        opus_decoder_destroy(decoder);
        printf("opus_decoder_destroy(decoder)\n");
    }
    
    //关闭文件
    if (fin != NULL)
    {
        fclose(fin);
        fin = NULL;
        printf("fclose(fin);\n");
    }
    
    //关闭文件
    if (fout != NULL)
    {
        fclose(fout);
        fout = NULL;
        printf("fclose(fout);\n");
    }

    if (frame_size < 0)
    {
        JZSDK_LOG_ERROR("opus解码失败");
        g_Opus_decode_Flag = JZ_FLAGCODE_OFF;
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }
    
    //解码完成
    JZSDK_LOG_INFO("Decode Finished...\n");   
    g_Opus_decode_Flag = JZ_FLAGCODE_OFF;
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

/*******************
*
*      opus解码线程
*
*******************/
static void *DecodeOpus_task(void *arg)
{
    unsigned char *opusFile = (unsigned char *)arg;

    T_JZsdkReturnCode ret = OpusDecodeFun(opusFile);
    if (ret != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
    {
        //广播解码失败
        Megaphone_Broadcast_OpusDecodeStatus(1);
    }
    else
    {
        Megaphone_Broadcast_OpusDecodeStatus(0);
    }

    free(opusFile);
}

T_JZsdkReturnCode OpusFile_DecodeOpus(unsigned char *opusFile)
{
    T_JZsdkOsalHandler *OsalHandler = JZsdk_Platform_GetOsalHandler();

    T_JZsdkReturnCode ret = JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;

    //因为播放的流通pcm文件只有一份,所以播放时,不能进行解码,不然会导致相当多问题
    int i = 0;
    while (i <= 4 && g_Opus_play_Flag == JZ_FLAGCODE_ON)
    {
        i++;
        delayMs(50);
    }
    
    //判断上一次播放是否结束 判断解码是否完成 
    if(i == 4)
    {    
        JZSDK_LOG_ERROR("超时200ms,上一次opus录音播放未结束,无法解码");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }
    
    i = 0;
    while (i<=4 && g_Opus_decode_Flag == JZ_FLAGCODE_ON)
    {
        i++;
        delayMs(50);
    }
    if(i == 4)
    {    
        JZSDK_LOG_ERROR("超时,上一次opus仍在解码,无法开始新的解码");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }  

    unsigned char *DecodeFile = OsalHandler->Malloc(strlen(opusFile));
    if(DecodeFile == NULL)
    {
        JZSDK_LOG_ERROR("DecodeFile malloc failed");
        return JZ_ERROR_SYSTEM_MODULE_CODE_MEMORY_ALLOC_FAILED;
    }
    memset(DecodeFile, strlen(opusFile), 0);
    memcpy(DecodeFile, opusFile, strlen(opusFile));
 
    OsalHandler->TaskCreate("DecodeOpus", DecodeOpus_task((void *)DecodeFile), 8192,NULL, &g_DecodeOpus_task);
    
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}