mirror of
				https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
				synced 2023-10-10 17:16:51 +00:00 
			
		
		
		
	Support external players.
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| User johns | User johns | ||||||
| Date: | Date: | ||||||
|  |  | ||||||
|  |     Support external players. | ||||||
|     Add VDPAU display preemption support. |     Add VDPAU display preemption support. | ||||||
|  |  | ||||||
| User m.Rcu | User m.Rcu | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								Todo
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								Todo
									
									
									
									
									
								
							| @@ -23,7 +23,7 @@ missing: | |||||||
|     software decoder with software deinterlace |     software decoder with software deinterlace | ||||||
|     zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?) |     zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?) | ||||||
|     ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? |     ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? | ||||||
|     suspend output / energie saver: stop audio, stop video, configurable |     suspend output / energie saver: stop and restart X11 | ||||||
|     Option deinterlace off / deinterlace force! |     Option deinterlace off / deinterlace force! | ||||||
|     Make output drivers better modular (under construction). |     Make output drivers better modular (under construction). | ||||||
|  |  | ||||||
| @@ -37,15 +37,14 @@ video: | |||||||
|     grab image with hardware and better scaling support |     grab image with hardware and better scaling support | ||||||
|     suspendoutput didn't show logo or black pictures |     suspendoutput didn't show logo or black pictures | ||||||
| 	(must detect video format to show image) | 	(must detect video format to show image) | ||||||
|  |     incomplete mpeg packets creates artefacts after channel switch | ||||||
|  |     hard channel switch | ||||||
|  |  | ||||||
| vdpau: | vdpau: | ||||||
|     hard channel switch |  | ||||||
|  |  | ||||||
| libva: | libva: | ||||||
|     hard channel switch |  | ||||||
|     yaepghd (VaapiSetOutputPosition) support |     yaepghd (VaapiSetOutputPosition) support | ||||||
|     can associate ony displayed part of osd |     can associate ony displayed part of osd | ||||||
|     ready(not intel checked) auto crop for va-api |  | ||||||
|     grab image for va-api |     grab image for va-api | ||||||
|     still many: |     still many: | ||||||
|     [drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung |     [drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung | ||||||
| @@ -55,8 +54,7 @@ libva: branch vaapi-ext | |||||||
|     add support for vaapi-ext |     add support for vaapi-ext | ||||||
|  |  | ||||||
| libva-intel-driver: | libva-intel-driver: | ||||||
|     intel still has hangups most with 1080i |     1080i does no v-sync (sometimes correct working with vaapi-ext) | ||||||
|     1080i does no v-sync (workaround written, fixed with vaapi-ext) |  | ||||||
|     OSD has sometimes wrong size (workaround written) |     OSD has sometimes wrong size (workaround written) | ||||||
|  |  | ||||||
| libva-vdpau-driver: | libva-vdpau-driver: | ||||||
| @@ -73,10 +71,10 @@ x11: | |||||||
|  |  | ||||||
| audio: | audio: | ||||||
|     write TS -> PES parser, which feeds audio before the next start packet |     write TS -> PES parser, which feeds audio before the next start packet | ||||||
|     CodecAudioOpen can fail "can't open audio codec" and does Fatal exit. |  | ||||||
|     Combine alsa+oss ringbuffer code. |     Combine alsa+oss ringbuffer code. | ||||||
|     Make alsa thread/polled and oss thread/polled output module runtime |     Make alsa thread/polled and oss thread/polled output module runtime | ||||||
|     selectable. |     selectable. | ||||||
|  |     software volume support | ||||||
|  |  | ||||||
| audio/alsa: | audio/alsa: | ||||||
|     better downmix of >2 channels on 2 channel hardware |     better downmix of >2 channels on 2 channel hardware | ||||||
| @@ -91,7 +89,6 @@ audio/oss: | |||||||
| HDMI/SPDIF Passthrough: | HDMI/SPDIF Passthrough: | ||||||
|     only AC-3 written |     only AC-3 written | ||||||
|     Channels are wrong setup, if changing setting during operation. |     Channels are wrong setup, if changing setting during operation. | ||||||
|     split pcm and ac-3 out into two devices |  | ||||||
|     support oss pass-through |     support oss pass-through | ||||||
|  |  | ||||||
| playback of recording | playback of recording | ||||||
| @@ -119,6 +116,5 @@ future features (not planed for 1.0 - 1.5) | |||||||
|     atmolight support |     atmolight support | ||||||
|     multistream handling |     multistream handling | ||||||
|     pip support |     pip support | ||||||
|     grab image with jpeg |  | ||||||
|  |  | ||||||
|     upmix stereo to AC-3 |     upmix stereo to AC-3 | ||||||
|   | |||||||
							
								
								
									
										80
									
								
								softhddev.c
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								softhddev.c
									
									
									
									
									
								
							| @@ -61,8 +61,6 @@ static char ConfigVdpauDecoder = 1;	///< use vdpau decoder, if possible | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| static char ConfigFullscreen;		///< fullscreen modus | static char ConfigFullscreen;		///< fullscreen modus | ||||||
| char ConfigSuspendClose;		///< suspend should close devices |  | ||||||
| char ConfigSuspendX11;			///< suspend should stop x11 |  | ||||||
|  |  | ||||||
| static pthread_mutex_t SuspendLockMutex;	///< suspend lock mutex | static pthread_mutex_t SuspendLockMutex;	///< suspend lock mutex | ||||||
|  |  | ||||||
| @@ -212,15 +210,15 @@ int PlayAudio(const uint8_t * data, int size, | |||||||
|     if (VideoFreezed) {			// video freezed |     if (VideoFreezed) {			// video freezed | ||||||
| 	return 0; | 	return 0; | ||||||
|     } |     } | ||||||
|  |     if (SkipAudio || !MyAudioDecoder) {	// skip audio | ||||||
|  | 	return size; | ||||||
|  |     } | ||||||
|     if (NewAudioStream) { |     if (NewAudioStream) { | ||||||
| 	// FIXME: does this clear the audio ringbuffer? | 	// FIXME: does this clear the audio ringbuffer? | ||||||
| 	CodecAudioClose(MyAudioDecoder); | 	CodecAudioClose(MyAudioDecoder); | ||||||
| 	AudioCodecID = CODEC_ID_NONE; | 	AudioCodecID = CODEC_ID_NONE; | ||||||
| 	NewAudioStream = 0; | 	NewAudioStream = 0; | ||||||
|     } |     } | ||||||
|     if (SkipAudio) {			// skip audio |  | ||||||
| 	return size; |  | ||||||
|     } |  | ||||||
|     // PES header 0x00 0x00 0x01 ID |     // PES header 0x00 0x00 0x01 ID | ||||||
|     // ID 0xBD 0xC0-0xCF |     // ID 0xBD 0xC0-0xCF | ||||||
|  |  | ||||||
| @@ -263,27 +261,17 @@ int PlayAudio(const uint8_t * data, int size, | |||||||
|  |  | ||||||
|     // Syncword - 0x0B77 |     // Syncword - 0x0B77 | ||||||
|     if (data[0] == 0x0B && data[1] == 0x77) { |     if (data[0] == 0x0B && data[1] == 0x77) { | ||||||
| 	if (!MyAudioDecoder) { |  | ||||||
| 	    MyAudioDecoder = CodecAudioNewDecoder(); |  | ||||||
| 	    AudioCodecID = CODEC_ID_NONE; |  | ||||||
| 	} |  | ||||||
| 	if (AudioCodecID != CODEC_ID_AC3) { | 	if (AudioCodecID != CODEC_ID_AC3) { | ||||||
| 	    Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id); | 	    Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id); | ||||||
| 	    CodecAudioClose(MyAudioDecoder); | 	    CodecAudioClose(MyAudioDecoder); | ||||||
|  |  | ||||||
| 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3); | 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3); | ||||||
| 	    AudioCodecID = CODEC_ID_AC3; | 	    AudioCodecID = CODEC_ID_AC3; | ||||||
| 	} | 	} | ||||||
| 	// Syncword - 0xFFFC - 0xFFFF | 	// Syncword - 0xFFFC - 0xFFFF | ||||||
|     } else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) { |     } else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) { | ||||||
| 	if (!MyAudioDecoder) { |  | ||||||
| 	    MyAudioDecoder = CodecAudioNewDecoder(); |  | ||||||
| 	    AudioCodecID = CODEC_ID_NONE; |  | ||||||
| 	} |  | ||||||
| 	if (AudioCodecID != CODEC_ID_MP2) { | 	if (AudioCodecID != CODEC_ID_MP2) { | ||||||
| 	    Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id); | 	    Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id); | ||||||
| 	    CodecAudioClose(MyAudioDecoder); | 	    CodecAudioClose(MyAudioDecoder); | ||||||
|  |  | ||||||
| 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2); | 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2); | ||||||
| 	    AudioCodecID = CODEC_ID_MP2; | 	    AudioCodecID = CODEC_ID_MP2; | ||||||
| 	} | 	} | ||||||
| @@ -300,9 +288,6 @@ int PlayAudio(const uint8_t * data, int size, | |||||||
| 	    if (n < 0) { | 	    if (n < 0) { | ||||||
| 		return osize; | 		return osize; | ||||||
| 	    } | 	    } | ||||||
| 	    if (!MyAudioDecoder) { |  | ||||||
| 		MyAudioDecoder = CodecAudioNewDecoder(); |  | ||||||
| 	    } |  | ||||||
|  |  | ||||||
| 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2); | 	    CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2); | ||||||
| 	    AudioCodecID = CODEC_ID_MP2; | 	    AudioCodecID = CODEC_ID_MP2; | ||||||
| @@ -312,7 +297,7 @@ int PlayAudio(const uint8_t * data, int size, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // no decoder or codec known |     // no decoder or codec known | ||||||
|     if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) { |     if (AudioCodecID == CODEC_ID_NONE) { | ||||||
| 	return osize; | 	return osize; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -757,13 +742,15 @@ int PlayVideo(const uint8_t * data, int size) | |||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|     // FIXME: no valid mpeg2/h264 detection yet |  | ||||||
|  |  | ||||||
|     check = data + 9 + n; |     check = data + 9 + n; | ||||||
|     if (0) { |     if (0) { | ||||||
| 	printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1], | 	printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1], | ||||||
| 	    check[2], check[3], check[4]); | 	    check[2], check[3], check[4]); | ||||||
|     } |     } | ||||||
|  |     // FIXME: no valid mpeg2/h264 detection yet | ||||||
|  |     // FIXME: better skip all zero's >3 && 0x01 0x09 h264, >2 && 0x01 -> mpeg2 | ||||||
|  |  | ||||||
|     // PES_VIDEO_STREAM 0xE0 or PES start code |     // PES_VIDEO_STREAM 0xE0 or PES start code | ||||||
|     //(data[6] & 0xC0) != 0x80 || |     //(data[6] & 0xC0) != 0x80 || | ||||||
|     if ((!check[0] && !check[1] && check[2] == 0x1)) { |     if ((!check[0] && !check[1] && check[2] == 0x1)) { | ||||||
| @@ -803,7 +790,9 @@ int PlayVideo(const uint8_t * data, int size) | |||||||
| 	    Debug(3, "video: not detected\n"); | 	    Debug(3, "video: not detected\n"); | ||||||
| 	    return size; | 	    return size; | ||||||
| 	} | 	} | ||||||
| 	if (VideoCodecID == CODEC_ID_MPEG2VIDEO) { | 	// FIXME: incomplete packets produce artefacts after channel switch | ||||||
|  | 	if (atomic_read(&VideoPacketsFilled) | ||||||
|  | 	    && VideoCodecID == CODEC_ID_MPEG2VIDEO) { | ||||||
| 	    // mpeg codec supports incomplete packets | 	    // mpeg codec supports incomplete packets | ||||||
| 	    // waiting for a full complete packages, increases needed delays | 	    // waiting for a full complete packages, increases needed delays | ||||||
| 	    VideoNextPacket(CODEC_ID_MPEG2VIDEO); | 	    VideoNextPacket(CODEC_ID_MPEG2VIDEO); | ||||||
| @@ -1079,7 +1068,6 @@ void OsdClose(void) | |||||||
| */ | */ | ||||||
| void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb) | void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb) | ||||||
| { | { | ||||||
|     Resume(); |  | ||||||
|     VideoOsdDrawARGB(x, y, height, width, argb); |     VideoOsdDrawARGB(x, y, height, width, argb); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1316,8 +1304,12 @@ void Start(void) | |||||||
| 	StartXServer(); | 	StartXServer(); | ||||||
|     } |     } | ||||||
|     CodecInit(); |     CodecInit(); | ||||||
|  |  | ||||||
|     // FIXME: AudioInit for HDMI after X11 startup |     // FIXME: AudioInit for HDMI after X11 startup | ||||||
|     AudioInit(); |     AudioInit(); | ||||||
|  |     MyAudioDecoder = CodecAudioNewDecoder(); | ||||||
|  |     AudioCodecID = CODEC_ID_NONE; | ||||||
|  |  | ||||||
|     if (!ConfigStartX11Server) { |     if (!ConfigStartX11Server) { | ||||||
| 	StartVideo(); | 	StartVideo(); | ||||||
|     } |     } | ||||||
| @@ -1350,8 +1342,12 @@ void MainThreadHook(void) | |||||||
|  |  | ||||||
| /** | /** | ||||||
| **	Suspend plugin. | **	Suspend plugin. | ||||||
|  | ** | ||||||
|  | **	@param video	suspend closes video | ||||||
|  | **	@param audio	suspend closes audio | ||||||
|  | **	@param dox11	suspend closes x11 server | ||||||
| */ | */ | ||||||
| void Suspend(void) | void Suspend(int video, int audio, int dox11) | ||||||
| { | { | ||||||
|     pthread_mutex_lock(&SuspendLockMutex); |     pthread_mutex_lock(&SuspendLockMutex); | ||||||
|     if (SkipVideo && SkipAudio) {	// already suspended |     if (SkipVideo && SkipAudio) {	// already suspended | ||||||
| @@ -1365,22 +1361,25 @@ void Suspend(void) | |||||||
|     SkipAudio = 1; |     SkipAudio = 1; | ||||||
|     pthread_mutex_unlock(&SuspendLockMutex); |     pthread_mutex_unlock(&SuspendLockMutex); | ||||||
|  |  | ||||||
|     if (ConfigSuspendClose) { |     if (audio || video) { | ||||||
| 	pthread_mutex_lock(&SuspendLockMutex); | 	pthread_mutex_lock(&SuspendLockMutex); | ||||||
|  |  | ||||||
| 	AudioExit(); | 	if (audio) { | ||||||
| 	if (MyAudioDecoder) { | 	    AudioExit(); | ||||||
| 	    CodecAudioClose(MyAudioDecoder); | 	    if (MyAudioDecoder) { | ||||||
| 	    CodecAudioDelDecoder(MyAudioDecoder); | 		CodecAudioClose(MyAudioDecoder); | ||||||
| 	    MyAudioDecoder = NULL; | 		CodecAudioDelDecoder(MyAudioDecoder); | ||||||
|  | 		MyAudioDecoder = NULL; | ||||||
|  | 	    } | ||||||
|  | 	    NewAudioStream = 0; | ||||||
|  | 	} | ||||||
|  | 	if (video) { | ||||||
|  | 	    StopVideo(); | ||||||
| 	} | 	} | ||||||
| 	NewAudioStream = 0; |  | ||||||
|  |  | ||||||
| 	StopVideo(); |  | ||||||
|  |  | ||||||
| 	pthread_mutex_unlock(&SuspendLockMutex); | 	pthread_mutex_unlock(&SuspendLockMutex); | ||||||
|     } |     } | ||||||
|     if (ConfigSuspendX11) { |     if (dox11) { | ||||||
| 	// FIXME: stop x11, if started | 	// FIXME: stop x11, if started | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1396,17 +1395,20 @@ void Resume(void) | |||||||
|  |  | ||||||
|     Debug(3, "[softhddev]%s:\n", __FUNCTION__); |     Debug(3, "[softhddev]%s:\n", __FUNCTION__); | ||||||
|  |  | ||||||
|     if (ConfigSuspendX11) { |     pthread_mutex_lock(&SuspendLockMutex); | ||||||
|     } |     // FIXME: start x11 | ||||||
|     if (ConfigSuspendClose) { |  | ||||||
| 	pthread_mutex_lock(&SuspendLockMutex); |  | ||||||
|  |  | ||||||
|  |     if (!MyHwDecoder) {			// video not running | ||||||
| 	StartVideo(); | 	StartVideo(); | ||||||
|  |     } | ||||||
|  |     if (!MyAudioDecoder) {		// audio not running | ||||||
| 	AudioInit(); | 	AudioInit(); | ||||||
|  | 	MyAudioDecoder = CodecAudioNewDecoder(); | ||||||
| 	pthread_mutex_unlock(&SuspendLockMutex); | 	AudioCodecID = CODEC_ID_NONE; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     SkipVideo = 0; |     SkipVideo = 0; | ||||||
|     SkipAudio = 0; |     SkipAudio = 0; | ||||||
|  |  | ||||||
|  |     pthread_mutex_unlock(&SuspendLockMutex); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -79,7 +79,7 @@ extern "C" | |||||||
|     extern void MainThreadHook(void); |     extern void MainThreadHook(void); | ||||||
|  |  | ||||||
|     /// Suspend plugin |     /// Suspend plugin | ||||||
|     extern void Suspend(void); |     extern void Suspend(int, int, int); | ||||||
|     /// Resume plugin |     /// Resume plugin | ||||||
|     extern void Resume(void); |     extern void Resume(void); | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|   | |||||||
| @@ -38,8 +38,6 @@ extern "C" | |||||||
| #include "video.h" | #include "video.h" | ||||||
|     extern void AudioPoller(void); |     extern void AudioPoller(void); | ||||||
|     extern void CodecSetAudioPassthrough(int); |     extern void CodecSetAudioPassthrough(int); | ||||||
|     extern char ConfigSuspendClose;	///< suspend should close devices |  | ||||||
|     extern char ConfigSuspendX11;	///< suspend should stop x11 |  | ||||||
| } | } | ||||||
|  |  | ||||||
| ////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -84,6 +82,9 @@ static int ConfigAudioPassthrough;	///< config audio pass-through | |||||||
| static int ConfigAutoCropInterval;	///< auto crop detection interval | static int ConfigAutoCropInterval;	///< auto crop detection interval | ||||||
| static int ConfigAutoCropDelay;		///< auto crop detection delay | static int ConfigAutoCropDelay;		///< auto crop detection delay | ||||||
|  |  | ||||||
|  | static char ConfigSuspendClose;		///< suspend should close devices | ||||||
|  | static char ConfigSuspendX11;		///< suspend should stop x11 | ||||||
|  |  | ||||||
| static volatile char DoMakePrimary;	///< flag switch primary | static volatile char DoMakePrimary;	///< flag switch primary | ||||||
|  |  | ||||||
| ////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -722,7 +723,8 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode) | |||||||
| 	    return true; | 	    return true; | ||||||
| 	case pmExtern_THIS_SHOULD_BE_AVOIDED: | 	case pmExtern_THIS_SHOULD_BE_AVOIDED: | ||||||
| 	    dsyslog("[softhddev] play mode external\n"); | 	    dsyslog("[softhddev] play mode external\n"); | ||||||
| 	    break; | 	    Suspend(1, 1, 0); | ||||||
|  | 	    return true; | ||||||
| 	default: | 	default: | ||||||
| 	    dsyslog("[softhddev]playmode not implemented... %d\n", play_mode); | 	    dsyslog("[softhddev]playmode not implemented... %d\n", play_mode); | ||||||
| 	    break; | 	    break; | ||||||
| @@ -1096,7 +1098,7 @@ cOsdObject *cPluginSoftHdDevice::MainMenuAction(void) | |||||||
|     //MyDevice->StopReplay(); |     //MyDevice->StopReplay(); | ||||||
|     cControl::Launch(new cSoftHdControl); |     cControl::Launch(new cSoftHdControl); | ||||||
|     cControl::Attach(); |     cControl::Attach(); | ||||||
|     Suspend(); |     Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11); | ||||||
|     if (ShutdownHandler.GetUserInactiveTime()) { |     if (ShutdownHandler.GetUserInactiveTime()) { | ||||||
| 	dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__); | 	dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__); | ||||||
| 	ShutdownHandler.SetUserInactive(); | 	ShutdownHandler.SetUserInactive(); | ||||||
| @@ -1121,7 +1123,7 @@ void cPluginSoftHdDevice::MainThreadHook(void) | |||||||
|     // check if user is inactive, automatic enter suspend mode |     // check if user is inactive, automatic enter suspend mode | ||||||
|     if (ShutdownHandler.IsUserInactive()) { |     if (ShutdownHandler.IsUserInactive()) { | ||||||
| 	// this is regular called, but guarded against double calls | 	// this is regular called, but guarded against double calls | ||||||
| 	Suspend(); | 	Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ::MainThreadHook(); |     ::MainThreadHook(); | ||||||
| @@ -1271,7 +1273,7 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command, | |||||||
|     if (!strcasecmp(command, "SUSP")) { |     if (!strcasecmp(command, "SUSP")) { | ||||||
| 	cControl::Launch(new cSoftHdControl); | 	cControl::Launch(new cSoftHdControl); | ||||||
| 	cControl::Attach(); | 	cControl::Attach(); | ||||||
| 	Suspend(); | 	Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11); | ||||||
| 	return "SoftHdDevice is suspended"; | 	return "SoftHdDevice is suspended"; | ||||||
|     } |     } | ||||||
|     if (!strcasecmp(command, "RESU")) { |     if (!strcasecmp(command, "RESU")) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user