[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