/* * Copyright (C) 2000-2001 the xine project * * This file is part of xine, a unix video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * audio_directx_out.c, direct sound audio output plugin for xine * by Matthew Grooms */ typedef unsigned char boolean; #include #include #include "audio_out.h" #include "xine_internal.h" #if (0) #define LOG 1 #endif #define MAX_CHANNELS 6 #define MAX_BITS 16 #define MAX_SAMPLE_RATE 44100 #define SOUND_BUFFER_DIV 32 #define SOUND_BUFFER_MAX MAX_CHANNELS * MAX_BITS * MAX_SAMPLE_RATE / SOUND_BUFFER_DIV #define DSBUFF_INIT 0 #define DSBUFF_LEFT 1 #define DSBUFF_RIGHT 2 #define AO_DIRECTX_IFACE_VERSION 7 // ----------------------------------------- // // ao_directx driver struct // // ----------------------------------------- typedef struct ao_directx_s { ao_driver_t ao_driver; int capabilities; // directx objects LPDIRECTSOUND dsobj; LPDIRECTSOUNDBUFFER dsbuffer; DSBCAPS dsbcaps; LPDIRECTSOUNDNOTIFY notify; DSBPOSITIONNOTIFY notify_events[ 2 ]; // buffer vars long buffer_size; long buffer_init; int write_status; long write_pos; uint8_t prebuff[ SOUND_BUFFER_MAX ]; uint32_t prebuff_size; // current buffer properties int bits; int rate; int chnn; int frsz; // current mixer settings int mute; int volume; }ao_directx_t; typedef struct { audio_driver_class_t driver_class; config_values_t *config; char *device_name; } audiox_class_t; // ------------------------------------------- // // BEGIN : Direct Sound and win32 handlers // for xine audio output plugins. // // ------------------------------------------- boolean CreateDirectSound( ao_directx_t * ao_directx ); void DestroyDirectSound( ao_directx_t * ao_directx ); boolean CreateSoundBuffer( ao_directx_t * ao_directx ); void DestroySoundBuffer( ao_directx_t * ao_directx ); uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * samples ); // Display formatted error message in // popup message box. void Error( HWND hwnd, LPSTR szfmt, ... ) { char tempbuff[ 256 ]; *tempbuff = 0; wvsprintf( &tempbuff[ strlen( tempbuff ) ], szfmt, ( char * )( &szfmt + 1 ) ); MessageBox( hwnd, tempbuff, "Error", MB_ICONERROR | MB_OK | MB_APPLMODAL | MB_SYSTEMMODAL ); } // Create our direct sound object and // set the cooperative level. boolean CreateDirectSound( ao_directx_t * ao_directx ) { DSCAPS dscaps; HWND hxinewnd; #ifdef LOG printf("audio_directx_out: CreateDirectSound(%08x) Enter\n", (unsigned long)ao_directx); #endif // create direct sound object if( DirectSoundCreate( 0, &ao_directx->dsobj, 0 ) != DS_OK ) { Error( 0, "DirectSoundCreate : Unable to create direct sound object" ); #ifdef LOG printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); #endif return FALSE; } // try to get our current xine window hxinewnd = FindWindow( "xinectrlwindow", "xine" ); if( !hxinewnd ) hxinewnd = GetDesktopWindow(); // set direct sound cooperative level if( IDirectSound_SetCooperativeLevel( ao_directx->dsobj, hxinewnd, DSSCL_EXCLUSIVE ) != DS_OK ) { Error( 0, "IDirectSound_SetCooperativeLevel : could not set direct sound cooperative level" ); #ifdef LOG printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); #endif return FALSE; } // get the direct sound device caps memset( &dscaps, 0, sizeof( dscaps ) ); dscaps.dwSize = sizeof( dscaps ); if( IDirectSound_GetCaps( ao_directx->dsobj, &dscaps ) != DS_OK ) { Error( 0, "IDirectSound_GetCaps : Unable to get direct sound device capabilities" ); #ifdef LOG printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); #endif return FALSE; } #ifdef LOG printf("audio_directx_out: CreateDirectSound() Exit! Returning True\n"); #endif return TRUE; } // Destroy all direct sound allocated // resources. void DestroyDirectSound( ao_directx_t * ao_directx ) { #ifdef LOG printf("audio_directx_out: DestroyDirectSound(%08x) Enter\n", (unsigned long)ao_directx); #endif if( ao_directx->dsobj ) { #ifdef LOG printf("audio_directx_out: IDirectSound_Release()\n"); #endif IDirectSound_Release( ao_directx->dsobj ); ao_directx->dsobj = 0; } #ifdef LOG printf("audio_directx_out: DestroyDirectSound() Exit\n"); #endif } // Used to create directx sound buffer, // notification events, and initialize // buffer to null sample data. boolean CreateSoundBuffer( ao_directx_t * ao_directx ) { DSBUFFERDESC dsbdesc; PCMWAVEFORMAT pcmwf; #ifdef LOG printf("audio_directx_out: CreateSoundBuffer(%08x) Enter\n", (unsigned long)ao_directx); #endif // calculate buffer and frame size ao_directx->frsz = ( ao_directx->bits / 8 ) * ao_directx->chnn; ao_directx->buffer_size = ( ao_directx->frsz * ao_directx->rate ) / SOUND_BUFFER_DIV; // release any existing sound buffer // related resources DestroySoundBuffer( ao_directx ); // create a secondary sound buffer memset( &pcmwf, 0, sizeof( PCMWAVEFORMAT ) ); pcmwf.wBitsPerSample = ( unsigned short ) ao_directx->bits; pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; pcmwf.wf.nChannels = ao_directx->chnn; pcmwf.wf.nSamplesPerSec = ao_directx->rate; pcmwf.wf.nBlockAlign = ao_directx->frsz; pcmwf.wf.nAvgBytesPerSec = ao_directx->rate * ao_directx->frsz; memset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) ); dsbdesc.dwSize = sizeof( DSBUFFERDESC ); dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; dsbdesc.dwBufferBytes = ao_directx->buffer_size; dsbdesc.lpwfxFormat = ( LPWAVEFORMATEX ) &pcmwf; if( IDirectSound_CreateSoundBuffer( ao_directx->dsobj, &dsbdesc, &ao_directx->dsbuffer, 0 ) != DS_OK ) { Error( 0, "IDirectSound_CreateSoundBuffer : Unable to create secondary sound buffer" ); return FALSE; } // get the buffer capabilities memset( &ao_directx->dsbcaps, 0, sizeof( DSBCAPS ) ); ao_directx->dsbcaps.dwSize = sizeof( DSBCAPS ); if( IDirectSound_GetCaps( ao_directx->dsbuffer, &ao_directx->dsbcaps ) != DS_OK ) { Error( 0, "IDirectSound_GetCaps : Unable to get secondary sound buffer capabilities" ); return FALSE; } // create left side notification ( non-signaled ) ao_directx->notify_events[ 0 ].hEventNotify = CreateEvent( NULL, FALSE, FALSE, NULL ); // create right side notification ( signaled ) ao_directx->notify_events[ 1 ].hEventNotify = CreateEvent( NULL, FALSE, FALSE, NULL ); if( !ao_directx->notify_events[ 0 ].hEventNotify || !ao_directx->notify_events[ 1 ].hEventNotify ) { Error( 0, "CreateEvent : Unable to create sound notification events" ); return FALSE; } // get the direct sound notification interface if( IDirectSoundBuffer_QueryInterface( ao_directx->dsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&ao_directx->notify ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_QueryInterface : Unable to get notification interface" ); return FALSE; } // set notification events ao_directx->notify_events[ 0 ].dwOffset = 0; ao_directx->notify_events[ 1 ].dwOffset = ao_directx->buffer_size / 2; if( IDirectSoundNotify_SetNotificationPositions( ao_directx->notify, 2, ao_directx->notify_events ) != DS_OK ) { Error( 0, "IDirectSoundNotify_SetNotificationPositions : Unable to set notification positions" ); return FALSE; } // DEBUG : set sound buffer volume if( IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MAX ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_SetVolume : Unable to set sound buffer volume" ); return FALSE; } // initialize our sound buffer IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); FillSoundBuffer( ao_directx, DSBUFF_INIT, 0 ); return TRUE; #ifdef LOG printf("audio_directx_out: CreateSoundBuffer() Exit\n"); #endif } // Destroy all direct sound buffer allocated // resources. void DestroySoundBuffer( ao_directx_t * ao_directx ) { #ifdef LOG printf("audio_directx_out: DestroySoundBuffer(%08x) Enter\n", (unsigned long)ao_directx); #endif // stop our buffer and zero it out if( ao_directx->dsbuffer ) { IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); IDirectSoundBuffer_Stop( ao_directx->dsbuffer ); FillSoundBuffer( ao_directx, DSBUFF_INIT, 0 ); } // release our notification events if( ao_directx->notify_events[ 0 ].hEventNotify ) { CloseHandle( ao_directx->notify_events[ 0 ].hEventNotify ); ao_directx->notify_events[ 0 ].hEventNotify = 0; } if( ao_directx->notify_events[ 1 ].hEventNotify ) { CloseHandle( ao_directx->notify_events[ 1 ].hEventNotify ); ao_directx->notify_events[ 1 ].hEventNotify = 0; } // release our buffer notification interface if( ao_directx->notify ) { IDirectSoundNotify_Release( ao_directx->notify ); ao_directx->notify = 0; } // release our direct sound buffer if( ao_directx->dsbuffer ) { IDirectSoundBuffer_Release( ao_directx->dsbuffer ); ao_directx->dsbuffer = 0; } #ifdef LOG printf("audio_directx_out: DestroySoundBuffer() Exit\n"); #endif } // Used to fill our looping sound buffer // with data. uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * samples ) { uint8_t * buff_pointer; // pointer inside circular buffer uint32_t buff_length; // bytes locked by pointer uint32_t half_size; // half our sound buffer size uint32_t result; // error result #ifdef LOG if ((void*)samples != (void*)0) printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); else printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); #endif half_size = ao_directx->buffer_size / 2; if( code == DSBUFF_INIT ) { #ifdef LOG printf("audio_directx_out: FillSoundBuffer: DSBUFF_INIT\n"); #endif // set our new status code ao_directx->write_status = DSBUFF_RIGHT; // lock our sound buffer for write access result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, 0, 0, &buff_pointer, &buff_length, 0, 0, DSBLOCK_ENTIREBUFFER ); if( result != DS_OK ) { Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); return 0; } // clear our entire sound buffer memset( buff_pointer, 0, buff_length ); // unlock our sound buffer if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, buff_pointer, buff_length, 0, 0 ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); return 0; } // start the buffer playing if( IDirectSoundBuffer_Play( ao_directx->dsbuffer, 0, 0, DSBPLAY_LOOPING ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_Play : could not play sound buffer" ); return 0 ; } else IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); } else if( code == DSBUFF_LEFT ) { #ifdef LOG printf("audio_directx_out: FillSoundBuffer: DSBUFF_LEFT\n"); #endif // set our new status code ao_directx->write_status = DSBUFF_RIGHT; // lock our sound buffer for write access result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, 0, half_size, &buff_pointer, &buff_length, 0, 0, 0 ); if( result != DS_OK ) { Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); return 0; } // write data to our sound buffer memcpy( buff_pointer, samples, buff_length ); // unlock our sound buffer if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, buff_pointer, buff_length, 0, 0 ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); return 0; } } else if( code == DSBUFF_RIGHT ) { #ifdef LOG printf("audio_directx_out: FillSoundBuffer: DSBUFF_RIGHT\n"); #endif // set our new status code ao_directx->write_status = DSBUFF_LEFT; // lock our sound buffer for write access result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, half_size, half_size, &buff_pointer, &buff_length, 0, 0, 0 ); if( result != DS_OK ) { Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); return 0; } // write data to our sound buffer memcpy( buff_pointer, samples, buff_length ); // unlock our sound buffer if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, buff_pointer, buff_length, 0, 0 ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); return 0; } } #ifdef LOG printf("audio_directx_out: FillSoundBuffer() Exit\n"); #endif return buff_length; } // ----------------------------------------- // // BEGIN : Xine driver audio output plugin // handlers. // // ----------------------------------------- static int ao_directx_control(ao_driver_t *this_gen, int cmd, ...) { ao_directx_t * ao_directx = ( ao_directx_t * ) this_gen; switch (cmd) { case AO_CTRL_PLAY_PAUSE: break; case AO_CTRL_PLAY_RESUME: break; case AO_CTRL_FLUSH_BUFFERS: break; } return 0; } static int ao_directx_open( ao_driver_t * ao_driver, uint32_t bits, uint32_t rate, int mode ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; #ifdef LOG printf("audio_directx_out: ao_directx_open(%08x, %d, %d, %d) Enter\n", (unsigned long)ao_directx, bits, rate, mode); #endif // store input rate and bits ao_directx->bits = bits; ao_directx->rate = rate; // store channel count switch( mode ) { case AO_CAP_MODE_MONO: ao_directx->chnn = 1; printf( "ao_directx : opened in AO_CAP_MODE_MONO mode\n" ); break; case AO_CAP_MODE_STEREO: ao_directx->chnn = 2; printf( "ao_directx : opened in AO_CAP_MODE_STEREO mode\n" ); break; case AO_CAP_MODE_4CHANNEL: ao_directx->chnn = 4; printf( "ao_directx : opened in AO_CAP_MODE_4CHANNEL mode\n" ); break; case AO_CAP_MODE_5CHANNEL: ao_directx->chnn = 5; printf( "ao_directx : opened in AO_CAP_MODE_5CHANNEL mode\n" ); break; case AO_CAP_MODE_5_1CHANNEL: ao_directx->chnn = 6; printf( "ao_directx : opened in AO_CAP_MODE_5_1CHANNEL mode\n" ); break; case AO_CAP_MODE_A52: case AO_CAP_MODE_AC5: return 0; } CreateSoundBuffer( ao_directx ); #ifdef LOG printf("audio_directx_out: ao_directx_open() Exit! Returning ao_directx->rate=%d\n", ao_directx->rate); #endif return ao_directx->rate; } static int ao_directx_num_channels( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; return ao_directx->chnn; } static int ao_directx_bytes_per_frame( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; return ao_directx->frsz; } static int ao_directx_get_gap_tolerance( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; return 5000; } static int ao_directx_delay( ao_driver_t * ao_driver ) { DWORD current_read; DWORD bytes_left; DWORD frames_left; ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; #ifdef LOG printf("audio_directx_out: ao_directx_delay(%08x) Enter\n", (unsigned long)ao_directx); #endif IDirectSoundBuffer_GetCurrentPosition( ao_directx->dsbuffer, ¤t_read, 0 ); if( ao_directx->write_pos > current_read ) bytes_left = ( ao_directx->write_pos - current_read ); else bytes_left = ( ao_directx->write_pos + ao_directx->buffer_size - current_read ); frames_left = ( ao_directx->prebuff_size + bytes_left ) / ao_directx->frsz; #ifdef LOG printf("audio_directx_out: ao_directx_delay() Exit! Returning frames_left=%d\n", frames_left); #endif return frames_left; } static int ao_directx_write( ao_driver_t * ao_driver, int16_t * frame_buffer, uint32_t num_frames ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; uint32_t frame_bytes; // how many bytes to lock uint32_t wrote; // number of bytes written uint32_t half_size; // half our sound buffer size #ifdef LOG printf("audio_directx_out: ao_directx_write(%08x, %08x, %d) Enter\n", (unsigned long)ao_directx, (unsigned long)frame_buffer, num_frames); #endif // zero write counter wrote = 0; // calculate how many bytes in frame_buffer frame_bytes = num_frames * ao_directx->frsz; // calculate half our buffer size half_size = ao_directx->buffer_size / 2; // fill audio prebuff memcpy( ao_directx->prebuff + ao_directx->prebuff_size, frame_buffer, frame_bytes ); ao_directx->prebuff_size = ao_directx->prebuff_size + frame_bytes; // check to see if we have enough in prebuff to // fill half of our sound buffer while( ao_directx->prebuff_size >= half_size ) { // write to our sound buffer if( ao_directx->write_status == DSBUFF_LEFT ) { // wait for our read pointer to reach the right half // of our sound buffer, we only want to write to the // left side WaitForSingleObject( ao_directx->notify_events[ 1 ].hEventNotify, INFINITE ); // fill left half of our buffer wrote = FillSoundBuffer( ao_directx, DSBUFF_LEFT, ao_directx->prebuff ); } else if( ao_directx->write_status == DSBUFF_RIGHT ) { // wait for our read pointer to reach the left half, // of our sound buffer, we only want to write to the // right side WaitForSingleObject( ao_directx->notify_events[ 0 ].hEventNotify, INFINITE ); // fill right half of our buffer wrote = FillSoundBuffer( ao_directx, DSBUFF_RIGHT, ao_directx->prebuff ); } // calc bytes written and store position for next write ao_directx->write_pos = ( ao_directx->write_pos + wrote ) % ao_directx->buffer_size; // copy remaining contents of prebuff and recalc size memcpy( ao_directx->prebuff, ao_directx->prebuff + wrote, ao_directx->prebuff_size - wrote ); ao_directx->prebuff_size = ao_directx->prebuff_size - wrote; } #ifdef LOG printf("audio_directx_out: ao_directx_write() Exit! Returning num_frmaes=%d\n", num_frames); #endif return num_frames; } static void ao_directx_close( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; #ifdef LOG printf("audio_directx_out: ao_directx_close(%08x) Enter\n", (unsigned long)ao_directx); #endif // release any existing sound buffer // related resources DestroySoundBuffer( ao_directx ); #ifdef LOG printf("audio_directx_out: ao_directx_close() Exit!\n"); #endif } static uint32_t ao_directx_get_capabilities( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; return AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL; } static void ao_directx_exit( ao_driver_t * ao_driver ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; #ifdef LOG printf("audio_directx_out: ao_directx_exit(%08x) Enter\n", (unsigned long)ao_directx); #endif // release any existing sound buffer // related resources DestroySoundBuffer( ao_directx ); // release any existing direct sound // related resources DestroyDirectSound( ao_directx ); // free our driver free( ao_directx ); #ifdef LOG printf("audio_directx_out: ao_directx_exit() Exit!\n"); #endif } static int ao_directx_get_property( ao_driver_t * ao_driver, int property ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; return 0; } static int ao_directx_set_property( ao_driver_t * ao_driver, int property, int value ) { ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; #ifdef LOG printf("audio_directx_out: ao_directx_set_property(%08x, %d, %d) Enter\n", (unsigned long)ao_directx, property, value); #endif switch( property ) { case AO_PROP_PCM_VOL: case AO_PROP_MIXER_VOL: #ifdef LOG printf("audio_directx_out: ao_directx_set_property: AO_PROP_PCM_VOL|AO_PROP_MIXER_VOL\n"); #endif ao_directx->volume = value * ( DSBVOLUME_MIN / 100 / 3); if( !ao_directx->mute && ao_directx->dsbuffer ) IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); printf( "ao_directx : volume set to %d - directX volume = %d\n", value, ao_directx->volume); return value; break; case AO_PROP_MUTE_VOL: #ifdef LOG printf("audio_directx_out: ao_directx_set_property: AO_PROP_MUTE_VOL\n"); #endif ao_directx->mute = value; if( !ao_directx->mute && ao_directx->dsbuffer ) IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); if( ao_directx->mute && ao_directx->dsbuffer ) IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); printf( "ao_directx : mute toggled" ); return value; break; } #ifdef LOG printf("audio_directx_out: ao_directx_set_property() Exit! Returning ~value=%d\n", ~value); #endif return ~value; } static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { ao_directx_t * ao_directx = ( ao_directx_t * ) malloc( sizeof( ao_directx_t ) ); memset( ao_directx, 0, sizeof( ao_directx_t ) ); #ifdef LOG printf("audio_directx_out: open_plugin(%08x, %08x) Enter\n", (unsigned long)class_gen, (unsigned long)data); printf("audio_directx_out: open_plugin: ao_directx=%08x\n", (unsigned long)ao_directx); #endif ao_directx->ao_driver.get_capabilities = ao_directx_get_capabilities; ao_directx->ao_driver.get_property = ao_directx_get_property; ao_directx->ao_driver.set_property = ao_directx_set_property; ao_directx->ao_driver.open = ao_directx_open; ao_directx->ao_driver.num_channels = ao_directx_num_channels; ao_directx->ao_driver.bytes_per_frame = ao_directx_bytes_per_frame; ao_directx->ao_driver.delay = ao_directx_delay; ao_directx->ao_driver.write = ao_directx_write; ao_directx->ao_driver.close = ao_directx_close; ao_directx->ao_driver.exit = ao_directx_exit; ao_directx->ao_driver.get_gap_tolerance = ao_directx_get_gap_tolerance; ao_directx->ao_driver.control = ao_directx_control; CreateDirectSound( ao_directx ); #ifdef LOG printf("audio_directx_out: open_plugin() Exit! Returning ao_directx=%08x\n", (unsigned long)ao_directx); #endif return ( ao_driver_t * ) ao_directx; } static char* get_identifier (video_driver_class_t *this_gen) { return "DirectX"; } static char* get_description (audio_driver_class_t *this_gen) { return _("xine audio output plugin for win32 using directx"); } static void dispose_class (audio_driver_class_t *this_gen) { audiox_class_t *audiox = (audiox_class_t *) this_gen; free (audiox); } static void *init_class (xine_t *xine, void *data) { audiox_class_t *audiox; char* device_name; #ifdef LOG printf("audio_directx_out: init_class() Enter\n"); #endif device_name = xine->config->register_string(xine->config, "audio.directx_device", "/dev/audio_directx", _("xine audio output plugin for win32 using directx"), NULL, 10, NULL, NULL); /* * from this point on, nothing should go wrong anymore */ audiox = (audiox_class_t *) malloc (sizeof (audiox_class_t)); memset( audiox, 0, sizeof( audiox_class_t ) ); audiox->driver_class.open_plugin = open_plugin; audiox->driver_class.get_identifier = get_identifier; audiox->driver_class.get_description = get_description; audiox->driver_class.dispose = dispose_class; audiox->config = xine->config; audiox->device_name = device_name; #ifdef LOG printf("audio_directx_out: init_class() Exit! Returning audiox=%08x\n", audiox); #endif return audiox; } static ao_info_t ao_info_directx = { 1 /* priority */ }; /* * exported plugin catalog entry */ plugin_info_t xine_plugin_info[] = { /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_DIRECTX_IFACE_VERSION, "directx", XINE_VERSION_CODE, &ao_info_directx, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } };