📄 play_capture_audio.c
字号:
/* * * Copyright (c) 2001-2007 Sigma Designs, Inc. * All Rights Reserved. Proprietary and Confidential. * *//** @file play_capture_audio.c @brief functions to set up the emhwlib audio passthrough (no external chip interaction) @author Christian Wolff Sean.Sekwon.Choi*/// to enable or disable the debug messages of this source file, put 1 or 0 below#if 0#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif#include "sample_os.h"#define ALLOW_OS_CODE 1#include "../rua/include/rua.h"#include "../rua/include/rua_property.h"#include "../dcc/include/dcc.h"#include "../rmcore/include/rmstatustostring.h"#include "../rmlibcw/include/rmlibcw.h"#include "common.h"// TODO:#define AUDIO_GUARD_TIME 2 // wait 2 seconds after audio has been set up until audio passtrough can be restarted#define AUDIO_FIFO_SIZE (2048*1024)#define XFER_FIFO_COUNT (32)//#include "play_capture_main.h"#include "play_capture_audio.h"struct capsam_audio_instance { // Access struct dcc_context *dcc_info; struct capsam_audio_setup Setup; // State struct audio_cmdline *audio_opt; // options for the audio playback (used because code in apply_audio_engine_options/apply_audio_decoder_options should not be duplicated) enum audio_state audio_state; RMuint64 audio_guard_time; RMbool audio_pll_locked; // stability of audio clock RMbool auto_detect_codec; // TRUE: codec of the incoming audio needs to be determined RMuint32 CurrChStat; RMuint16 CurrPc;};/* create the audio instace */RMstatus capsam_audio_open( struct dcc_context *dcc_info, struct capsam_audio_instance **ppAudio){ struct capsam_audio_instance *pAudio; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (ppAudio == NULL) return RM_FATALINVALIDPOINTER; *ppAudio = NULL; if (dcc_info == NULL) return RM_FATALINVALIDPOINTER; // Allocate and clear local instance pAudio = (struct capsam_audio_instance *)RMMalloc(sizeof(struct capsam_audio_instance)); if (pAudio == NULL) { fprintf(stderr, "FATAL! Not enough memory for struct capsam_audio_instance!\n"); return RM_FATALOUTOFMEMORY; } RMMemset(pAudio, 0, sizeof(struct capsam_audio_instance)); *ppAudio = pAudio; // Set default and non-zero startup values pAudio->dcc_info = dcc_info; pAudio->Setup.STCTimerNumber = 1; pAudio->Setup.AudioInAlign = 1; pAudio->Setup.audio_free_run = TRUE; pAudio->audio_state = audio_state_off; return RM_OK;}/* destroy the audio instance, close open chips */RMstatus capsam_audio_close( struct capsam_audio_instance *pAudio){ RMstatus err = RM_OK; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pAudio == NULL) return RM_OK; // already closed // Free all available ressources if (pAudio->audio_opt != NULL) { err = capsam_audio_stop_passthrough(pAudio); } else { err = capsam_audio_stop_capture(pAudio); } RMFree(pAudio); return err;}/* provide setup info to the audio capture */RMstatus capsam_audio_setup( struct capsam_audio_instance *pAudio, struct capsam_audio_setup *pSetup, // necessary info for the audio capture struct audio_cmdline *audio_opt) // reference to the app's audio_opt, to set up the audio playback{ RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pAudio == NULL) return RM_FATALINVALIDPOINTER; if (pSetup == NULL) return RM_FATALINVALIDPOINTER; pAudio->Setup = *pSetup; // copy pAudio->audio_opt = audio_opt; // reference, can be NULL return RM_OK;}/* calculate SI_CONF matching the current setup */static RMstatus get_SI_CONF( struct capsam_audio_instance *pAudio, RMuint32 *pSI_CONF){ RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Capture from I2S, 32 bit frames if (pAudio->Setup.CaptureSource == 0) { // *pSI_CONF = 0x009; // 16 bit I2S frames *pSI_CONF = 0x007 | // SerialIn Configuration, 32 bit frames ((pAudio->Setup.AudioInAlign & 0x1F) << 3) | (pAudio->Setup.AudioInSClkNegEdge ? 0x000 : 0x100) | (pAudio->Setup.AudioInLSBfirst ? 0x200 : 0x000) | (pAudio->Setup.AudioInFrameInvert ? 0x400 : 0x000); } else // Capture from SPDIF, always 16 bit frames#ifdef RMFEATURE_HAS_SPDIF_INPUT // in 8622/24 Tango 1.5 and 8634 Tango 2, spdif is dedicated line. use it with source=1 if (pAudio->Setup.CaptureSource == 1) { *pSI_CONF = 0x800 | // capture from SI_SPDIF (pAudio->Setup.AudioInSClkNegEdge ? 0x000 : 0x100); } else #endif if (pAudio->Setup.CaptureSource <= 2) { *pSI_CONF = 0x000 | // capture from SI_DATA (pAudio->Setup.AudioInSClkNegEdge ? 0x000 : 0x100); } else { fprintf(stderr, "Error, unsupported audio source: %lu\n", pAudio->Setup.CaptureSource); return RM_ERROR; } *pSI_CONF |= 0x80000000; // extended info in unused bits of SI_CONF if (pAudio->Setup.CaptureSource == 0) { // only I2S supports more than 16 bits per sample RMuint32 BitsPerSample = 16; if (pAudio->audio_opt != NULL) { if (pAudio->audio_opt->Codec == AudioDecoder_Codec_PCM) { switch (pAudio->audio_opt->SubCodec) { default: BitsPerSample = pAudio->audio_opt->PcmCdaParams.BitsPerSample; break; case 1: BitsPerSample = pAudio->audio_opt->LpcmVobParams.BitsPerSample; break; case 2: BitsPerSample = pAudio->audio_opt->LpcmAobParams.BitsPerSampleGroup1; break; case 3: BitsPerSample = pAudio->audio_opt->PcmCdaParams.BitsPerSample; break; } } } else { BitsPerSample = pAudio->Setup.BitsPerSample; } if (BitsPerSample >= 24) { *pSI_CONF |= 0x40000000; // don't truncate 24 bit PCM samples to 16 bits } } return RM_OK;}/* retreive current SPDIF channel status and payload header info from em8xxx */RMstatus capsam_audio_get_spdif_channel_status( struct capsam_audio_instance *pAudio, struct AudioEngine_InputSPDIFStatus_type *pStat){ RMstatus err; struct AudioEngine_InputSPDIFStatus_type stat; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUAGetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioEngine, pAudio->Setup.AudioEngineID), RMAudioEnginePropertyID_InputSPDIFStatus, &stat, sizeof(stat)); if (RMSUCCEEDED(err)) { if (pStat) { *pStat = stat; } else { fprintf(stderr, "Audio Input channel status [18:0]: 0x%05lX Pc:%04X Pd:%04X Pe:%04X Pf:%04X\n", stat.ChannelStatus, stat.Pc, stat.Pd, stat.Pe, stat.Pf); } } return err;}/* Stops capture */RMstatus capsam_audio_stop_capture( struct capsam_audio_instance *pAudio){ enum AudioCapture_Capture_type cmd = AudioCapture_Capture_Off; RMuint32 dummy = 0; RMstatus err; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Capture, &cmd, sizeof(cmd), 0); if (RMFAILED(err)) fprintf(stderr, "Error sending capture OFF command. %s\n", RMstatusToString(err)); err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Close, &dummy, sizeof(dummy), 0); if (RMFAILED(err)) { fprintf(stderr, "Error closing capture module! %s\n", RMstatusToString(err)); } return err;}/* Initializes and starts capture */RMstatus capsam_audio_start_capture( struct capsam_audio_instance *pAudio){ struct AudioCapture_Open_type capture_open; enum AudioCapture_Capture_type cmd; enum AudioCapture_Source_type src; RMuint32 CaptureDelay; RMstatus err; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pAudio == NULL) return RM_FATALINVALIDPOINTER; //pAudio->Setup.CaptureDelay = 6004; // Retreive video delay and apply to audio, unless specified on command line if (pAudio->Setup.CaptureDelay) { CaptureDelay = pAudio->Setup.CaptureDelay; } else { // actual video delay is plus/minus one field duration of this value, depending on input-to-output vsync phase err = RUAGetProperty(pAudio->dcc_info->pRUA, pAudio->Setup.VideoCaptureModuleID, RMGenericPropertyID_CaptureDelay, &CaptureDelay, sizeof(CaptureDelay)); if (RMFAILED(err) || (CaptureDelay == 0)) { CaptureDelay = 6004; // NTSC // CaptureDelay = 7200; // PAL } else fprintf(stderr, "Audio Delay from Video Passthrough: %ld PTS, %ld mSec\n", CaptureDelay, CaptureDelay / 90); } fprintf(stderr, "Audio Delay: %ld PTS, %ld ms\n", CaptureDelay, CaptureDelay / 90); memset(&capture_open, 0, sizeof(struct AudioCapture_Open_type)); capture_open.CaptureMode = 1; // Pass-through capture_open.Delay = CaptureDelay / 2; // Delay is 45000 Hz based start PTS err = get_SI_CONF(pAudio, &(capture_open.SI_CONF)); if (RMFAILED(err)) { fprintf(stderr, "Error setting up audio input! %s\n", RMstatusToString(err)); return err; } if (pAudio->Setup.CaptureSource == 0) { src = AudioCapture_Source_I2S; } else { src = AudioCapture_Source_SPDIF; } //printf("capture source = %lx spdif=%x SI_CONF = %lx\n", pAudio->Setup.CaptureSource, pAudio->audio_opt->Spdif, capture_open.SI_CONF); err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Open, &capture_open, sizeof(capture_open), 0); if (RMFAILED(err)) { fprintf(stderr, "Error opening audio capture module! %s\n", RMstatusToString(err)); return err; } err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Source, &(src), sizeof(src), 0); if (RMFAILED(err)) { fprintf(stderr, "Error setting audio capture source! %s\n", RMstatusToString(err)); return err; } err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_SpdifBitstreamNumber, &(pAudio->Setup.CaptureBitstream), sizeof(pAudio->Setup.CaptureBitstream), 0); if (RMFAILED(err)) { fprintf(stderr, "Error setting audio capture bitstream number! %s\n", RMstatusToString(err)); return err; } err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_SpdifDataType, &(pAudio->Setup.CaptureType), sizeof(pAudio->Setup.CaptureType), 0); if (RMFAILED(err)) { fprintf(stderr, "Error setting audio capture type! %s\n", RMstatusToString(err)); return err; } cmd = AudioCapture_Capture_On; err = RUASetProperty(pAudio->dcc_info->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Capture, &cmd, sizeof(cmd), 0); if (RMFAILED(err)) { fprintf(stderr, "Error sending capture ON command. %s\n", RMstatusToString(err)); } if (pAudio->Setup.audio_free_run) { RMbool AVSyncEnable = FALSE; struct DCCAudioSourceHandle AudioHandle; // wait until audio decoder has started the delayed playback RMMicroSecondSleep(CaptureDelay * 200 / 9); // actual delay in uSec: CaptureDelay * 100 / 9 // Disable AV-Sync (for now, because STC is running on asynchronous clock, which breaks the passthrough after some time.) err = DCCMultipleAudioSourceGetSingleDecoderHandleForInstance(pAudio->dcc_info->pMultipleAudioSource, 0, &AudioHandle); if (RMFAILED(err)) { AudioHandle.moduleID = pAudio->dcc_info->audio_decoder; } err = RUASetProperty(pAudio->dcc_info->pRUA, AudioHandle.moduleID, RMAudioDecoderPropertyID_SyncSTCEnable, &AVSyncEnable, sizeof(AVSyncEnable), 0); if (RMFAILED(err)) { fprintf(stderr, "Error disabling AV-Sync! %s\n", RMstatusToString(err)); return err; } else { RMDBGLOG((ENABLE, "\n*********\n AUDIO sync is %s\n*********\n", AVSyncEnable ? "enabled" : "disabled")); } } return err;}void capsam_audio_print_bitstream_fifo_info(struct dcc_context *dcc_info, RMuint32 threshold){ RMstatus err; struct DataFIFOInfo audio_info; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUAGetProperty(dcc_info->pRUA, dcc_info->audio_decoder, RMGenericPropertyID_DataFIFOInfo, &audio_info, sizeof(audio_info)); if (RMFAILED(err)) { fprintf(stderr, "Cannot retreive A.FIFO!\n"); } else { if (audio_info.Readable * 100 / audio_info.Size >= threshold) fprintf(stderr, "A.FIFO: St.0x%08lX Sz.0x%08lX Wr.0x%08lX Rd.0x%08lX %3lu%% full, %lu readable\n", audio_info.StartAddress, audio_info.Size, audio_info.Writable, audio_info.Readable, audio_info.Readable * 100 / audio_info.Size, audio_info.Readable); if (audio_info.Readable > audio_info.Size) { fprintf(stderr, "FATAL ERROR: audio playback has crashed!\n"); } }}/* Stops capture, and playback of captured audio */RMstatus capsam_audio_stop_passthrough( struct capsam_audio_instance *pAudio){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -