📄 play_audio.c
字号:
} RMDBGLOG((ENABLE, "\n****************\nAUDIO_IN enabled\n***************\n")); DCCSTCSetTime(dcc_info.pStcSource, 0, 90000); DCCSTCPlay(dcc_info.pStcSource); // Send Play command to audio playback err = DCCPlayMultipleAudioSource(dcc_info.pMultipleAudioSource); if (RMFAILED(err)) { fprintf(stderr, "Cannot play audio decoder %d\n", err); goto cleanup; } if (1) { RMbool AVSyncEnable = FALSE; struct DCCAudioSourceHandle audioHandle1; // wait until audio decoder has started the delayed playback RMMicroSecondSleep(context.audio_opt[0].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(dcc_info.pMultipleAudioSource, 0, &audioHandle1); if (RMFAILED(err)) { audioHandle1.moduleID = dcc_info.audio_decoder; } err = RUASetProperty(dcc_info.pRUA, audioHandle1.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")); } } // Start audio capture err = StartAudioCapture(&dcc_info, audio_capture, &(context.audio_opt[0]), &context); if (RMFAILED(err)) { fprintf(stderr, "Error starting audio capture! %s\n", RMstatusToString(err)); goto cleanup; } context.play_opt->waitexit = TRUE; // Force wait on exit if(!context.fp_capture){ goto cleanup; }else{ goto capture_loop; } } else { file = open_stream(context.play_opt->filename, RM_FILE_OPEN_READ, 0); if (file == NULL) { fprintf(stderr, "Cannot open file %s\n", context.play_opt->filename); goto cleanup; } context.f_bitstream = file; RMSizeOfOpenFile(file, &context.fileSize); if (context.audio_opt[0].skip_first_n_bytes) { context.skipFirstNBytes = context.audio_opt[0].skip_first_n_bytes; RMDBGLOG((ENABLE, ">> skip first %lu bytes, adjust file size from %llu to %llu\n", context.skipFirstNBytes, context.fileSize, context.fileSize - context.skipFirstNBytes)); context.fileSize -= context.skipFirstNBytes; } if (context.audio_opt[0].send_n_bytes) { context.sendNBytes = context.audio_opt[0].send_n_bytes; RMDBGLOG((ENABLE, ">> send up to %lu bytes only, adjust file size from %llu to %lu\n", context.sendNBytes, context.fileSize, context.sendNBytes)); // pcm should start at the correct sample position if (context.audio_opt[0].Codec == AudioDecoder_Codec_PCM) { context.sendNBytes -= context.sendNBytes % context.PCMblockSize; RMDBGLOG((ENABLE, "aligned to %lu\n", context.sendNBytes)); } context.fileSize = context.sendNBytes; } RMDBGLOG((ENABLE, "file: %s, size %llu, duration %llu\n", context.play_opt->filename, context.fileSize, context.play_opt->duration / 1000)); context.Duration = context.play_opt->duration / 1000; context.audio_vop_tir = 90000; dcc_info.RM_PSM_commands = RM_PSM_ENABLE_PLAY; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_STOP; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_PAUSE; if (context.Duration) fprintf(stderr, "duration %llu secs\n", context.Duration); if ((context.play_opt->duration > 1000) && (context.fileSize > 0)) { RMDBGLOG((ENABLE, "seek and ffwd trick mode enabled\n")); dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_SPEED; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_FASTER; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_SLOWER; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_SEEK; dcc_info.RM_PSM_commands |= RM_PSM_ENABLE_REWIND; dcc_info.seek_supported = TRUE; } } context.dcc_info = &dcc_info; context.PSMcontext = &PSMContext; PSMContext.validPSMContexts = 1; PSMContext.currentActivePSMContext = 1; PSMContext.keyflags = KEYFLAGS;#if DUMP_DATA RMDBGLOG((ENABLE, "\t\t\t***** OPEN SAVE DATA FILE ****\n")); context.saveFile = fopen("ec3_transcoded_ac3.with_pushLibrary.dump", "wb");#endif if (context.audio_opt[0].transcode_ec3_to_ac3) { struct RMEC3subParams_struct subParams; RMuint32 ch; RMDBGLOG((ENABLE, "init ec3 transcoding lib\n")); context.transcodeEC3toAC3 = TRUE; subParams.compMode = RMEC3_COMP_LINE; subParams.outLFE = RMEC3_LFEOUT_ON; subParams.outChanConfig = RMEC3_MODE32; subParams.pcmScale = RMEC3_DEFAULTSCALEFACTOR; subParams.stereoMode = RMEC3_STEREOMODE_AUTO; subParams.dualMode = RMEC3_DUAL_STEREO; subParams.dynScaleHigh = RMEC3_DEFAULTSCALEFACTOR; subParams.dynScaleLow = RMEC3_DEFAULTSCALEFACTOR; for (ch = 0; ch < RMEC3_MAXPCMCHANS; ch++) subParams.chanRouting[ch] = ch; subParams.subStream = RMEC3_DEFAULTSUBSTREAMID;#if defined(KCAPABLE) subParams.karaokeMode = RMEC3_BOTH_VOCALS;#endif /* defined(KCAPABLE) */ context.ec3TranscoderHandle = RMEC3OpenTranscoder(subParams); if (!context.ec3TranscoderHandle) { fprintf(stderr, "couldnt init ec3 transcoding library\n"); goto cleanup; } context.readBuffer = (RMuint8*)RMMalloc((1<<context.play_opt->dmapool_log2size) * sizeof(RMuint8)); if (!context.readBuffer) { fprintf(stderr, "couldnt init read buffer required by ec3 lib\n"); goto cleanup; } RMDBGLOG((ENABLE, "allocated %lu bytes of read buffer\n", (1<<context.play_opt->dmapool_log2size))); } /*************************************************************** Play_audio does NOT have PTS to sync ****************************************************************/ // Disable AV-Sync (for now, because STC is running on asynchronous clock, which breaks the passthrough after some time.) { struct DCCAudioSourceHandle audioHandle1; RMbool sync_stc = FALSE; err = DCCMultipleAudioSourceGetSingleDecoderHandleForInstance(dcc_info.pMultipleAudioSource, 0, &audioHandle1); if (RMSUCCEEDED(err)) { err = RUASetProperty(dcc_info.pRUA, audioHandle1.moduleID, RMAudioDecoderPropertyID_SyncSTCEnable, &sync_stc, sizeof(RMbool), 0); } else { err = RUASetProperty(dcc_info.pRUA, dcc_info.audio_decoder, RMAudioDecoderPropertyID_SyncSTCEnable, &sync_stc, sizeof(RMbool), 0); } if (RMFAILED(err)) { fprintf(stderr, "Error disabling AV-Sync! %s\n", RMstatusToString(err)); return err; } } //////////////////////////////////////////////////////////////////////// // main playback loop //////////////////////////////////////////////////////////////////////// do { enum RM_PSM_State PlaybackStatus; RMDBGLOG((ENABLE, "do-while\n")); if (context.play_opt->start_pause) RM_PSM_SetState(context.PSMcontext, &(context.dcc_info), RM_PSM_Paused); else RM_PSM_SetState(context.PSMcontext, &(context.dcc_info), RM_PSM_Playing); context.play_opt->start_pause = FALSE; mainloop: RMDBGLOG((ENABLE, "mainloop\n")); file_offset = 0; if (RMSeekFile(file, context.skipFirstNBytes, RM_FILE_SEEK_START) != RM_OK) { perror("seeking file to beginning\n"); goto cleanup; } mainloop_no_seek: RMDBGLOG((ENABLE, "mainloop no seek\n")); context.FirstPTS = 0; // pcm should start at the correct sample position if ((context.audio_opt[0].Codec == AudioDecoder_Codec_PCM) && (!context.skipFirstNBytes)) { RMint64 filePos = 0; RMint64 seekPos; RMGetCurrentPositionOfFile(file, &filePos); seekPos = filePos; seekPos -= seekPos % context.PCMblockSize; RMDBGLOG((ENABLE, "filePos %lld, blockSize %lu, new seekPos %lld\n", filePos, context.PCMblockSize, seekPos)); RMSeekFile(file, seekPos, RM_FILE_SEEK_START); } mainloop_seek: context.lastSTC = 0; context.FirstSystemTimeStamp = TRUE; context.trickMode = FALSE; context.dcc_info->state = RM_PLAYING; DCCSTCSetSpeed(dcc_info.pStcSource, 1, 1); PlaybackStatus = RM_PSM_GetState(context.PSMcontext, &(context.dcc_info)); if ((PlaybackStatus != RM_PSM_Paused) && (PlaybackStatus != RM_PSM_Stopped)) { RMDBGLOG((ENABLE, "setting play state\n")); RM_PSM_SetState(context.PSMcontext, &(context.dcc_info), RM_PSM_Playing); } else PROCESS_KEY(FALSE, TRUE); // the following call will configure the decoders, after that we can 'pause' them err = Play(&context, RM_DEVICES_AUDIO); if (err != RM_OK) goto cleanup; /* do prebufferization only when in playing state */ if (RM_PSM_GetState(context.PSMcontext, &(context.dcc_info)) == RM_PSM_Playing) { Pause(&context, RM_DEVICES_STC | RM_DEVICES_AUDIO); RM_PSM_SetState(context.PSMcontext, &(context.dcc_info), RM_PSM_Prebuffering); fprintf(stderr, "prebuffering\n"); }#ifdef WITH_MONO RMDCCInfo(&dcc_info); // pass DCC context to application#endif /* wake up disks if necessary */ switch (context.play_opt->disk_ctrl_state) { case DISK_CONTROL_STATE_DISABLE: case DISK_CONTROL_STATE_RUNNING: break; case DISK_CONTROL_STATE_SLEEPING: if(context.play_opt->disk_ctrl_callback && context.play_opt->disk_ctrl_callback(DISK_CONTROL_ACTION_RUN) == RM_OK) context.play_opt->disk_ctrl_state = DISK_CONTROL_STATE_RUNNING; break; }#ifdef WITH_BSAC bsac_frame_size = 0; DMA_buf_size = 0; bsac_get_info_done = 0;#endif while (1) { // additional 'while' used for taking care of commands issued during EOSWait while (1) { RMuint32 count; RMuint32 bufferSize = (1<<context.play_opt->dmapool_log2size); RMstatus status = RM_OK; struct emhwlib_info Info; struct emhwlib_info *pInfo = &Info; RMuint32 Info_size = sizeof(Info); RMint32 lastOKinstance = -1; if ((context.sendNBytes) && (!context.trickMode)) { RMint64 current_file_offset; RMGetCurrentPositionOfFile(file, ¤t_file_offset); if (current_file_offset - context.skipFirstNBytes > context.sendNBytes) { RMDBGLOG((ENABLE, "a seek beyond the sendable data occurred\n")); RMDBGLOG((ENABLE, "stop sending data at %llu (sendNBytes %lu, skipNBytes %lu)\n", current_file_offset, context.sendNBytes, context.skipFirstNBytes)); break; } bufferSize = context.sendNBytes - (RMuint32)current_file_offset - context.skipFirstNBytes; bufferSize = RMmin( (RMuint32)(1<<context.play_opt->dmapool_log2size), (RMuint32)bufferSize); if (!bufferSize) { RMDBGLOG((ENABLE, "stop sending data at %llu (sendNBytes %lu, skipNBytes %lu)\n", current_file_offset, context.sendNBytes, context.skipFirstNBytes)); break; } } else bufferSize = (1<<context.play_opt->dmapool_log2size); PROCESS_KEY(FALSE, TRUE); update_hdmi_audio(context.dcc_info, &(context.audio_opt[0])); if (buf) RMDBGLOG((ENABLE, "*************unreleased buffer found!\n")); get_buffer: switch (context.play_opt->disk_ctrl_state) { case DISK_CONTROL_STATE_DISABLE: case DISK_CONTROL_STATE_SLEEPING: break; case DISK_CONTROL_STATE_RUNNING: if (context.dmabuffer_index > 0) { context.dmabuffer_index--; buf = context.dmabuffer_array[context.dmabuffer_index]; RMDBGLOG((ENABLE, "fill buffer phase: got buffer %p (index %lu, level %lu, count %lu)\n", buf, context.dmabuffer_index, context.play_opt->disk_ctrl_low_level, context.play_opt->dmapool_count)); goto fill_buffer; } break; } while (RUAGetBuffer(context.pDMA, &buf, GETBUFFER_TIMEOUT_US) != RM_OK) { check_prebuf_state(&context, 0); /* fprintf(stderr, "Wait for a buffer\n"); */ switch (context.play_opt->disk_ctrl_state) { case DISK_CONTROL_STATE_DISABLE: case DISK_CONTROL_STATE_SLEEPING: break; case DISK_CONTROL_STATE_RUNNING: if(context.play_opt->disk_ctrl_callback && context.play_opt->disk_ctrl_callback(DISK_CONTROL_ACTION_SLEEP) == RM_OK) context.play_opt->disk_ctrl_state = DISK_CONTROL_STATE_SLEEPING; break; } PROCESS_KEY(FALSE, TRUE); update_hdmi_audio(context.dcc_info, &(context.audio_opt[0])); } check_prebuf_state(&context, bufferSize); switch (context.play_opt->disk_ctrl_state) { case DISK_CONTROL_STATE_DISABLE: case DISK_CONTROL_STATE_RUNNING: break; case DISK_CONTROL_STATE_SLEEPING: context.dmabuffer_array[context.dmabuffer_index] = buf; context.dmabuffer_index ++; if (context.dmabuffer_index + context.play_opt->disk_ctrl_low_level >= context.play_opt->dmapool_count) { if(context.play_opt->disk_ctrl_callback && context.play_opt->disk_ctrl_callback(DISK_CONTROL_ACTION_RUN) == RM_OK) context.play_opt->disk_ctrl_state = DISK_CONTROL_STATE_RUNNING; } RMDBGLOG((ENABLE, "recycle buffer phase: got buffer %p (index %lu, level %lu, count %lu)\n", buf, context.dmabuffer_index,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -