/*{{{ AudioIoctlStop*/ int AudioIoctlStop (struct DeviceContext_s* Context) { int Result = 0; DVB_DEBUG("\n"); /*if (Context->AudioState.play_state == AUDIO_PLAYING)*/ if (Context->AudioStream != NULL) { struct mutex* WriteLock = Context->ActiveAudioWriteLock; /* Discard previously injected data to free the lock. */ StreamDrain (Context->AudioStream, true); /*mutex_lock (WriteLock);*/ if (mutex_lock_interruptible (WriteLock) != 0) return -ERESTARTSYS; /* Give up for now. The stream will be removed later by the release */ /*StreamEnable (Context->PlayerContext, STREAM_CONTENT_AUDIO, false);*/ Result = PlaybackRemoveStream (Context->Playback, Context->AudioStream); if (Result == 0) { Context->AudioStream = NULL; Context->AudioState.play_state = AUDIO_STOPPED; Context->ActiveAudioWriteLock = &(Context->AudioWriteLock); /*AudioInit (Context);*/ } mutex_unlock (WriteLock); } DVB_DEBUG("Play state = %d\n", Context->AudioState.play_state); return Result; }
/*{{{ AudioIoctlSetSpeed*/ static int AudioIoctlSetSpeed (struct DeviceContext_s* Context, int Speed) { #if 0 int Result; DVB_DEBUG("\n"); if (Context->Playback == NULL) { Context->PlaySpeed = Speed; return 0; } Result = PlaybackSetSpeed (Context->Playback, Speed); if (Result < 0) return Result; Result = PlaybackGetSpeed (Context->Playback, &Context->PlaySpeed); if (Result < 0) return Result; DVB_DEBUG("Speed set to %d\n", Context->PlaySpeed); return Result; #else int DirectionChange; int Result; DVB_DEBUG("\n"); if (Context->Playback == NULL) { Context->PlaySpeed = Speed; return 0; } /* If changing direction we require a write lock */ DirectionChange = ((Speed * Context->PlaySpeed) < 0); if (DirectionChange) { /* Discard previously injected data to free the lock. */ StreamDrain (Context->AudioStream, true); if (mutex_lock_interruptible (Context->ActiveAudioWriteLock) != 0) return -ERESTARTSYS; /* Give up for now. */ } Result = PlaybackSetSpeed (Context->Playback, Speed); if (Result >= 0) Result = PlaybackGetSpeed (Context->Playback, &Context->PlaySpeed); /* If changing direction release write lock*/ if (DirectionChange) mutex_unlock( Context->ActiveAudioWriteLock ); DVB_DEBUG("Speed set to %d\n", Context->PlaySpeed); return Result; #endif }
/*{{{ AudioRelease*/ static int AudioRelease (struct inode* Inode, struct file* File) { struct dvb_device* DvbDevice = (struct dvb_device*)File->private_data; struct DeviceContext_s* Context = (struct DeviceContext_s*)DvbDevice->priv; struct DvbContext_s* DvbContext = Context->DvbContext; DVB_DEBUG("\n"); if ((File->f_flags & O_ACCMODE) != O_RDONLY) { mutex_lock (&(DvbContext->Lock)); if (Context->AudioStream != NULL) { unsigned int MutexIsLocked = true; /* Discard previously injected data to free the lock. */ StreamDrain (Context->AudioStream, true); if (mutex_lock_interruptible (Context->ActiveAudioWriteLock) != 0) MutexIsLocked = false; PlaybackRemoveStream (Context->Playback, Context->AudioStream); Context->AudioStream = NULL; if (MutexIsLocked) mutex_unlock (Context->ActiveAudioWriteLock); } DisplayDelete (BACKEND_AUDIO_ID, Context->Id); /* Check to see if video and demux have also finished so we can release the playback */ if ((Context->VideoStream == NULL) && (Context->DemuxStream == NULL) && (Context->Playback != NULL)) { /* Check to see if our playback has already been deleted by the demux context */ if (Context->DemuxContext->Playback != NULL) { /* Try and delete playback then set our demux to Null if succesful or not. If we fail someone else is still using it but we are done. */ if (PlaybackDelete (Context->Playback) == 0) DVB_DEBUG("Playback deleted successfully\n"); } Context->Playback = NULL; Context->StreamType = STREAM_TYPE_TRANSPORT; Context->PlaySpeed = DVB_SPEED_NORMAL_PLAY; Context->PlayInterval.start = DVB_TIME_NOT_BOUNDED; Context->PlayInterval.end = DVB_TIME_NOT_BOUNDED; Context->SyncContext = Context; } AudioInit (Context); mutex_unlock (&(DvbContext->Lock)); } return dvb_generic_release (Inode, File); }
/*{{{ AudioIoctlSelectSource*/ static int AudioIoctlSelectSource (struct DeviceContext_s* Context, audio_stream_source_t Source) { DVB_DEBUG("\n"); Context->AudioState.stream_source = Source; if (Source == AUDIO_SOURCE_DEMUX) Context->StreamType = STREAM_TYPE_TRANSPORT; else Context->StreamType = STREAM_TYPE_PES; DVB_DEBUG("Source = %x\n", Context->AudioState.stream_source); return 0; }
/*{{{ AudioIoctlGetStatus*/ static int AudioIoctlGetStatus (struct DeviceContext_s* Context, struct audio_status* Status) { memcpy (Status, &Context->AudioState, sizeof(struct audio_status)); DVB_DEBUG("\n"); return 0; }
/*{{{ AudioIoctlGetCapabilities*/ static int AudioIoctlGetCapabilities (struct DeviceContext_s* Context, int* Capabilities) { *Capabilities = AUDIO_CAP_DTS | AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2 | AUDIO_CAP_MP3 | AUDIO_CAP_AAC | AUDIO_CAP_AC3; DVB_DEBUG("Capabilities returned = %x\n", *Capabilities); return 0; }
/*{{{ AudioIoctlSetSyncGroup*/ static int AudioIoctlSetSyncGroup (struct DeviceContext_s* Context, unsigned int Group) { int Result = 0; if (Context != Context->SyncContext) { DVB_ERROR("Sync group already set - cannot reset\n"); return -EPERM; } if ((Group < 0) || (Group >= DVB_MAX_DEVICES_PER_ADAPTER)) { DVB_ERROR("Invalid sync group - out of range.\n"); return -EPERM; } if (Context->SyncContext->Playback) { DVB_ERROR("Sync group already set - cannot reset\n"); return -EPERM; } Context->SyncContext = &Context->DvbContext->DeviceContext[Group]; DVB_DEBUG("Sync group set to device %d\n", Group); return Result; }
/*{{{ AudioIoctlSetSpdifSource*/ static int AudioIoctlSetSpdifSource (struct DeviceContext_s* Context, unsigned int Mode) { int Result; int BypassCodedData = (Mode == AUDIO_SPDIF_SOURCE_ES); DVB_DEBUG("\n"); if ((Mode != AUDIO_SPDIF_SOURCE_PP) && (Mode != AUDIO_SPDIF_SOURCE_ES)) return -EINVAL; DVB_DEBUG("Bypass = %s\n", BypassCodedData ? "Enabled (ES)" : "Disabled (Post-proc LPCM)"); if (Context->AudioState.bypass_mode == BypassCodedData) return 0; Result = StreamSetOption (Context->AudioStream, PLAY_OPTION_AUDIO_SPDIF_SOURCE, (unsigned int)BypassCodedData); if (Result == 0) Context->AudioState.bypass_mode = Mode; return Result; }
/*{{{ AudioIoctlSetStreamType*/ static int AudioIoctlSetStreamType(struct DeviceContext_s* Context, unsigned int Type) { DVB_DEBUG("Set type to %x\n", Type); /*if ((Type < STREAM_TYPE_TRANSPORT) || (Type > STREAM_TYPE_PES))*/ if ((Type < STREAM_TYPE_NONE) || (Type > STREAM_TYPE_RAW)) return -EINVAL; Context->StreamType = (stream_type_t)Type; return 0; }
static int AudioIoctlSetAvSync (struct DeviceContext_s* Context, unsigned int State) #endif { int Result = 0; DVB_DEBUG("\n"); /* implicitly un-mute audio when we re-enable AV sync */ if (Context->AudioState.play_state == AUDIO_PLAYING) StreamEnable (Context->AudioStream, true); if (Context->AudioStream != NULL) Result = StreamSetOption (Context->AudioStream, PLAY_OPTION_AV_SYNC, State ? PLAY_OPTION_VALUE_ENABLE : PLAY_OPTION_VALUE_DISABLE); if (Result != 0) return Result; Context->AudioState.AV_sync_state = (int)State; DVB_DEBUG("AV Sync = %d\n", Context->AudioState.AV_sync_state); return Result; }
static void __exit StmUnloadModule (void) { int i; BackendDelete (); for (i = 0; i < DVB_MAX_DEVICES_PER_ADAPTER; i++) { struct DeviceContext_s* DeviceContext = &DvbContext->DeviceContext[i]; struct dvb_demux* DvbDemux = &DeviceContext->DvbDemux; struct dmxdev* DmxDevice = &DeviceContext->DmxDevice; #if defined (USE_KERNEL_DEMUX) if (DmxDevice != NULL) { /* We don't need to unregister DmxDevice->dvr_dvbdev as this will be done by dvb_dmxdev_release */ dvb_dmxdev_release (DmxDevice); } if (DvbDemux != NULL) { DvbDemux->dmx.remove_frontend (&DvbDemux->dmx, &DeviceContext->MemoryFrontend); dvb_dmx_release (DvbDemux); } #else dvb_unregister_device (DeviceContext->DemuxDevice); dvb_unregister_device (DeviceContext->DvrDevice); #endif if (DeviceContext->AudioDevice != NULL) dvb_unregister_device (DeviceContext->AudioDevice); if (DeviceContext->VideoDevice != NULL) dvb_unregister_device (DeviceContext->VideoDevice); PlaybackDelete (DeviceContext->Playback); DeviceContext->AudioStream = NULL; DeviceContext->VideoStream = NULL; DeviceContext->Playback = NULL; kfree(DeviceContext->dvr_in); kfree(DeviceContext->dvr_out); } if (DvbContext != NULL) { dvb_unregister_adapter (&DvbContext->DvbAdapter); kfree (DvbContext); } DvbContext = NULL; DVB_DEBUG("STM stream device unloaded\n"); return; }
/*{{{ AudioIoctlSetMute*/ static int AudioIoctlSetMute (struct DeviceContext_s* Context, unsigned int State) { int Result = 0; DVB_DEBUG("Mute = %d (was %d)\n", State, Context->AudioState.mute_state); if (Context->AudioStream != NULL) Result = StreamEnable (Context->AudioStream, !State); if (Result == 0) Context->AudioState.mute_state = (int)State; return Result; }
/*{{{ AudioIoctlChannelSelect*/ static int AudioIoctlChannelSelect (struct DeviceContext_s* Context, audio_channel_select_t Channel) { int Result = 0; DVB_DEBUG("Channel = %x\n", Channel); if (Context->AudioStream != NULL) Result = StreamChannelSelect (Context->AudioStream, (channel_select_t)Channel); if (Result != 0) return Result; Context->AudioState.channel_select = Channel; return Result; }
static int AudioIoctlPause (struct DeviceContext_s* Context) #endif { int Result = 0; DVB_DEBUG("\n"); if (Context->AudioState.play_state == AUDIO_PLAYING) { Result = AudioIoctlSetSpeed (Context, DVB_SPEED_STOPPED); if (Result < 0) return Result; Context->AudioState.play_state = AUDIO_PAUSED; } return 0; }
static int AudioIoctlContinue (struct DeviceContext_s* Context) #endif { int Result = 0; DVB_DEBUG("\n"); if ((Context->AudioState.play_state == AUDIO_PAUSED) || (Context->AudioState.play_state == AUDIO_PLAYING)) { Result = AudioIoctlSetSpeed (Context, DVB_SPEED_NORMAL_PLAY); if (Result < 0) return Result; Context->AudioState.play_state = AUDIO_PLAYING; } return 0; }
/*{{{ AudioIoctlSetId*/ int AudioIoctlSetId (struct DeviceContext_s* Context, int Id) { int Result = 0; unsigned int DemuxId = (Context->AudioState.stream_source == AUDIO_SOURCE_DEMUX) ? Context->DemuxContext->Id : DEMUX_INVALID_ID; DVB_DEBUG("Setting Audio Id to %04x\n", Id); if (Context->AudioStream != NULL) Result = StreamSetId (Context->AudioStream, DemuxId, Id); if (Result != 0) return Result; Context->AudioId = Id; return Result; }
/*{{{ AudioIoctlSetPlayInterval*/ static int AudioIoctlSetPlayInterval (struct DeviceContext_s* Context, dvb_play_interval_t* PlayInterval) { int Result; DVB_DEBUG("\n"); memcpy (&Context->PlayInterval, PlayInterval, sizeof(dvb_play_interval_t)); if (Context->Playback == NULL) return 0; Result = PlaybackSetPlayInterval (Context->Playback, (play_interval_t*)PlayInterval); if (Result < 0) return Result; return Result; }
static int DvrOpen (struct inode* Inode, struct file* File) { struct dvb_device* DvbDevice = (struct dvb_device*)File->private_data; struct dmxdev* DmxDevice = (struct dmxdev*)DvbDevice->priv; struct dvb_demux* DvbDemux = (struct dvb_demux*)DmxDevice->demux->priv; struct DeviceContext_s* Context = (struct DeviceContext_s*)DvbDemux->priv; DVB_DEBUG("\n"); #if 0 if ((Context->Playback == NULL) && (Context->DemuxContext->Playback == NULL)) { Result = DvbPlaybackCreate (&Context->Playback); if (Result < 0) return Result; Result = DvbPlaybackSetSpeed (Context->Playback, Context->PlaySpeed); if (Result < 0) return Result; if (Context != Context->DemuxContext) Context->DemuxContext->Playback = Context->Playback; } if ((Context->DemuxStream == NULL) && (Context->DemuxContext->DemuxStream == NULL)) { Result = DvbPlaybackAddDemux (Context->Playback, Context->DemuxContext->Id, &Context->DemuxStream); if (Result < 0) return Result; if (Context != Context->DemuxContext) Context->DemuxContext->DemuxStream = Context->DemuxStream; } #endif #ifdef __TDT__ //sylvester: wenn der stream vom user kommt soll WriteToDecoder nix //tun, da das ja hier schon passiert. keine ahnung wie man das ansonsten //verhindern soll;-) Context->dvr_write = 0; #else Context->StartOffset = -1; Context->EndOffset = -1; #endif return OriginalDvrFops.open (Inode, File); }
/*{{{ AudioIoctlFlush*/ static int AudioIoctlFlush (struct DeviceContext_s* Context) { int Result = 0; struct DvbContext_s* DvbContext = Context->DvbContext; DVB_DEBUG("\n"); /* If the stream is frozen it cannot be drained so an error is returned. */ if ((Context->PlaySpeed == 0) || (Context->PlaySpeed == DVB_SPEED_REVERSE_STOPPED)) return -EPERM; if (mutex_lock_interruptible (Context->ActiveAudioWriteLock) != 0) return -ERESTARTSYS; mutex_unlock (&(DvbContext->Lock)); /* release lock so non-writing ioctls still work while draining */ Result = StreamDrain (Context->AudioStream, false); mutex_unlock (Context->ActiveAudioWriteLock); /* release write lock so actions which have context lock can complete */ mutex_lock (&(DvbContext->Lock)); /* reclaim lock so can be released by outer function */ return Result; }
/*{{{ AudioIoctlDiscontinuity*/ static int AudioIoctlDiscontinuity (struct DeviceContext_s* Context, audio_discontinuity_t Discontinuity) { int Result = 0; DVB_DEBUG("%d\n", Discontinuity); /* If the stream is frozen a discontinuity cannot be injected. */ if ((Context->AudioState.play_state == AUDIO_PAUSED) || (Context->PlaySpeed == 0) || (Context->PlaySpeed == DVB_SPEED_REVERSE_STOPPED)) return -EINVAL; /*mutex_lock (Context->ActiveAudioWriteLock);*/ if (mutex_lock_interruptible (Context->ActiveAudioWriteLock) != 0) return -ERESTARTSYS; Result = StreamDiscontinuity (Context->AudioStream, (discontinuity_t)Discontinuity); mutex_unlock (Context->ActiveAudioWriteLock); return Result; }
/*{{{ AudioIoctlSetEncoding*/ static int AudioIoctlSetEncoding (struct DeviceContext_s* Context, unsigned int Encoding) { DVB_DEBUG("Set encoding to %d\n", Encoding); if ((Encoding < AUDIO_ENCODING_AUTO) || (Encoding > AUDIO_ENCODING_PRIVATE)) return -EINVAL; if ((Context->AudioState.play_state != AUDIO_STOPPED) && (Context->AudioState.play_state != AUDIO_INCOMPLETE)) { DVB_ERROR("Cannot change encoding after play has started\n"); return -EPERM; } Context->AudioEncoding = (audio_encoding_t)Encoding; /* At this point we have received the missing piece of information which will allow the * stream to be fully populated so we can reissue the play. */ if (Context->AudioState.play_state == AUDIO_INCOMPLETE) AudioIoctlPlay (Context); return 0; }
static int AudioIoctlClearBuffer (struct DeviceContext_s* Context) #endif { int Result = 0; #ifdef __TDT__ int prevSpeed = 0; #endif dvb_discontinuity_t Discontinuity = DVB_DISCONTINUITY_SKIP | DVB_DISCONTINUITY_SURPLUS_DATA; DVB_DEBUG("\n"); #ifdef __TDT__ prevSpeed = Context->AudioState.play_state; #endif /* Discard previously injected data to free the lock. */ StreamDrain (Context->AudioStream, true); /*mutex_lock (Context->ActiveAudioWriteLock);*/ if (mutex_lock_interruptible (Context->ActiveAudioWriteLock) != 0) return -ERESTARTSYS; StreamDrain (Context->AudioStream, true); if (Result == 0) Result = StreamDiscontinuity (Context->AudioStream, Discontinuity); mutex_unlock (Context->ActiveAudioWriteLock); #ifdef __TDT__ //it seems like the player forgets our current status after clear buffer if(prevSpeed == AUDIO_PAUSED) { AudioIoctlSetSpeed (Context, DVB_SPEED_STOPPED); } #endif return Result; }
/*{{{ AudioIoctlPlay*/ int AudioIoctlPlay (struct DeviceContext_s* Context) { int Result = 0; sigset_t newsigs, oldsigs; DVB_DEBUG("\n"); if ((Context->AudioState.play_state == AUDIO_STOPPED) || (Context->AudioState.play_state == AUDIO_INCOMPLETE)) { if (Context->Playback == NULL) { /* Check to see if we are wired to a demux. If so the demux should create the playback and we will get another play call. Just exit in this case. If we are playing from memory we need to create a playback. */ if (Context->AudioState.stream_source == AUDIO_SOURCE_DEMUX) { if (Context->DemuxContext->Playback == NULL) return 0; else Context->Playback = Context->DemuxContext->Playback; } else if (Context->SyncContext->Playback == NULL) { Result = PlaybackCreate (&Context->Playback); if (Result < 0) return Result; if (Context->PlaySpeed != DVB_SPEED_NORMAL_PLAY) { Result = AudioIoctlSetSpeed (Context, Context->PlaySpeed); if (Result < 0) return Result; } if ((Context->PlayInterval.start != DVB_TIME_NOT_BOUNDED) || (Context->PlayInterval.end != DVB_TIME_NOT_BOUNDED)) { Result = AudioIoctlSetPlayInterval (Context, &Context->PlayInterval); if (Result < 0) return Result; } Context->SyncContext->Playback = Context->Playback; } else Context->Playback = Context->SyncContext->Playback; } PlaybackInit (Context); if ((Context->AudioStream == NULL) || (Context->AudioState.play_state == AUDIO_INCOMPLETE)) { unsigned int DemuxId = (Context->AudioState.stream_source == AUDIO_SOURCE_DEMUX) ? Context->DemuxContext->Id : DEMUX_INVALID_ID; /* a signal received in here can cause issues! Lets turn them off, just for this bit... */ sigfillset(&newsigs); sigprocmask(SIG_BLOCK, &newsigs, &oldsigs); Result = PlaybackAddStream (Context->Playback, BACKEND_AUDIO_ID, BACKEND_PES_ID, AudioContent[Context->AudioEncoding], DemuxId, Context->Id, &Context->AudioStream); sigprocmask(SIG_SETMASK, &oldsigs, NULL); if (Result == STREAM_INCOMPLETE) { Context->AudioState.play_state = AUDIO_INCOMPLETE; return 0; } if (Result == 0) Result = AudioIoctlSetId (Context, Context->AudioId); if (Result == 0) Result = AudioIoctlSetAvSync (Context, Context->AudioState.AV_sync_state); if (Result == 0) Result = AudioIoctlChannelSelect (Context, Context->AudioState.channel_select); /* If we are connected to a demux we will want to use the VIDEO write lock of the demux device (which could be us). */ if ((Result == 0) && (Context->AudioState.stream_source == AUDIO_SOURCE_DEMUX)) Context->ActiveAudioWriteLock = &(Context->DemuxContext->VideoWriteLock); } } else { /* Play is used implicitly to exit slow motion and fast forward states so set speed to times 1 if audio is playing or has been paused */ Result = AudioIoctlSetSpeed (Context, DVB_SPEED_NORMAL_PLAY); } if (Result == 0) { StreamEnable (Context->AudioStream, true); Context->AudioState.play_state = AUDIO_PLAYING; } DVB_DEBUG("State = %d\n", Context->AudioState.play_state); return Result; }
/*static*/ int __init StmLoadModule(void) { int Result; int i; short int AdapterNumbers[] = { -1 }; DvbContext = kzalloc(sizeof(struct DvbContext_s), GFP_KERNEL); if (DvbContext == NULL) { DVB_ERROR("Unable to allocate device memory\n"); return -ENOMEM; } #ifdef __TDT__ memset(DvbContext, 0, sizeof * DvbContext); #endif #ifdef __TDT__ if (swts) printk("swts ->routing streams from dvr0 to tsm to pti to player\n"); else printk("no swts ->routing streams from dvr0 direct to the player\n"); #endif #if DVB_API_VERSION < 5 Result = dvb_register_adapter(&DvbContext->DvbAdapter, MODULE_NAME, THIS_MODULE, NULL); #else Result = dvb_register_adapter(&DvbContext->DvbAdapter, MODULE_NAME, THIS_MODULE, NULL, AdapterNumbers); #endif if (Result < 0) { DVB_ERROR("Failed to register adapter (%d)\n", Result); kfree(DvbContext); DvbContext = NULL; return -ENOMEM; } mutex_init(&(DvbContext->Lock)); mutex_lock(&(DvbContext->Lock)); /*{{{ Register devices*/ for (i = 0; i < DVB_MAX_DEVICES_PER_ADAPTER; i++) { struct DeviceContext_s* DeviceContext = &DvbContext->DeviceContext[i]; struct dvb_demux* DvbDemux = &DeviceContext->DvbDemux; struct dmxdev* DmxDevice = &DeviceContext->DmxDevice; struct dvb_device* DvrDevice; #ifdef __TDT__ //sylvester: wenn der stream vom user kommt soll WriteToDecoder nix //tun, da das ja hier schon passiert. keine ahnung wie man das ansonsten //verhindern soll;-) DeviceContext->dvr_write = 0; #endif DeviceContext->DvbContext = DvbContext; #if defined (USE_KERNEL_DEMUX) memset(DvbDemux, 0, sizeof(struct dvb_demux)); #ifdef __TDT__ DvbDemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING | DMX_TS_DESCRAMBLING; /* currently only dummy to avoid EINVAL error. Later we need it for second frontend ?! */ DvbDemux->dmx.set_source = SetSource; #else DvbDemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; #endif DvbDemux->priv = DeviceContext; DvbDemux->filternum = 32; DvbDemux->feednum = 32; DvbDemux->start_feed = StartFeed; DvbDemux->stop_feed = StopFeed; #ifdef __TDT__ DvbDemux->write_to_decoder = WriteToDecoder; #else DvbDemux->write_to_decoder = NULL; #endif Result = dvb_dmx_init(DvbDemux); if (Result < 0) { DVB_ERROR("dvb_dmx_init failed (errno = %d)\n", Result); return Result; } memset(DmxDevice, 0, sizeof(struct dmxdev)); DmxDevice->filternum = DvbDemux->filternum; DmxDevice->demux = &DvbDemux->dmx; DmxDevice->capabilities = 0; Result = dvb_dmxdev_init(DmxDevice, &DvbContext->DvbAdapter); if (Result < 0) { DVB_ERROR("dvb_dmxdev_init failed (errno = %d)\n", Result); dvb_dmx_release(DvbDemux); return Result; } DvrDevice = DvrInit(DmxDevice->dvr_dvbdev->fops); #ifdef __TDT__ printk("%d: DeviceContext %p, DvbDemux %p, DmxDevice %p\n", i, DeviceContext, DvbDemux, DmxDevice); #endif /* Unregister the built-in dvr device and replace it with our own version */ dvb_unregister_device(DmxDevice->dvr_dvbdev); dvb_register_device(&DvbContext->DvbAdapter, &DmxDevice->dvr_dvbdev, DvrDevice, DmxDevice, DVB_DEVICE_DVR); DeviceContext->MemoryFrontend.source = DMX_MEMORY_FE; Result = DvbDemux->dmx.add_frontend(&DvbDemux->dmx, &DeviceContext->MemoryFrontend); if (Result < 0) { DVB_ERROR("add_frontend failed (errno = %d)\n", Result); dvb_dmxdev_release(DmxDevice); dvb_dmx_release(DvbDemux); return Result; } #else dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->DemuxDevice, DemuxInit(DeviceContext), DeviceContext, DVB_DEVICE_DEMUX); dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->DvrDevice, DvrInit(DeviceContext), DeviceContext, DVB_DEVICE_DVR); #endif dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->AudioDevice, AudioInit(DeviceContext), DeviceContext, DVB_DEVICE_AUDIO); #ifdef __TDT__ /* register the CA device (e.g. CIMAX) */ if (i < 3) #ifndef VIP2_V1 dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->CaDevice, CaInit(DeviceContext), DeviceContext, DVB_DEVICE_CA); #endif #else dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->CaDevice, CaInit(DeviceContext), DeviceContext, DVB_DEVICE_CA); #endif dvb_register_device(&DvbContext->DvbAdapter, &DeviceContext->VideoDevice, VideoInit(DeviceContext), DeviceContext, DVB_DEVICE_VIDEO); DeviceContext->Id = i; DeviceContext->numRunningFeeds = 0; DeviceContext->DemuxContext = DeviceContext; /* wire directly to own demux by default */ DeviceContext->SyncContext = DeviceContext; /* we are our own sync group by default */ DeviceContext->Playback = NULL; DeviceContext->StreamType = STREAM_TYPE_TRANSPORT; DeviceContext->DvbContext = DvbContext; DeviceContext->DemuxStream = NULL; DeviceContext->VideoStream = NULL; DeviceContext->AudioStream = NULL; DeviceContext->PlaySpeed = DVB_SPEED_NORMAL_PLAY; DeviceContext->dvr_in = kmalloc(65536, GFP_KERNEL); // 128Kbytes is quite a lot per device. DeviceContext->dvr_out = kmalloc(65536, GFP_KERNEL); // However allocating on each write is expensive. DeviceContext->EncryptionOn = 0; #ifdef __TDT__ DeviceContext->VideoPlaySpeed = DVB_SPEED_NORMAL_PLAY; DeviceContext->provideToDecoder = 0; DeviceContext->feedPesType = 0; mutex_init(&DeviceContext->injectMutex); if (i < 4) { ptiInit(DeviceContext); } if (i < 1) { init_e2_proc(DeviceContext); } #endif } mutex_unlock(&(DvbContext->Lock)); DvbBackendInit(); #ifndef __TDT__ #if defined (CONFIG_CPU_SUBTYPE_STX7105) // || defined (CONFIG_CPU_SUBTYPE_STX7200) cap_init(); #endif #endif linuxdvb_v4l2_init(); DVB_DEBUG("STM stream device loaded\n"); return 0; }
static int AudioIoctlSetBypassMode (struct DeviceContext_s* Context, unsigned int Mode) #endif { #ifdef __TDT__ int vLoop; int number = 0; struct snd_kcontrol *single_control = NULL; struct snd_kcontrol ** kcontrol = pseudoGetControls(&number); //DVB_DEBUG("(not implemented)\n"); //mpeg2=4, ac3=6 //e2 : 1=mpegm 0=ac3, 2=dts, 8=aac, 9=aache, 6=lpcm //libdreamdvd : 5=dts 6=lpcm DVB_DEBUG("Set BypassMode to %d\n", Mode); if (Mode == 0) Context->AudioEncoding = (audio_encoding_t) AUDIO_ENCODING_AC3; else if (Mode == 5 || Mode == 2) Context->AudioEncoding = (audio_encoding_t) AUDIO_ENCODING_DTS; else if (Mode == 6) Context->AudioEncoding = (audio_encoding_t) AUDIO_ENCODING_LPCM; else if (Mode == 8) Context->AudioEncoding = (audio_encoding_t) AUDIO_ENCODING_AAC; else Context->AudioEncoding = (audio_encoding_t) AUDIO_ENCODING_MPEG2; //before we jump to any conclusions, does the user really want passtrough, its possible that he wants downmix! //ask e2_proc_audio what the user wants for (vLoop = 0; vLoop < number; vLoop++) { if (kcontrol[vLoop]->private_value == PSEUDO_ADDR(spdif_bypass)) { single_control = kcontrol[vLoop]; printk("Find spdif_bypass control at %p\n", single_control); break; } } if ((kcontrol != NULL) && (single_control != NULL)) { struct snd_ctl_elem_value ucontrol; ucontrol.value.integer.value[0] = e2_proc_audio_getPassthrough(); snd_pseudo_switch_put(single_control, &ucontrol); } else { printk("Pseudo Mixer does not deliver controls\n"); } #ifdef use_hdmi_bypass /* Dagobert; set hdmi bypass, maybe we need another prco for this? */ for (vLoop = 0; vLoop < number; vLoop++) { if (kcontrol[vLoop]->private_value == PSEUDO_ADDR(hdmi_bypass)) { single_control = kcontrol[vLoop]; printk("Find hdmi_bypass control at %p\n", single_control); break; } } if ((kcontrol != NULL) && (single_control != NULL)) { struct snd_ctl_elem_value ucontrol; ucontrol.value.integer.value[0] = e2_proc_audio_getPassthrough(); snd_pseudo_switch_put(single_control, &ucontrol); } else { printk("Pseudo Mixer does not deliver controls\n"); } #endif return 0; #else DVB_DEBUG("(not implemented)\n"); return -EPERM; #endif }
static ssize_t DvrWrite (struct file *File, const char __user* Buffer, size_t Count, loff_t* ppos) { struct dvb_device* DvbDevice = (struct dvb_device*)File->private_data; struct dmxdev* DmxDevice = (struct dmxdev*)DvbDevice->priv; struct dvb_demux* DvbDemux = (struct dvb_demux*)DmxDevice->demux->priv; struct DeviceContext_s* Context = (struct DeviceContext_s*)DvbDemux->priv; int Result = 0; #ifdef __TDT__ // attach to the video stream context struct DeviceContext_s* Context0 = &Context->DvbContext->DeviceContext[0]; #endif if (!DmxDevice->demux->write) return -EOPNOTSUPP; if ((File->f_flags & O_ACCMODE) != O_WRONLY) return -EINVAL; #ifdef __TDT__ while(1) { // Check whether a video stream is available and in FREEZED state. // If the video stream is freezed and the number of buffers with // decoded video frames exceeds a limit then sleep until the video // stream is playing or the write operation is cancelled. // It solves the issue with the first timeshift start after reboot. // It also allows e2 to interrupt the video stream while it is // paused (until now e2 kept sending SIGUSR1 to the file push thread). if((Context0->VideoStream != NULL) && (Context0->VideoState.play_state == VIDEO_FREEZED)) { int NumberOfBuffers = 0; int BuffersInUse = 0; DvbStreamGetDecodeBufferPoolStatus(Context0->VideoStream, &NumberOfBuffers,&BuffersInUse); if(BuffersInUse > 5) { // 40 milliseconds corresponds to one full frame if(msleep_interruptible(40) != 0) { DVB_DEBUG("interrupted\n"); return 0; } } else { break; } } else break; } #endif if (mutex_lock_interruptible (&DmxDevice->mutex)) return -ERESTARTSYS; #if 0 // We should enable this for security reasons, just want to check the impact because it can be performed inline. if (!access_ok(VERIFY_READ, Buffer, Count)) return -EINVAL; #endif #ifdef __TDT__ //sylvester: wenn der stream vom user kommt soll WriteToDecoder nix //tun, da das ja hier schon passiert. keine ahnung wie man das ansonsten //verhindern soll;-) Context->dvr_write = 1; #endif /* * Assume that we have a blueray packet if content size is divisible by 192 but not by 188 * If ordinary ts call demux write function on whole lot. If bdts give data to write function * 188 bytes at a time. */ if ((((Count % TRANSPORT_PACKET_SIZE) == 0) || ((Count % BLUERAY_PACKET_SIZE) != 0)) && !Context->EncryptionOn) { #ifdef __TDT__ if (swts) { /* inject data through tsm */ stm_tsm_inject_user_data(Buffer, Count); } else demultiplexDvbPackets (DvbDemux, Buffer, Count/188); mutex_unlock (&DmxDevice->mutex); //printk("Context %p, DvbDemux %p, DmxDevice %p\n", // Context, DvbDemux, DmxDevice); //Dagobert: dvbtest does not care the return value but e2 does. //StreamInject seems to return zero if it has injected all //(must be investigate for further versions and maybe for this). if (Result == 0) Result = Count; #else // Nicks modified version of chris's patch to reduce the injected size to chunks of a suitable size, and corectly accumulate the result as in blu-ray example below size_t Transfer; size_t RemainingSize = Count; const char __user* BufferPointer = Buffer; while( RemainingSize != 0 ) { Transfer = min( RemainingSize, (0x10000 - (0x10000 % TRANSPORT_PACKET_SIZE)) ); // limit to whole number of packets less than 64kb Result += DmxDevice->demux->write (DmxDevice->demux, BufferPointer, Transfer); RemainingSize -= Transfer; BufferPointer += Transfer; } mutex_unlock (&DmxDevice->mutex); if (Context->DemuxStream) { mutex_lock (&(Context->VideoWriteLock)); Result = DvbStreamInject (Context->DemuxStream, Buffer, Count); mutex_unlock (&(Context->VideoWriteLock)); } #endif return Result; } else if ( (Count % (192*32)) || (!Context->EncryptionOn)) { int n; for (n=0;n<Count;n+=192) Result += DmxDevice->demux->write (DmxDevice->demux, &Buffer[n+4], TRANSPORT_PACKET_SIZE) + 4; mutex_unlock (&DmxDevice->mutex); if (Context->DemuxStream) { mutex_lock (&(Context->VideoWriteLock)); Result = DvbStreamInject (Context->DemuxStream, Buffer, Count); mutex_unlock (&(Context->VideoWriteLock)); } return Result; } else { int n; unsigned long ptr = (unsigned long)stm_v4l2_findbuffer((unsigned long)Buffer,Count,0); // We need to support partial injection, rather nastally unfortunatley unsigned char *out = Context->dvr_out; unsigned int Size = Count; int StartOffset = 0; if (ptr && (ptr & ~31)) { //tkdma_bluray_decrypt_data(&Context->dvr_out[0],(void*)ptr,Count / (32*192),0); // Need to do an interruptibility test } else { copy_from_user(Context->dvr_in,&Buffer[0],Count); //copy_from_user(&Context->dvr_out[16],Buffer,16); //tkdma_bluray_decrypt_data(&Context->dvr_out[0],Context->dvr_in,Count / (32*192),0); //Need to do an interruptibility test } if (Context->StartOffset>0 && Context->StartOffset < Count) { out += Context->StartOffset; Size -= Context->StartOffset; StartOffset = Context->StartOffset; Context->StartOffset = -1; } if (Context->EndOffset>0 && Context->EndOffset < Count && Context->EndOffset > StartOffset) { Size -= Context->EndOffset - StartOffset; Context->EndOffset = -1; } #if 1 for (n=0;n<Size;n+=192) Result += DmxDevice->demux->write (DmxDevice->demux, &out[n+4], TRANSPORT_PACKET_SIZE) + 4; #endif mutex_unlock (&DmxDevice->mutex); if (Context->DemuxStream) { mutex_lock (&(Context->VideoWriteLock)); Result = DvbStreamInject (Context->DemuxStream, &out[0], Size); mutex_unlock (&(Context->VideoWriteLock)); } return Result; } }
int StartFeed (struct dvb_demux_feed* Feed) { struct dvb_demux* DvbDemux = Feed->demux; struct dmxdev_filter* Filter = (struct dmxdev_filter*)Feed->feed.ts.priv; struct dmx_pes_filter_params* Params = &Filter->params.pes; struct DeviceContext_s* Context = (struct DeviceContext_s*)DvbDemux->priv; struct DvbContext_s* DvbContext = Context->DvbContext; int Result = 0; int i; unsigned int Video = false; unsigned int Audio = false; #ifdef __TDT__ struct DeviceContext_s *AvContext = NULL; #endif DVB_DEBUG ("(demux%d)\n", Context->Id); /* either numRunningFeeds == 0 and reset_tsm == 1 or reset_tsm > 1 */ #ifdef __TDT__ // fix recoding freezer on tuner0 and demux1/2 or tuner1 and demux0/2 or tuner2 and demux0/1 int tsm_reset = 1; for (i = 0; i < DVB_MAX_DEVICES_PER_ADAPTER; i++) { struct DeviceContext_s* DeviceContext = &DvbContext->DeviceContext[i]; if(DeviceContext->numRunningFeeds != 0) tsm_reset = 0; } if (tsm_reset && reset_tsm) { printk(KERN_WARNING "reset_tsm: %d numRunningFeeds: %d => calling stm_tsm_init(1)\n", reset_tsm, Context->numRunningFeeds); stm_tsm_init(1); } #else if (Context->numRunningFeeds == 0 && reset_tsm) { printk(KERN_WARNING "reset_tsm: %d numRunningFeeds: %d => calling stm_tsm_init(1)\n", reset_tsm, Context->numRunningFeeds); stm_tsm_init(1); } #endif #if defined(ADB_BOX)//tutaj if (glowica == SINGLE) { if ((Context->pPtiSession->source==DMX_SOURCE_FRONT1)&&(StartFeed_!=NULL)) StartFeed_(Feed); } else if (glowica == TWIN) { if ((Context->pPtiSession->source==DMX_SOURCE_FRONT2)&&(StartFeed_!=NULL)) StartFeed_(Feed); } #endif #ifdef __TDT__ #ifdef no_subtitles if ((Feed->type == DMX_TYPE_TS) && (Feed->pes_type > DMX_TS_PES_OTHER)) { DVB_DEBUG ("pes_type %d > %d (OTHER)>\n", Feed->pes_type, DMX_TS_PES_OTHER); return -EINVAL; } #endif DVB_DEBUG("t = %d, pt = %d, pid = %d\n", Feed->type, Feed->pes_type, Feed->pid); #endif switch (Feed->type) { case DMX_TYPE_TS: if (Feed->pes_type > DMX_TS_PES_OTHER) return -EINVAL; for (i = 0; i < DVB_MAX_DEVICES_PER_ADAPTER; i++) { if (Feed->pes_type == AudioId[i]) { Audio = true; break; } if (Feed->pes_type == VideoId[i]) { Video = true; break; } } #ifdef __TDT__ AvContext = &Context->DvbContext->DeviceContext[i]; //fix freeze if record starts in background //AvContext->DemuxContext = Context; //videotext & subtitles (other) if ((Feed->pes_type == DMX_TS_PES_TELETEXT) || (Feed->pes_type == DMX_TS_PES_OTHER)) { mutex_lock (&(DvbContext->Lock)); Context->numRunningFeeds++; //printk("%s:%d numRunningFeeds: %d\n", __func__,__LINE__,Context->numRunningFeeds); stpti_start_feed (Feed, Context); mutex_unlock (&(DvbContext->Lock)); break; } #endif if (!Audio && !Video) { #ifdef __TDT__ DVB_DEBUG ("pes_type = %d\n<\n", Feed->pes_type); #endif /*mutex_unlock (&(DvbContext->Lock)); This doesn't look right we haven't taken it yet*/ return 0; } mutex_lock (&(DvbContext->Lock)); #ifndef __TDT__ if ((Video && !Context->VideoOpenWrite) || (Audio && !Context->AudioOpenWrite)) { mutex_unlock (&(DvbContext->Lock)); return -EBADF; } #endif if ((Context->Playback == NULL) && (Context->SyncContext->Playback == NULL)) { Result = DvbPlaybackCreate (&Context->Playback); if (Result < 0) { mutex_unlock (&(DvbContext->Lock)); return Result; } Context->SyncContext->Playback = Context->Playback; if (Context->PlaySpeed != DVB_SPEED_NORMAL_PLAY) { Result = VideoIoctlSetSpeed (Context, Context->PlaySpeed); if (Result < 0) #ifdef __TDT__ { mutex_unlock (&(DvbContext->Lock)); return Result; } #else return Result; #endif } #ifdef __TDT__ if ((Context->VideoPlayInterval.start != DVB_TIME_NOT_BOUNDED) || (Context->VideoPlayInterval.end != DVB_TIME_NOT_BOUNDED)) { Result = VideoIoctlSetPlayInterval (Context, &Context->AudioPlayInterval); if (Result < 0) { mutex_unlock (&(DvbContext->Lock)); return Result; } } #endif } else if (Context->Playback == NULL) Context->Playback = Context->SyncContext->Playback; else if (Context->SyncContext->Playback == NULL) Context->SyncContext->Playback = Context->Playback; else if (Context->Playback != Context->SyncContext->Playback) DVB_ERROR ("Context playback not equal to sync context playback\n"); if (Context->DemuxStream == NULL) { Result = DvbPlaybackAddDemux (Context->Playback, Context->DemuxContext->Id, &Context->DemuxStream); if (Result < 0) { mutex_unlock (&(DvbContext->Lock)); return Result; } } #ifdef __TDT__ if (Video) { Context->numRunningFeeds++; //printk("%s:%d numRunningFeeds: %d\n", __func__,__LINE__,Context->numRunningFeeds); stpti_start_feed (Feed, Context); if(Feed->ts_type & TS_DECODER) VideoIoctlSetId (AvContext, Feed->pid); } else if (Audio) { Context->numRunningFeeds++; //printk("%s:%d numRunningFeeds: %d\n", __func__,__LINE__,Context->numRunningFeeds); stpti_start_feed (Feed, Context); if(Feed->ts_type & TS_DECODER) AudioIoctlSetId (AvContext, Feed->pid); } #else if (Video) { struct DeviceContext_s* VideoContext = &Context->DvbContext->DeviceContext[i]; VideoContext->DemuxContext = Context; VideoIoctlSetId (VideoContext, Feed->pid | (Params->flags & DMX_FILTER_BY_PRIORITY_MASK)); VideoIoctlPlay (VideoContext); if ((Context->VideoPlayInterval.start != DVB_TIME_NOT_BOUNDED) || (Context->VideoPlayInterval.end != DVB_TIME_NOT_BOUNDED)) VideoIoctlSetPlayInterval (Context, &Context->AudioPlayInterval); } else { struct DeviceContext_s* AudioContext = &Context->DvbContext->DeviceContext[i]; AudioContext->DemuxContext = Context; AudioIoctlSetId (AudioContext, Feed->pid | (Params->flags & DMX_FILTER_BY_PRIORITY_MASK)); AudioIoctlPlay (AudioContext); if ((Context->AudioPlayInterval.start != DVB_TIME_NOT_BOUNDED) || (Context->AudioPlayInterval.end != DVB_TIME_NOT_BOUNDED)) AudioIoctlSetPlayInterval (Context, &Context->AudioPlayInterval); } #endif mutex_unlock (&(DvbContext->Lock)); break; case DMX_TYPE_SEC: #ifdef __TDT__ //DVB_DEBUG ("feed type = SEC\n"); mutex_lock (&(DvbContext->Lock)); Context->numRunningFeeds++; //printk("%s:%d numRunningFeeds: %d\n", __func__,__LINE__,Context->numRunningFeeds); stpti_start_feed (Feed, Context); mutex_unlock (&(DvbContext->Lock)); #endif break; default: #ifdef __TDT DVB_DEBUG ("< (type = %d unknown\n", Feed->type); #endif return -EINVAL; } return 0; }
static int DvrRelease (struct inode* Inode, struct file* File) { struct dvb_device* DvbDevice = (struct dvb_device*)File->private_data; struct dmxdev* DmxDevice = (struct dmxdev*)DvbDevice->priv; struct dvb_demux* DvbDemux = (struct dvb_demux*)DmxDevice->demux->priv; struct DeviceContext_s* Context = (struct DeviceContext_s*)DvbDemux->priv; int Result = 0; #ifdef __TDT__ DVB_DEBUG("%p, %x\n", DvbDemux, File->f_flags & O_ACCMODE); //Dagobert: This is also responsible for the crash when ending timeshift. //Not sure if this is a good idea, must be tested #if 0 //dagobert: the dvr device can be opened for //recording. so for this case it is a bad idea //to destroy the live stream playback ;-) if (Context->dvr_write == 1) { if (Context->DemuxStream != NULL) { Result = PlaybackRemoveDemux (Context->Playback, Context->DemuxStream); Context->DemuxStream = NULL; if (Context != Context->DemuxContext) Context->DemuxContext->DemuxStream = NULL; } /* Check to see if audio and video have also finished so we can release the playback */ if ((Context->AudioStream == NULL) && (Context->VideoStream == NULL) && (Context->Playback != NULL)) { /* Try and delete playback then set our demux to Null if succesful or not. If we fail someone else is still using it but we are done. */ if (PlaybackDelete (Context->Playback) == 0) DVB_TRACE("Playback deleted successfully\n"); Context->Playback = NULL; Context->StreamType = STREAM_TYPE_TRANSPORT; Context->PlaySpeed = DVB_SPEED_NORMAL_PLAY; Context->PlayInterval.start = DVB_TIME_NOT_BOUNDED; Context->PlayInterval.end = DVB_TIME_NOT_BOUNDED; Context->SyncContext = Context; } Context->StreamType = STREAM_TYPE_TRANSPORT; } #endif Result = OriginalDvrFops.release (Inode, File); //sylvester: wenn der stream vom user kommt soll WriteToDecoder nix //tun, da das ja hier schon passiert. keine ahnung wie man das ansonsten //verhindern soll;-) Context->dvr_write = 0; return Result; #else DVB_DEBUG("\n"); if (Context->DemuxStream != NULL) { Result = DvbPlaybackRemoveDemux (Context->Playback, Context->DemuxStream); Context->DemuxStream = NULL; /* if (Context != Context->DemuxContext) Context->DemuxContext->DemuxStream = NULL; */ } /* Check to see if audio and video have also finished so we can release the playback */ if ((Context->AudioStream == NULL) && (Context->VideoStream == NULL) && (Context->Playback != NULL)) { /* Check to see if our playback has already been deleted by the demux context */ if (Context->DemuxContext->Playback != NULL) { /* Try and delete playback then set our demux to Null if succesful or not. If we fail someone else is still using it but we are done. */ if (DvbPlaybackDelete (Context->Playback) == 0) DVB_TRACE("Playback deleted successfully\n"); } Context->Playback = NULL; Context->StreamType = STREAM_TYPE_TRANSPORT; Context->PlaySpeed = DVB_SPEED_NORMAL_PLAY; Context->AudioPlayInterval.start = DVB_TIME_NOT_BOUNDED; Context->AudioPlayInterval.end = DVB_TIME_NOT_BOUNDED; Context->VideoPlayInterval.start = DVB_TIME_NOT_BOUNDED; Context->VideoPlayInterval.end = DVB_TIME_NOT_BOUNDED; Context->SyncContext = Context; } Context->StreamType = STREAM_TYPE_TRANSPORT; return OriginalDvrFops.release (Inode, File); #endif }