[gst-devel] A directsound sink made with gob

John Janecek nopa90 at gmail.com
Wed Nov 30 03:25:04 CET 2005


KMerage may vary just made it today :)
change paths to suit ur needs

works with version 0.95 compiled with mingw
(too poor to buy MS crap, plus MS crap blows)

not a directsound expert
used this dudes
http://www.burnttoys.co.uk/DXASCPP.html to load dll
(i like that no need to link against MS libs)
And pored over DirectSound docs

Do not really need to install SDK just need headers

---------scons file--------------
import sys
env = Environment()
env.ParseConfig('pkg-config --cflags --libs gstreamer-0.9')
if sys.platform == "win32" :
	env.Command("ds-sink.cc",'ds_sink.gob',"E:/GTK/bin/gob2 --for-cpp $SOURCE")
	env.Append(CPPPATH=["E:/msys/1.0/local/include","E:/GTK/include/glib-2.0","../../../DirXSDK/Include"])
	env.Append(LIBS=['gstaudio-0.9','gstbase-0.9','gstreamer-0.9',"gobject-2.0",'glib-2.0'])
	env.Append(CCFLAGS = '-g')
sink = env.SharedLibrary(target ="direct-sound",
		source = ["ds-sink.cc"],
		SHLIBPREFIX='')
if sys.platform == "win32" :
	env.Install("E:/gplugs",sink)
	env.Alias('install','E:/gplugs')

-------------ds_sink.gob file
--------------------------------------------------------------------
%alltop{
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
#include <windows.h>
#include <dsound.h>
#include <mmsystem.h>
#include "ds_header.h"
//#include <stdio.h>
%}

%{
//gdb "gst-launch-0.9 audiotestsrc ! audioconvert ! dssink"
#include <stdio.h>
#define VERSION "0.01"
#define PACKAGE "dssink"
#define D_OUT(x) g_warning(x)
//#define BREAKPOINT __asm__("int3");
#define BREAKPOINT "";

static GstStaticPadTemplate dssink_sink_template_factory =
	GST_STATIC_PAD_TEMPLATE ("sink",
	GST_PAD_SINK,
	GST_PAD_ALWAYS,
	GST_STATIC_CAPS ("audio/x-raw-int, "
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
		"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
#else
		"endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
#endif
		"signed = (boolean) TRUE, "
		"width = (int) 16, "
		"depth = (int) 16, "
		"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
		"audio/x-raw-int, "
		"signed = (boolean) { TRUE, FALSE }, "
		"width = (int) 8, "
		"depth = (int) 8, "
		"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
	);
	
%}

class Ds:Sink from Gst:Audio:Sink {
	protected HMODULE hLibDSound;
	protected FNDSCREATE pfnDSC;
	protected LPDIRECTSOUND lpDS;
	protected DSBUFFERDESC dsBufferDesc;
	protected LPDIRECTSOUNDBUFFER lpDSB1st;
	protected LPDIRECTSOUNDBUFFER lpDSB2nd;
	protected WAVEFORMATEX wfxWaveFormat;
	protected char *device_name = {g_strdup("None")}
				destroywith g_free;
	protected gboolean playing;
	protected gint bytes_per_sample;
	
	protected gboolean first_write;
	protected DWORD write_pos;
	protected gint buffer_size; //size of the buffer in bytes
	
	property STRING device_name
		(nick = "DeviceName",
		blurb = "Name of Device",
		default_value = "None",
		/* Export get/set functions for this property */
		export,
		link);
		
	init(self) {
		D_OUT("dsink init");
		self->hLibDSound = NULL;
		self->playing = FALSE;
		}
		
	override (G:Object) void
	finalize(GObject* obj) {
		PARENT_HANDLER(obj);
		}
		
	override (Gst:BaseSink) GstCaps*
	get_caps (GstBaseSink *sink) {
		D_OUT("dsink get_caps");
		/*
		GstStructure *structure;
		GstCaps *caps;
		gint w,h;
		Self *self = SELF (sink);
		//g_warning ("buffersink get_caps");
		caps = gst_caps_copy(gst_pad_get_pad_template_caps (sink->sinkpad));
		return caps;
		*/
		return NULL;
		}
	
	override (Gst:Audio:Sink) gboolean
	open(GstAudioSink *sink) {
		BREAKPOINT
		D_OUT("dsink open");
		Self *self=SELF(sink);
		if(!(self->hLibDSound = (HMODULE) LoadLibrary("dsound.dll"))) {
			D_OUT("dsound.dll failed to load");
			return FALSE;
			}
		if(!(self->pfnDSC =
(FNDSCREATE)GetProcAddress(self->hLibDSound,"DirectSoundCreate8"))) {
			return FALSE;
			}
		if (FAILED(self->pfnDSC(NULL,&(self->lpDS),NULL))) {
			return FALSE;
			}
		//GetDesktopWindow()
		if (DS_OK != IDirectSound_SetCooperativeLevel(self->lpDS,GetDesktopWindow(),DSSCL_PRIORITY))
{
			return FALSE;
			}
		//Creating Primary Buffer
		ZeroMemory(&(self->dsBufferDesc), sizeof(self->dsBufferDesc));
		self->dsBufferDesc.dwSize = sizeof(self->dsBufferDesc);
		self->dsBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
		if (DS_OK != IDirectSound_CreateSoundBuffer(self->lpDS,&self->dsBufferDesc,&self->lpDSB1st,NULL))
{
			return FALSE;
			}
		return TRUE;
		}
		
	override (Gst:Audio:Sink) gboolean
	prepare(GstAudioSink *sink, GstRingBufferSpec *spec) {
		BREAKPOINT
		Self *self=SELF(sink);
		self->playing = FALSE;
		self->bytes_per_sample = spec->bytes_per_sample;
		//Creating Secondary Buffer
		//g_warning("dssink prepare width %d,depth %d,rate %d,channels %d,
bytes per sample %d",
		//					spec->width,spec->depth,spec->rate,spec->channels,spec->bytes_per_sample);
		self->wfxWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
		self->wfxWaveFormat.nChannels = spec->channels;
		self->wfxWaveFormat.nSamplesPerSec = spec->rate;
		self->wfxWaveFormat.nAvgBytesPerSec = spec->bytes_per_sample*spec->rate;
		self->wfxWaveFormat.nBlockAlign = (spec->channels*spec->width)/8;
		self->wfxWaveFormat.wBitsPerSample = spec->width;
		self->wfxWaveFormat.cbSize = 0;
		
		self->buffer_size = spec->bytes_per_sample*spec->rate;
		
		self->dsBufferDesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_GLOBALFOCUS;	// 0x1c000
		self->dsBufferDesc.dwBufferBytes = self->buffer_size;
		self->dsBufferDesc.lpwfxFormat = &self->wfxWaveFormat;
		
		HRESULT res = IDirectSound_CreateSoundBuffer(self->lpDS,
&self->dsBufferDesc, &(self->lpDSB2nd), NULL);
		if (res!=DS_OK) {
			g_warning("failed to create secondary sound buffer %x",res);
			return FALSE;
			}
			
		LPDWORD lp1;
		DWORD l1;
		IDirectSoundBuffer_Lock(self->lpDSB2nd, 0, 0, (LPVOID *)(&lp1), &l1,
NULL, NULL,DSBLOCK_ENTIREBUFFER);
		ZeroMemory(lp1,l1); //not correct for signed samples
		IDirectSoundBuffer_Unlock(self->lpDSB2nd,(LPVOID)(lp1),l1,NULL,NULL);
		
		if (DS_OK != IDirectSoundBuffer_Play(self->lpDSB2nd,0,0,DSBPLAY_LOOPING)) {
			g_warning("failed to set sound buffer to play");
			return FALSE;
			}
		self->first_write = TRUE;
		self->playing = TRUE;
		return TRUE;
		}
		
	override (Gst:Audio:Sink) gboolean
	unprepare(GstAudioSink *sink) {
		Self *self=SELF(sink);
		if (self->playing) IDirectSoundBuffer_Stop(self->lpDSB2nd);
		if (self->lpDSB2nd) IDirectSoundBuffer_Release(self->lpDSB2nd);
		self->playing = FALSE;
		return TRUE;
		}
		
	override (Gst:Audio:Sink) gboolean
	close(GstAudioSink *sink) {
		Self *self=SELF(sink);
		if (self->lpDSB1st) IDirectSoundBuffer_Release(self->lpDSB1st);
		if (self->lpDS) IDirectSound_Release(self->lpDS);
		if (self->hLibDSound) FreeLibrary(self->hLibDSound);
		return TRUE;
		}
		
	override (Gst:Audio:Sink) guint
	write(GstAudioSink *sink, gpointer data, guint length) {
		//length is the length of the buffer in bytes
		BREAKPOINT
		Self *self=SELF(sink);
		//g_warning("dsink write %d",length);
		
		DWORD PlayOffset,WriteOffset;
		IDirectSoundBuffer_GetCurrentPosition(self->lpDSB2nd,&PlayOffset,&WriteOffset);
		
		if(self->first_write) {
			self->first_write=FALSE;
			self->write_pos = WriteOffset;
			}
		
		
		DWORD delta=0;
		if(self->write_pos<PlayOffset) {
			delta = (self->buffer_size - PlayOffset) + self->write_pos;
			}
		else {
			delta = self->write_pos - PlayOffset;
			}
		if(delta>=(self->buffer_size/2)) return 0;
		
		LPVOID ptr1,ptr2;
		DWORD len1,len2;
		HRESULT R=IDirectSoundBuffer_Lock(self->lpDSB2nd,self->write_pos,length,
					(LPVOID *)(&ptr1),&len1,(LPVOID *)(&ptr2),&len2,0);
		if(R!=DS_OK) {
			D_OUT("unable to lock buffer");
			return 0;
			}
		memcpy(ptr1,data,len1);
		if(len1<length) {
			memcpy(ptr2,(void*)(((char *)data)+len1),len2);
			}
		IDirectSoundBuffer_Unlock(self->lpDSB2nd,(LPVOID)ptr1,len1,(LPVOID)(ptr2),len2);
		self->write_pos+=length;
		if(self->write_pos>=self->buffer_size) {
			self->write_pos-=self->buffer_size;
			}
		return length;
		}
		
	override (Gst:Audio:Sink) guint
	delay(GstAudioSink *sink) {
		Self *self=SELF(sink);
		//D_OUT("ds_sink delay");
		DWORD PlayOffset,WriteOffset;
		IDirectSoundBuffer_GetCurrentPosition(self->lpDSB2nd,&PlayOffset,&WriteOffset);
		//g_warning("dsink delay %d %d",WriteOffset,PlayOffset);
		//g_warning("dsink delay %d",(WriteOffset -
PlayOffset)/self->bytes_per_sample);
		guint delay = 0;
		if(!self->first_write) {
			WriteOffset=self->write_pos;
			}
		if(WriteOffset>=PlayOffset) {
			delay = (WriteOffset - PlayOffset)/self->bytes_per_sample;
			}
		else {
			g_warning("wrap");			
			delay = (self->buffer_size - (PlayOffset -
WriteOffset))/self->bytes_per_sample;
			}
		g_warning("dsink delay %d",delay);
		return delay;
		}
	
	override (Gst:Audio:Sink) void
	reset(GstAudioSink *sink) {
		D_OUT("ds_sink reset");
		}
	
	public void
	base_init (gpointer g_class) {
		D_OUT("ds_sink base_init");
		static GstElementDetails sink_details =
		GST_ELEMENT_DETAILS (
		"DsSink",
		"Sink/Audio",
		"DirectSound sink",
		"John Janecek nopa90 at gmail.com");
		
		GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
		
		gst_element_class_add_pad_template (element_class,
				gst_static_pad_template_get (&dssink_sink_template_factory));
		
		gst_element_class_set_details (element_class, &sink_details);
		}

	public GType
	get_type (void) {
		static GType type = 0;
		//D_OUT("ds_sink get_type");
		if(!type) {
			static const GTypeInfo info = {
				sizeof (SelfClass),
				(GBaseInitFunc) ds_sink_base_init,
				(GBaseFinalizeFunc) NULL,
				(GClassInitFunc) ds_sink_class_init,
				(GClassFinalizeFunc) NULL,
				NULL /* class_data */,
				sizeof (Self),
				0 /* n_preallocs */,
				(GInstanceInitFunc)ds_sink_init,
				NULL
				};
			//type registered should be parent type
			type = g_type_register_static
(GST_TYPE_AUDIO_SINK,"DsSink",&info,(GTypeFlags)0);
			}
		return type;
		}
}

%{
static gboolean
plugin_init (GstPlugin * plugin)
	{
	//BREAKPOINT
	D_OUT("ds_sink plugin_init");
	return gst_element_register (plugin,"dssink", //name here has to match
		GST_RANK_NONE,
		DS_TYPE_SINK);
	}

GST_PLUGIN_DEFINE (
	GST_VERSION_MAJOR,
	GST_VERSION_MINOR,
	"dssink",
	"dssink plugin",
	plugin_init,
	VERSION,
	"LGPL",
	"GStreamer",
	"http://gstreamer.net/"
	)
%}

-------------------ds_header.h file
--------------------------------------------------------------
//required because gob fuks up on the function declaration
typedef HRESULT (WINAPI *FNDSCREATE)(LPCGUID pcGuidDevice,
LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
#define PRIV(x) self->_priv->x
#define _PRIV self->_priv




More information about the gstreamer-devel mailing list