📄 audio.c
字号:
/* * * Copyright (c) 2001-2007 Sigma Designs, Inc. * All Rights Reserved. Proprietary and Confidential. * *//** @file 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 1#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif#include "common.h"#include "audio.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)struct cap_audio_instance { // Access struct RUA *pRUA; struct DCC *pDCC; struct DCCAudioSource *pAudioSource; struct rmcapture_options *cap_opt; // State struct cap_audio_setup Setup; 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 cap_audio_open( struct RUA *pRUA, struct DCC *pDCC, struct rmcapture_options *cap_opt, struct cap_audio_instance **ppAudio){ struct cap_audio_instance *pAudio; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (ppAudio == NULL) return RM_FATALINVALIDPOINTER; *ppAudio = NULL; if (pRUA == NULL) return RM_FATALINVALIDPOINTER; if (pDCC == NULL) return RM_FATALINVALIDPOINTER; if (cap_opt == NULL) return RM_FATALINVALIDPOINTER; // Allocate and clear local instance pAudio = (struct cap_audio_instance *)RMMalloc(sizeof(struct cap_audio_instance)); if (pAudio == NULL) { RMDBGLOG((ENABLE, "FATAL! Not enough memory for struct cap_audio_instance!\n")); return RM_FATALOUTOFMEMORY; } RMMemset(pAudio, 0, sizeof(struct cap_audio_instance)); *ppAudio = pAudio; // Set default and non-zero startup values pAudio->cap_opt = cap_opt; pAudio->Setup.STCTimerNumber = cap_opt->STCTimerNumber; pAudio->Setup.AudioInAlign = cap_opt->AudioInAlign; pAudio->Setup.audio_free_run = cap_opt->audio_free_run; pAudio->Setup.AudioEngineID = cap_opt->AudioEngineID; pAudio->Setup.AudioDecoderID = cap_opt->AudioDecoderID; // TODO honor rest of cap_opt audio options pAudio->audio_state = audio_state_off; return RM_OK;}/* destroy the audio instance, close open chips */RMstatus cap_audio_close( struct cap_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 err = cap_audio_stop_capture(pAudio); RMFree(pAudio); return err;}/* provide setup info to the audio capture */RMstatus cap_audio_setup( struct cap_audio_instance *pAudio, struct cap_audio_setup *pSetup) // necessary info for the audio capture{ RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pAudio == NULL) return RM_FATALINVALIDPOINTER; if (pSetup == NULL) return RM_FATALINVALIDPOINTER; pAudio->Setup = *pSetup; // copy return RM_OK;}/* calculate SI_CONF matching the current setup */static RMstatus get_SI_CONF( struct cap_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 { RMDBGLOG((ENABLE, "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->cap_opt->Codec == AudioDecoder_Codec_PCM) { switch (pAudio->cap_opt->SubCodec) { case 0: BitsPerSample = pAudio->cap_opt->PcmCdaParams.BitsPerSample; break; case 1: BitsPerSample = pAudio->cap_opt->LpcmVobParams.BitsPerSample; break; case 2: BitsPerSample = pAudio->cap_opt->LpcmAobParams.BitsPerSampleGroup1; break; case 3: BitsPerSample = pAudio->cap_opt->PcmCdaParams.BitsPerSample; break; default: 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 cap_audio_get_spdif_channel_status( struct cap_audio_instance *pAudio, struct AudioEngine_InputSPDIFStatus_type *pStat){ RMstatus err; struct AudioEngine_InputSPDIFStatus_type stat; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUAGetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioEngine, pAudio->Setup.AudioEngineID), RMAudioEnginePropertyID_InputSPDIFStatus, &stat, sizeof(stat)); if (RMSUCCEEDED(err)) { if (pStat) { *pStat = stat; } else { RMDBGLOG((ENABLE, "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 cap_audio_stop_capture( struct cap_audio_instance *pAudio){ enum AudioCapture_Capture_type cmd = AudioCapture_Capture_Off; RMuint32 dummy = 0; RMstatus err; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Capture, &cmd, sizeof(cmd), 0); if (RMFAILED(err)) RMDBGLOG((ENABLE, "Error sending capture OFF command. %s\n", RMstatusToString(err))); err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Close, &dummy, sizeof(dummy), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error closing capture module! %s\n", RMstatusToString(err))); } return err;}/* Initializes and starts capture */RMstatus cap_audio_start_capture( struct cap_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->pRUA, pAudio->Setup.VideoCaptureModuleID, RMGenericPropertyID_CaptureDelay, &CaptureDelay, sizeof(CaptureDelay)); if (RMFAILED(err) || (CaptureDelay == 0)) { CaptureDelay = 6004; // NTSC // CaptureDelay = 7200; // PAL } else RMDBGLOG((ENABLE, "Audio Delay from Video Passthrough: %ld PTS, %ld mSec\n", CaptureDelay, CaptureDelay / 90)); } RMDBGLOG((ENABLE, "Audio Delay: %ld PTS, %ld ms\n", CaptureDelay, CaptureDelay / 90)); RMMemset(&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)) { RMDBGLOG((ENABLE, "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; } //RMDBGLOG((LOCALDBG, "capture source = %lx spdif=%x SI_CONF = %lx\n", pAudio->Setup.CaptureSource, pAudio->audio_opt->Spdif, capture_open.SI_CONF)); err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Open, &capture_open, sizeof(capture_open), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error opening audio capture module! %s\n", RMstatusToString(err))); return err; } err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Source, &(src), sizeof(src), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error setting audio capture source! %s\n", RMstatusToString(err))); return err; } err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_SpdifBitstreamNumber, &(pAudio->Setup.CaptureBitstream), sizeof(pAudio->Setup.CaptureBitstream), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error setting audio capture bitstream number! %s\n", RMstatusToString(err))); return err; } err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_SpdifDataType, &(pAudio->Setup.CaptureType), sizeof(pAudio->Setup.CaptureType), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error setting audio capture type! %s\n", RMstatusToString(err))); return err; } cmd = AudioCapture_Capture_On; err = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioCapture, pAudio->Setup.AudioCaptureID), RMAudioCapturePropertyID_Capture, &cmd, sizeof(cmd), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error sending capture ON command. %s\n", RMstatusToString(err))); } if (pAudio->Setup.audio_free_run) { RMbool AVSyncEnable = FALSE; // 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 = RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioDecoder, pAudio->Setup.AudioDecoderID), RMAudioDecoderPropertyID_SyncSTCEnable, &AVSyncEnable, sizeof(AVSyncEnable), 0); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "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 cap_audio_print_bitstream_fifo_info(struct cap_audio_instance *pAudio, RMuint32 threshold){ RMstatus err; struct DataFIFOInfo audio_info; RMDBGLOG((FUNCNAME, "%s\n",__func__)); err = RUAGetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioDecoder, pAudio->Setup.AudioDecoderID), RMGenericPropertyID_DataFIFOInfo, &audio_info, sizeof(audio_info)); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Cannot retreive A.FIFO!\n")); } else { if (audio_info.Readable * 100 / audio_info.Size >= threshold) RMDBGLOG((ENABLE, "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) { RMDBGLOG((ENABLE, "FATAL ERROR: audio playback has crashed!\n")); } }}// Set up the audio clock on the audio engine, settings from pAudio->Setupstatic RMstatus cap_audio_set_sample_clock( struct cap_audio_instance *pAudio){ struct AudioEngine_SampleFrequencyFromSource_type sf; sf.GeneratorNumber = 3; sf.SampleFrequency = pAudio->Setup.SampleRate; if (pAudio->Setup.ExternalClk) { // external clock source sf.Source = 4; // RClkIn0 if (pAudio->Setup.ExternalClkFreq) { sf.SourceFrequency = pAudio->Setup.ExternalClkFreq; } else { sf.SourceFrequency = sf.SampleFrequency * ((pAudio->cap_opt->mclk == MClkFactor_256Xfs) ? 256 : 128); } sf.IntermediateFrequency = sf.SourceFrequency * 8; } else { // internal clock source sf.Source = 1; // XTalIn sf.SourceFrequency = 27000000; sf.IntermediateFrequency = 148500000; // dummy value } return RUASetProperty(pAudio->pRUA, EMHWLIB_MODULE(AudioEngine, pAudio->Setup.AudioEngineID),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -