spresenseで96kHzサンプリングレートにて音声の再生と録音を同時に行いたい


spresenseメインボードとB-stem PDA01
SPRESENSE用機能拡張ボードを用いて開発を行っています。実現したいことは、超音波信号を再生し、その伝播や反響を取得するために96kHzサンプリングで信号を再生し、同時に96kHz以上（おそらく、192kHz)で録音をしたいと思っています。  
素人質問で申し訳ないですが、このような機能は実現可能か知りたいです。

できればarduinoにて開発したいのですが、マルチコア処理ですとaudio libraryは使えないとなっていました。audio
libraryに信号の再生と録音を同時に行う機能は含まれていますか？  
もし、上記が実現できない場合はspresense SDKによる開発で実現可能でしょうか？  
よろしくお願いします。




興味があったので、実際に記録と再生を同時に動かすことをやってみました。  
基本的にできると思います。自分はできました。

サンプルにある  
player_objIf.ino  
と  
recorder_wav_objif.ino  
をマージすればよいです。

ただし、  
player_objIf.ino  
は、MP3の再生なので、96kHzを再生するのであれば、WAVしかなく、その変更が必要です。

[code]

    thePlayer->init(MediaPlayer::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_96000, AS_CHANNEL_MONO);
    
[/code]

また、記録もノーマルレゾリューションなので、

[code]

    static const uint32_t recoding_sampling_rate = 192000;
    static const uint8_t  recoding_cannel_number = 1;
    static const uint8_t  recoding_bit_length = 16;
    
[/code]

にしました。

ちなみに、記録は、16k,48k,192kしかないので、192kになりますね。

で、ハイレゾの記録再生同時になると、SDカードのアクセス速度がネックになるので、読み書きのバッファが足りなくなるので、変更しています。

[code]

     thePlayer->activate(MediaPlayer::Player0, mediaplayer_done_callback, 1024*2*20);
      theRecorder->activate(AS_SETRECDR_STS_INPUTDEVICE_MIC, mediarecorder_done_callback, (768*2*8)*30);
    
[/code]

サイズは合わせて調整すると良いと思います。

で、このサイズだと、メモリが足りなくなるので、  
タブにある  
tool/  
Memory:768KB(default)  
を  
Memory:896KB  
に替えました。

もう一点、終端処理のケアが必要になります。  
おそらく、記録と再生を別なタスクにすればよいのかもしれないですが、  
双方の停止でアプリのループが止まるため、どちらかが止まると両方止まります。

なので、終端処理を以下にしました。

[code]

    stop_player:    
      theRecorder->stop();
      thePlayer->stop(MediaPlayer::Player0);
      execute_frames();    
      /* Get ramaining data(flushing) */
      sleep(1); /* For data pipline stop */
      theRecorder->writeWavHeader(recFile);
      puts("Update Header!");
      playFile.close();
      recFile.close();
    
      thePlayer->deactivate(MediaPlayer::Player0);
      theRecorder->deactivate();
      thePlayer->end();
      theRecorder->end();
      puts("End Recording");
      exit(1);
    
[/code]

特に記録側のstopは、ループ側にstopがあるので、こちらに移動してきました。

これで、動かしたところ、動作できています。

ご参考になれば。

[code]

    #include &lt;SDHCI.h>
    #include &lt;MediaRecorder.h>
    #include &lt;MediaPlayer.h>
    #include &lt;OutputMixer.h>
    #include &lt;MemoryUtil.h>
    
    #define RECORD_FILE_NAME "Recorde.wav"
    #define ANALOG_MIC_GAIN  0 /* +0dB */
    SDClass theSD;
    
    MediaRecorder *theRecorder;
    MediaPlayer *thePlayer;
    OutputMixer *theMixer;
    
    File playFile;
    File recFile;
    
    bool ErrEnd = false;
    
    
    /* Recording bit rate
     * Set in bps.
     */
    
    //static const uint32_t recoding_bitrate = 48000*8*2;
    static const uint32_t recoding_bitrate = 192000*8*2;
    
    /* Sampling rate
     * Set 16000 or 48000
     */
    
    static const uint32_t recoding_sampling_rate = 192000;
    
    /* Number of input channels
     * Set either 1, 2, or 4.
     */
    
    static const uint8_t  recoding_cannel_number = 1;
    
    /* Audio bit depth
     * Set 16 or 24
     */
    
    static const uint8_t  recoding_bit_length = 16;
    
    /* Recording time[second] */
    
    static const uint32_t recoding_time = 30;
    
    /* Bytes per second */
    
    static const int32_t  recoding_byte_per_second = (recoding_bitrate / 8);
    
    /* Total recording size */
    
    static const int32_t  recoding_size = recoding_byte_per_second * recoding_time;
    
    /* One frame size
     * Calculated with 1152 samples per frame.
     */
    
    static const uint32_t frame_size  = (1152 * (recoding_bitrate / 8)) / recoding_sampling_rate;
    
    /* Buffer size
     * Align in 512byte units based on frame size.
     */
    
    static const uint32_t buffer_size = (frame_size + 511) & ~511;
    static uint8_t        s_buffer[buffer_size];
    
    /**
     * @brief Audio attention callback
     *
     * When audio internal error occurc, this function will be called back.
     */
    
    static void attention_cb(const ErrorAttentionParam *atprm)
    {
      puts("Attention!");
      
      if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
        {
          ErrEnd = true;
       }
    }
    
    static void mediarecorder_attention_cb(const ErrorAttentionParam *atprm)
    {
      puts("Attention!");
      
      if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
        {
          ErrEnd = true;
       }
    }
    
    /**
     * @brief Mixer done callback procedure
     *
     * @param [in] requester_dtq    MsgQueId type
     * @param [in] reply_of         MsgType type
     * @param [in,out] done_param   AsOutputMixDoneParam type pointer
     */
    static void outputmixer_done_callback(MsgQueId requester_dtq,
                                          MsgType reply_of,
                                          AsOutputMixDoneParam *done_param)
    {
      return;
    }
    
    /**
     * @brief Mixer data send callback procedure
     *
     * @param [in] identifier   Device identifier
     * @param [in] is_end       For normal request give false, for stop request give true
     */
    static void outmixer_send_callback(int32_t identifier, bool is_end)
    {
      AsRequestNextParam next;
    
      next.type = (!is_end) ? AsNextNormalRequest : AsNextStopResRequest;
    
      AS_RequestNextPlayerProcess(AS_PLAYER_ID_0, &next);
    
      return;
    }
    
    /**
     * @brief Player done callback procedure
     *
     * @param [in] event        AsPlayerEvent type indicator
     * @param [in] result       Result
     * @param [in] sub_result   Sub result
     *
     * @return true on success, false otherwise
     */
    static bool mediaplayer_done_callback(AsPlayerEvent event, uint32_t result, uint32_t sub_result)
    {
      printf("mp cb %x %x %x\n", event, result, sub_result);
    
      return true;
    }
    
    /**
     * @brief Player decode callback procedure
     *
     * @param [in] pcm_param    AsPcmDataParam type
     */
    void mediaplayer_decode_callback(AsPcmDataParam pcm_param)
    {  
      theMixer->sendData(OutputMixer0,
                         outmixer_send_callback,
                         pcm_param);
    }
    
    /**
     * @brief Recorder done callback procedure
     *
     * @param [in] event        AsRecorderEvent type indicator
     * @param [in] result       Result
     * @param [in] sub_result   Sub result
     *
     * @return true on success, false otherwise
     */
    
    static bool mediarecorder_done_callback(AsRecorderEvent event, uint32_t result, uint32_t sub_result)
    {
      return true;
    }
    
    /**
     * @brief Setup Player and Mixer
     *
     * Set output device to Speakers/Headphones <br>
     * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate <br>
     * System directory "/mnt/sd0/BIN" will be searched for MP3 decoder (MP3DEC file)
     * Open "Sound.mp3" file <br>
     * Set volume to -16.0 dB
     */
    void setup()
    {
      /* Initialize SD */
      while (!theSD.begin())
        {
          /* wait until SD card is mounted. */
          Serial.println("Insert SD card.");
        }
    
      /* Initialize memory pools and message libs */
      
      initMemoryPools();
      createStaticPools(MEM_LAYOUT_RECORDINGPLAYER);
      
      /* start audio system */
      
      thePlayer = MediaPlayer::getInstance();
      theMixer  = OutputMixer::getInstance();
      theRecorder = MediaRecorder::getInstance();
    
      thePlayer->begin();
      theMixer->begin();
      theRecorder->begin(mediarecorder_attention_cb);
      
      puts("initialization Audio Library");
    
      /* Create Objects */
    
      thePlayer->create(MediaPlayer::Player0, attention_cb);
    
      theMixer->create(attention_cb);
    
      /* Set rendering clock */
    
      theMixer->setRenderingClkMode(OUTPUTMIXER_RNDCLK_HIRESO);
    
      /* Activate Player Object */
    
      thePlayer->activate(MediaPlayer::Player0, mediaplayer_done_callback, 1024*2*20);
    
      /* Activate Mixer Object.
       * Set output device to speaker with 2nd argument.
       * If you want to change the output device to I2S,
       * specify "I2SOutputDevice" as an argument.
       */
    
      theMixer->activate(OutputMixer0, HPOutputDevice, outputmixer_done_callback);
      theRecorder->activate(AS_SETRECDR_STS_INPUTDEVICE_MIC, mediarecorder_done_callback, (768*2*8)*30);
    
      usleep(100 * 1000);
    
      /*
       * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate
       * Search for MP3 codec in "/mnt/sd0/BIN" directory
       */
      thePlayer->init(MediaPlayer::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_96000, AS_CHANNEL_MONO);
    
      /*
       * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate
       * Search for MP3 codec in "/mnt/sd0/BIN" directory
       */
      theRecorder->init(AS_CODECTYPE_WAV,
                        recoding_cannel_number,
                        recoding_sampling_rate,
                        recoding_bit_length,
                        recoding_bitrate,
                        "/mnt/sd0/BIN");
    
      /* Initialize SD */
      while (!theSD.begin())
        {
          /* wait until SD card is mounted. */
          Serial.println("Insert SD card.");
        }
    
      playFile = theSD.open("AUDIO/Sound.wav");
      recFile  = theSD.open(RECORD_FILE_NAME, FILE_WRITE);
    
      /* Verify file open */
      if (!playFile)
        {
          printf("File open error\n");
          exit(1);
        }
      printf("Open! %d\n", recFile);
    
      /* Verify file open */
      if (!recFile)
        {
          printf("File open error\n");
          exit(1);
        }
      printf("Open! %d\n", recFile);
    
      /* Send first frames to be decoded */
      err_t err = thePlayer->writeFrames(MediaPlayer::Player0, playFile);
    
      if (err != MEDIAPLAYER_ECODE_OK)
        {
          printf("File Read Error! =%d\n",err);
          playFile.close();
          exit(1);
        }
    
      puts("Play!");
    
      /* Main volume set to -16.0 dB, Main player and sub player set to 0 dB */
      theMixer->setVolume(-160, 0, 0);
    
      // Start Player
      thePlayer->start(MediaPlayer::Player0, mediaplayer_decode_callback);
    
       /* Set Gain */
      theRecorder->setMicGain(ANALOG_MIC_GAIN);
    
      /* Start Recorder */
      theRecorder->start();
    }
    
    /**
     * @brief Execute one frame
     */
    err_t execute_aframe(uint32_t* size)
    {
      err_t err = theRecorder->readFrames(s_buffer, buffer_size, size);
    
      if(((err == MEDIARECORDER_ECODE_OK) || (err == MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA)) && (*size > 0))
        {
        }else{
          return err;
        }
      int ret = recFile.write((uint8_t*)&s_buffer, *size);
      if (ret < 0)
        {
          puts("File write error.");
          err = MEDIARECORDER_ECODE_FILEACCESS_ERROR;
        }
    
      return err;
    }
    
    /**
     * @brief Execute frames for FIFO empty
     */
    void execute_frames()
    {
      uint32_t read_size = 0;
      do
        {
          err_t err = execute_aframe(&read_size);
          if ((err != MEDIARECORDER_ECODE_OK)
           && (err != MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA))
            {
              break;
            }
        }
      while (read_size > 0);
    }
    
    /**
     * @brief Play audio frames until file ends
     */
    void loop()
    {
        static int32_t total_size = 0;
        uint32_t read_size = 0;
        err_t err;
    
    #if 1
    /* Execute audio data */
      err = execute_aframe(&read_size);
      if (err != MEDIARECORDER_ECODE_OK && err != MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA)
        {
          puts("Recording Error!");
          goto stop_player;
        }
      else if (read_size>0)
        {
          total_size += read_size;
        }
    
      /* Stop Recording */
      if (total_size > recoding_size)
        {
          goto stop_player;
        }
    #endif
    
    #if 1
      /* Send new frames to decode in a loop until file ends */
      err = thePlayer->writeFrames(MediaPlayer::Player0, playFile);
    
      /*  Tell when player file ends */
      if (err == MEDIAPLAYER_ECODE_FILEEND)
        {
          printf("Main player File End!\n");
        }
    
      /* Show error code from player and stop */
      if (err)
        {
          printf("Main player error code: %d\n", err);
          goto stop_player;
        }
        
      if (ErrEnd)
        {
          printf("Error End\n");
          goto stop_player;
        }
    #endif
    
      /* Don't go further and continue play */
      return;
    
    stop_player:    
      theRecorder->stop();
      thePlayer->stop(MediaPlayer::Player0);
      execute_frames();    
      /* Get ramaining data(flushing) */
      sleep(1); /* For data pipline stop */
      theRecorder->writeWavHeader(recFile);
      puts("Update Header!");
      playFile.close();
      recFile.close();
    
      thePlayer->deactivate(MediaPlayer::Player0);
      theRecorder->deactivate();
      thePlayer->end();
      theRecorder->end();
      puts("End Recording");
      exit(1);
    
    }
    
[/code]




興味があったので、実際に記録と再生を同時に動かすことをやってみました。  
基本的にできると思います。自分はできました。

サンプルにある  
player_objIf.ino  
と  
recorder_wav_objif.ino  
をマージすればよいです。

ただし、  
player_objIf.ino  
は、MP3の再生なので、96kHzを再生するのであれば、WAVしかなく、その変更が必要です。

[code]

    thePlayer->init(MediaPlayer::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_96000, AS_CHANNEL_MONO);
    
[/code]

また、記録もノーマルレゾリューションなので、

[code]

    static const uint32_t recoding_sampling_rate = 192000;
    static const uint8_t  recoding_cannel_number = 1;
    static const uint8_t  recoding_bit_length = 16;
    
[/code]

にしました。

ちなみに、記録は、16k,48k,192kしかないので、192kになりますね。

で、ハイレゾの記録再生同時になると、SDカードのアクセス速度がネックになるので、読み書きのバッファが足りなくなるので、変更しています。

[code]

     thePlayer->activate(MediaPlayer::Player0, mediaplayer_done_callback, 1024*2*20);
      theRecorder->activate(AS_SETRECDR_STS_INPUTDEVICE_MIC, mediarecorder_done_callback, (768*2*8)*30);
    
[/code]

サイズは合わせて調整すると良いと思います。

で、このサイズだと、メモリが足りなくなるので、  
タブにある  
tool/  
Memory:768KB(default)  
を  
Memory:896KB  
に替えました。

もう一点、終端処理のケアが必要になります。  
おそらく、記録と再生を別なタスクにすればよいのかもしれないですが、  
双方の停止でアプリのループが止まるため、どちらかが止まると両方止まります。

なので、終端処理を以下にしました。

[code]

    stop_player:    
      theRecorder->stop();
      thePlayer->stop(MediaPlayer::Player0);
      execute_frames();    
      /* Get ramaining data(flushing) */
      sleep(1); /* For data pipline stop */
      theRecorder->writeWavHeader(recFile);
      puts("Update Header!");
      playFile.close();
      recFile.close();
    
      thePlayer->deactivate(MediaPlayer::Player0);
      theRecorder->deactivate();
      thePlayer->end();
      theRecorder->end();
      puts("End Recording");
      exit(1);
    
[/code]

特に記録側のstopは、ループ側にstopがあるので、こちらに移動してきました。

これで、動かしたところ、動作できています。

ご参考になれば。

[code]

    #include &lt;SDHCI.h>
    #include &lt;MediaRecorder.h>
    #include &lt;MediaPlayer.h>
    #include &lt;OutputMixer.h>
    #include &lt;MemoryUtil.h>
    
    #define RECORD_FILE_NAME "Recorde.wav"
    #define ANALOG_MIC_GAIN  0 /* +0dB */
    SDClass theSD;
    
    MediaRecorder *theRecorder;
    MediaPlayer *thePlayer;
    OutputMixer *theMixer;
    
    File playFile;
    File recFile;
    
    bool ErrEnd = false;
    
    
    /* Recording bit rate
     * Set in bps.
     */
    
    //static const uint32_t recoding_bitrate = 48000*8*2;
    static const uint32_t recoding_bitrate = 192000*8*2;
    
    /* Sampling rate
     * Set 16000 or 48000
     */
    
    static const uint32_t recoding_sampling_rate = 192000;
    
    /* Number of input channels
     * Set either 1, 2, or 4.
     */
    
    static const uint8_t  recoding_cannel_number = 1;
    
    /* Audio bit depth
     * Set 16 or 24
     */
    
    static const uint8_t  recoding_bit_length = 16;
    
    /* Recording time[second] */
    
    static const uint32_t recoding_time = 30;
    
    /* Bytes per second */
    
    static const int32_t  recoding_byte_per_second = (recoding_bitrate / 8);
    
    /* Total recording size */
    
    static const int32_t  recoding_size = recoding_byte_per_second * recoding_time;
    
    /* One frame size
     * Calculated with 1152 samples per frame.
     */
    
    static const uint32_t frame_size  = (1152 * (recoding_bitrate / 8)) / recoding_sampling_rate;
    
    /* Buffer size
     * Align in 512byte units based on frame size.
     */
    
    static const uint32_t buffer_size = (frame_size + 511) & ~511;
    static uint8_t        s_buffer[buffer_size];
    
    /**
     * @brief Audio attention callback
     *
     * When audio internal error occurc, this function will be called back.
     */
    
    static void attention_cb(const ErrorAttentionParam *atprm)
    {
      puts("Attention!");
      
      if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
        {
          ErrEnd = true;
       }
    }
    
    static void mediarecorder_attention_cb(const ErrorAttentionParam *atprm)
    {
      puts("Attention!");
      
      if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
        {
          ErrEnd = true;
       }
    }
    
    /**
     * @brief Mixer done callback procedure
     *
     * @param [in] requester_dtq    MsgQueId type
     * @param [in] reply_of         MsgType type
     * @param [in,out] done_param   AsOutputMixDoneParam type pointer
     */
    static void outputmixer_done_callback(MsgQueId requester_dtq,
                                          MsgType reply_of,
                                          AsOutputMixDoneParam *done_param)
    {
      return;
    }
    
    /**
     * @brief Mixer data send callback procedure
     *
     * @param [in] identifier   Device identifier
     * @param [in] is_end       For normal request give false, for stop request give true
     */
    static void outmixer_send_callback(int32_t identifier, bool is_end)
    {
      AsRequestNextParam next;
    
      next.type = (!is_end) ? AsNextNormalRequest : AsNextStopResRequest;
    
      AS_RequestNextPlayerProcess(AS_PLAYER_ID_0, &next);
    
      return;
    }
    
    /**
     * @brief Player done callback procedure
     *
     * @param [in] event        AsPlayerEvent type indicator
     * @param [in] result       Result
     * @param [in] sub_result   Sub result
     *
     * @return true on success, false otherwise
     */
    static bool mediaplayer_done_callback(AsPlayerEvent event, uint32_t result, uint32_t sub_result)
    {
      printf("mp cb %x %x %x\n", event, result, sub_result);
    
      return true;
    }
    
    /**
     * @brief Player decode callback procedure
     *
     * @param [in] pcm_param    AsPcmDataParam type
     */
    void mediaplayer_decode_callback(AsPcmDataParam pcm_param)
    {  
      theMixer->sendData(OutputMixer0,
                         outmixer_send_callback,
                         pcm_param);
    }
    
    /**
     * @brief Recorder done callback procedure
     *
     * @param [in] event        AsRecorderEvent type indicator
     * @param [in] result       Result
     * @param [in] sub_result   Sub result
     *
     * @return true on success, false otherwise
     */
    
    static bool mediarecorder_done_callback(AsRecorderEvent event, uint32_t result, uint32_t sub_result)
    {
      return true;
    }
    
    /**
     * @brief Setup Player and Mixer
     *
     * Set output device to Speakers/Headphones <br>
     * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate <br>
     * System directory "/mnt/sd0/BIN" will be searched for MP3 decoder (MP3DEC file)
     * Open "Sound.mp3" file <br>
     * Set volume to -16.0 dB
     */
    void setup()
    {
      /* Initialize SD */
      while (!theSD.begin())
        {
          /* wait until SD card is mounted. */
          Serial.println("Insert SD card.");
        }
    
      /* Initialize memory pools and message libs */
      
      initMemoryPools();
      createStaticPools(MEM_LAYOUT_RECORDINGPLAYER);
      
      /* start audio system */
      
      thePlayer = MediaPlayer::getInstance();
      theMixer  = OutputMixer::getInstance();
      theRecorder = MediaRecorder::getInstance();
    
      thePlayer->begin();
      theMixer->begin();
      theRecorder->begin(mediarecorder_attention_cb);
      
      puts("initialization Audio Library");
    
      /* Create Objects */
    
      thePlayer->create(MediaPlayer::Player0, attention_cb);
    
      theMixer->create(attention_cb);
    
      /* Set rendering clock */
    
      theMixer->setRenderingClkMode(OUTPUTMIXER_RNDCLK_HIRESO);
    
      /* Activate Player Object */
    
      thePlayer->activate(MediaPlayer::Player0, mediaplayer_done_callback, 1024*2*20);
    
      /* Activate Mixer Object.
       * Set output device to speaker with 2nd argument.
       * If you want to change the output device to I2S,
       * specify "I2SOutputDevice" as an argument.
       */
    
      theMixer->activate(OutputMixer0, HPOutputDevice, outputmixer_done_callback);
      theRecorder->activate(AS_SETRECDR_STS_INPUTDEVICE_MIC, mediarecorder_done_callback, (768*2*8)*30);
    
      usleep(100 * 1000);
    
      /*
       * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate
       * Search for MP3 codec in "/mnt/sd0/BIN" directory
       */
      thePlayer->init(MediaPlayer::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_96000, AS_CHANNEL_MONO);
    
      /*
       * Initialize main player to decode stereo mp3 stream with 48 kb/s sample rate
       * Search for MP3 codec in "/mnt/sd0/BIN" directory
       */
      theRecorder->init(AS_CODECTYPE_WAV,
                        recoding_cannel_number,
                        recoding_sampling_rate,
                        recoding_bit_length,
                        recoding_bitrate,
                        "/mnt/sd0/BIN");
    
      /* Initialize SD */
      while (!theSD.begin())
        {
          /* wait until SD card is mounted. */
          Serial.println("Insert SD card.");
        }
    
      playFile = theSD.open("AUDIO/Sound.wav");
      recFile  = theSD.open(RECORD_FILE_NAME, FILE_WRITE);
    
      /* Verify file open */
      if (!playFile)
        {
          printf("File open error\n");
          exit(1);
        }
      printf("Open! %d\n", recFile);
    
      /* Verify file open */
      if (!recFile)
        {
          printf("File open error\n");
          exit(1);
        }
      printf("Open! %d\n", recFile);
    
      /* Send first frames to be decoded */
      err_t err = thePlayer->writeFrames(MediaPlayer::Player0, playFile);
    
      if (err != MEDIAPLAYER_ECODE_OK)
        {
          printf("File Read Error! =%d\n",err);
          playFile.close();
          exit(1);
        }
    
      puts("Play!");
    
      /* Main volume set to -16.0 dB, Main player and sub player set to 0 dB */
      theMixer->setVolume(-160, 0, 0);
    
      // Start Player
      thePlayer->start(MediaPlayer::Player0, mediaplayer_decode_callback);
    
       /* Set Gain */
      theRecorder->setMicGain(ANALOG_MIC_GAIN);
    
      /* Start Recorder */
      theRecorder->start();
    }
    
    /**
     * @brief Execute one frame
     */
    err_t execute_aframe(uint32_t* size)
    {
      err_t err = theRecorder->readFrames(s_buffer, buffer_size, size);
    
      if(((err == MEDIARECORDER_ECODE_OK) || (err == MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA)) && (*size > 0))
        {
        }else{
          return err;
        }
      int ret = recFile.write((uint8_t*)&s_buffer, *size);
      if (ret < 0)
        {
          puts("File write error.");
          err = MEDIARECORDER_ECODE_FILEACCESS_ERROR;
        }
    
      return err;
    }
    
    /**
     * @brief Execute frames for FIFO empty
     */
    void execute_frames()
    {
      uint32_t read_size = 0;
      do
        {
          err_t err = execute_aframe(&read_size);
          if ((err != MEDIARECORDER_ECODE_OK)
           && (err != MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA))
            {
              break;
            }
        }
      while (read_size > 0);
    }
    
    /**
     * @brief Play audio frames until file ends
     */
    void loop()
    {
        static int32_t total_size = 0;
        uint32_t read_size = 0;
        err_t err;
    
    #if 1
    /* Execute audio data */
      err = execute_aframe(&read_size);
      if (err != MEDIARECORDER_ECODE_OK && err != MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA)
        {
          puts("Recording Error!");
          goto stop_player;
        }
      else if (read_size>0)
        {
          total_size += read_size;
        }
    
      /* Stop Recording */
      if (total_size > recoding_size)
        {
          goto stop_player;
        }
    #endif
    
    #if 1
      /* Send new frames to decode in a loop until file ends */
      err = thePlayer->writeFrames(MediaPlayer::Player0, playFile);
    
      /*  Tell when player file ends */
      if (err == MEDIAPLAYER_ECODE_FILEEND)
        {
          printf("Main player File End!\n");
        }
    
      /* Show error code from player and stop */
      if (err)
        {
          printf("Main player error code: %d\n", err);
          goto stop_player;
        }
        
      if (ErrEnd)
        {
          printf("Error End\n");
          goto stop_player;
        }
    #endif
    
      /* Don't go further and continue play */
      return;
    
    stop_player:    
      theRecorder->stop();
      thePlayer->stop(MediaPlayer::Player0);
      execute_frames();    
      /* Get ramaining data(flushing) */
      sleep(1); /* For data pipline stop */
      theRecorder->writeWavHeader(recFile);
      puts("Update Header!");
      playFile.close();
      recFile.close();
    
      thePlayer->deactivate(MediaPlayer::Player0);
      theRecorder->deactivate();
      thePlayer->end();
      theRecorder->end();
      puts("End Recording");
      exit(1);
    
    }
    
[/code]

