ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

wave.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * COPYRIGHT:            See COPYING in the top level directory
00004  * PROJECT:              ReactOS Multimedia
00005  * FILE:                 dll/win32/mmdrv/wave.c
00006  * PURPOSE:              Multimedia User Mode Driver (Wave Audio)
00007  * PROGRAMMER:           Andrew Greenwood
00008  * UPDATE HISTORY:
00009  *                       Jan 30, 2004: Imported into ReactOS tree
00010  *                       Jan 14, 2007: Rewritten and tidied up
00011  */
00012 
00013 #include <mmdrv.h>
00014 
00015 
00016 #define MAX_WAVE_BUFFER_SIZE    65536
00017 
00018 
00019 MMRESULT
00020 QueueWaveBuffer(
00021     SessionInfo* session_info,
00022     LPWAVEHDR wave_header)
00023 {
00024     PWAVEHDR queue_node, previous_node;
00025     DPRINT("Queueing wave buffer\n");
00026 
00027     if ( ! wave_header )
00028     {
00029         return MMSYSERR_INVALPARAM;
00030     }
00031 
00032     if ( ! wave_header->lpData )
00033     {
00034         return MMSYSERR_INVALPARAM;
00035     }
00036 
00037     /* Headers must be prepared first */
00038     if ( ! ( wave_header->dwFlags & WHDR_PREPARED ) )
00039     {
00040         DPRINT("I was given a header which hasn't been prepared yet!\n");
00041         return WAVERR_UNPREPARED;
00042     }
00043 
00044     /* ...and they must not already be in the playing queue! */
00045     if ( wave_header->dwFlags & WHDR_INQUEUE )
00046     {
00047         DPRINT("I was given a header for a buffer which is already playing\n");
00048         return WAVERR_STILLPLAYING;
00049     }
00050 
00051     /* Initialize */
00052     wave_header->dwBytesRecorded = 0;
00053 
00054     /* Clear the DONE bit, and mark the buffer as queued */
00055     wave_header->dwFlags &= ~WHDR_DONE;
00056     wave_header->dwFlags |= WHDR_INQUEUE;
00057 
00058     /* Save our handle in the header */
00059     wave_header->reserved = (DWORD_PTR) session_info;
00060 
00061     /* Locate the end of the queue */
00062     previous_node = NULL;
00063     queue_node = session_info->wave_queue;
00064 
00065     while ( queue_node )
00066     {
00067         previous_node = queue_node;
00068         queue_node = queue_node->lpNext;
00069     }
00070 
00071     /* Go back a step to obtain the previous node (non-NULL) */
00072     queue_node = previous_node;
00073 
00074     /* Append our buffer here, and terminate the queue */
00075     queue_node->lpNext = wave_header;
00076     wave_header->lpNext = NULL;
00077 
00078     /* When no buffers are playing there's no play queue so we start one */
00079 #if 0
00080     if ( ! session_info->next_buffer )
00081     {
00082         session_info->buffer_position = 0;
00083         session_info->next_buffer = wave_header;
00084     }
00085 #endif
00086 
00087     /* Pass to the driver - happens automatically during playback */
00088 //    return PerformWaveIO(session_info);
00089     return MMSYSERR_NOERROR;
00090 }
00091 
00092 VOID
00093 ReturnCompletedBuffers(SessionInfo* session_info)
00094 {
00095     PWAVEHDR header = NULL;
00096 
00097     /* Set the current header and test to ensure it's not NULL */
00098     while ( ( header = session_info->wave_queue ) )
00099     {
00100         if ( header->dwFlags & WHDR_DONE )
00101         {
00102             DWORD message;
00103 
00104             /* Mark as done, and unqueued */
00105             header->dwFlags &= ~WHDR_INQUEUE;
00106             header->dwFlags |= WHDR_DONE;
00107 
00108             /* Trim it from the start of the queue */
00109             session_info->wave_queue = header->lpNext;
00110 
00111             /* Choose appropriate notification */
00112             message = (session_info->device_type == WaveOutDevice) ? WOM_DONE :
00113                                                                      WIM_DATA;
00114 
00115             DPRINT("Notifying client that buffer 0x%p is done\n", header);
00116 
00117             /* Notify the client */
00118             NotifyClient(session_info, message, (DWORD_PTR) header, 0);
00119         }
00120     }
00121 
00122     /* TODO: Perform I/O as a new buffer may have arrived */
00123 }
00124 
00125 
00126 /*
00127     Each thread function/request is packed into the SessionInfo structure
00128     using a function ID and a parameter (in some cases.) When the function
00129     completes, the function code is set to an "invalid" value. This is,
00130     effectively, a hub for operations where sound driver I/O is concerned.
00131     It handles MME message codes so is a form of deferred wodMessage().
00132 */
00133 
00134 DWORD
00135 ProcessSessionThreadRequest(SessionInfo* session_info)
00136 {
00137     MMRESULT result = MMSYSERR_NOERROR;
00138 
00139     switch ( session_info->thread.function )
00140     {
00141         case WODM_WRITE :
00142         {
00143             result = QueueWaveBuffer(session_info,
00144                                      (LPWAVEHDR) session_info->thread.parameter);
00145             break;
00146         }
00147 
00148         case WODM_RESET :
00149         {
00150             /* TODO */
00151             break;
00152         }
00153 
00154         case WODM_PAUSE :
00155         {
00156             /* TODO */
00157             break;
00158         }
00159 
00160         case WODM_RESTART :
00161         {
00162             /* TODO */
00163             break;
00164         }
00165 
00166         case WODM_GETPOS :
00167         {
00168             /* TODO */
00169             break;
00170         }
00171 
00172         case WODM_SETPITCH :
00173         {
00174             result = SetDeviceData(session_info->kernel_device_handle,
00175                                    IOCTL_WAVE_SET_PITCH,
00176                                    (PBYTE) session_info->thread.parameter,
00177                                    sizeof(DWORD));
00178             break;
00179         }
00180 
00181         case WODM_GETPITCH :
00182         {
00183             result = GetDeviceData(session_info->kernel_device_handle,
00184                                    IOCTL_WAVE_GET_PITCH,
00185                                    (PBYTE) session_info->thread.parameter,
00186                                    sizeof(DWORD));
00187             break;
00188         }
00189 
00190         case WODM_SETVOLUME :
00191         {
00192             break;
00193         }
00194 
00195         case WODM_GETVOLUME :
00196         {
00197 #if 0
00198             result = GetDeviceData(session_info->kernel_device_handle,
00199                                    IOCTL_WAVE_GET_VOLUME,
00200                                    (PBYTE) session_info->thread.parameter,);
00201 #endif
00202             break;
00203         }
00204 
00205         case WODM_SETPLAYBACKRATE :
00206         {
00207             result = SetDeviceData(session_info->kernel_device_handle,
00208                                    IOCTL_WAVE_SET_PLAYBACK_RATE,
00209                                    (PBYTE) session_info->thread.parameter,
00210                                    sizeof(DWORD));
00211             break;
00212         }
00213 
00214         case WODM_GETPLAYBACKRATE :
00215         {
00216             result = GetDeviceData(session_info->kernel_device_handle,
00217                                    IOCTL_WAVE_GET_PLAYBACK_RATE,
00218                                    (PBYTE) session_info->thread.parameter,
00219                                    sizeof(DWORD));
00220             break;
00221         }
00222 
00223         case WODM_CLOSE :
00224         {
00225             DPRINT("Thread was asked if OK to close device\n");
00226 
00227             if ( session_info->wave_queue != NULL )
00228                 result = WAVERR_STILLPLAYING;
00229             else
00230                 result = MMSYSERR_NOERROR;
00231 
00232             break;
00233         }
00234 
00235         case DRVM_TERMINATE :
00236         {
00237             DPRINT("Terminating thread...\n");
00238             result = MMSYSERR_NOERROR;
00239             break;
00240         }
00241 
00242         default :
00243         {
00244             DPRINT("INVALID FUNCTION\n");
00245             result = MMSYSERR_ERROR;
00246             break;
00247         }
00248     }
00249 
00250     /* We're done with the function now */
00251 
00252     return result;
00253 }
00254 
00255 
00256 /*
00257     The wave "session". This starts, sets itself as high priority, then waits
00258     for the "go" event. When this occurs, it processes the requested function,
00259     tidies up any buffers that have finished playing, sends new buffers to the
00260     sound driver, then continues handing finished buffers back to the calling
00261     application until it's asked to do something else.
00262 */
00263 
00264 DWORD
00265 WaveThread(LPVOID parameter)
00266 {
00267     MMRESULT result = MMSYSERR_ERROR;
00268     SessionInfo* session_info = (SessionInfo*) parameter;
00269     BOOL terminate = FALSE;
00270 
00271     /* All your CPU time are belong to us */
00272     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
00273 
00274     DPRINT("Wave processing thread setting ready state\n");
00275 
00276     SetEvent(session_info->thread.ready_event);
00277 
00278     while ( ! terminate )
00279     {
00280         /* Wait for GO event, or IO completion notification */
00281         while ( WaitForSingleObjectEx(session_info->thread.go_event,
00282                                       INFINITE,
00283                                       TRUE) == WAIT_IO_COMPLETION )
00284         {
00285             /* A buffer has been finished with - pass back to the client */
00286             ReturnCompletedBuffers(session_info);
00287         }
00288 
00289         DPRINT("Wave processing thread woken up\n");
00290 
00291         /* Set the terminate flag if that's what the caller wants */
00292         terminate = (session_info->thread.function == DRVM_TERMINATE);
00293 
00294         /* Process the request */
00295         DPRINT("Processing thread request\n");
00296         result = ProcessSessionThreadRequest(session_info);
00297 
00298         /* Store the result code */
00299         session_info->thread.result = result;
00300 
00301         /* Submit new buffers and continue existing ones */
00302         DPRINT("Performing wave I/O\n");
00303         PerformWaveIO(session_info);
00304 
00305         /* Now we're ready for more action */
00306         DPRINT("Wave processing thread sleeping\n");
00307         SetEvent(session_info->thread.ready_event);
00308     }
00309 
00310     return 0;
00311 }
00312 
00313 
00314 /*
00315     Convenience function for calculating the size of the WAVEFORMATEX struct.
00316 */
00317 
00318 DWORD
00319 GetWaveFormatExSize(PWAVEFORMATEX format)
00320 {
00321     if ( format->wFormatTag == WAVE_FORMAT_PCM )
00322         return sizeof(PCMWAVEFORMAT);
00323     else
00324         return sizeof(WAVEFORMATEX) + format->cbSize;
00325 }
00326 
00327 
00328 /*
00329     Query if the driver/device is capable of handling a format. This is called
00330     if the device is a wave device, and the QUERYFORMAT flag is set.
00331 */
00332 
00333 DWORD
00334 QueryWaveFormat(
00335     DeviceType device_type,
00336     PVOID lpFormat)
00337 {
00338     /* TODO */
00339     return WAVERR_BADFORMAT;
00340 }
00341 
00342 
00343 /*
00344     Set the format to be used.
00345 */
00346 
00347 BOOL
00348 SetWaveFormat(
00349     HANDLE device_handle,
00350     PWAVEFORMATEX format)
00351 {
00352     DWORD bytes_returned;
00353     DWORD size;
00354 
00355     size = GetWaveFormatExSize(format);
00356 
00357     DPRINT("SetWaveFormat\n");
00358 
00359     return DeviceIoControl(device_handle,
00360                            IOCTL_WAVE_SET_FORMAT,
00361                            (PVOID) format,
00362                            size,
00363                            NULL,
00364                            0,
00365                            &bytes_returned,
00366                            NULL);
00367 }
00368 
00369 
00370 DWORD
00371 WriteWaveBuffer(
00372     DWORD_PTR private_handle,
00373     PWAVEHDR wave_header,
00374     DWORD wave_header_size)
00375 {
00376     SessionInfo* session_info = (SessionInfo*) private_handle;
00377     ASSERT(session_info);
00378 
00379     /* Let the processing thread know that it has work to do */
00380     return CallSessionThread(session_info, WODM_WRITE, wave_header);
00381 }

Generated on Sat May 26 2012 04:23:16 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.