ds_test.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. import unittest
  2. import struct
  3. import sys
  4. import os
  5. import pywintypes
  6. import win32event, win32api
  7. import os
  8. from pywin32_testutil import str2bytes, TestSkipped
  9. import win32com.directsound.directsound as ds
  10. # next two lines are for for debugging:
  11. # import win32com
  12. # import directsound as ds
  13. WAV_FORMAT_PCM = 1
  14. WAV_HEADER_SIZE = struct.calcsize('<4sl4s4slhhllhh4sl')
  15. def wav_header_unpack(data):
  16. (riff, riffsize, wave, fmt, fmtsize, format, nchannels, samplespersecond,
  17. datarate, blockalign, bitspersample, data, datalength) \
  18. = struct.unpack('<4sl4s4slhhllhh4sl', data)
  19. if riff != str2bytes('RIFF'):
  20. raise ValueError('invalid wav header')
  21. if fmtsize != 16 or fmt != str2bytes('fmt ') or str2bytes(data) != 'data':
  22. # fmt chuck is not first chunk, directly followed by data chuck
  23. # It is nowhere required that they are, it is just very common
  24. raise ValueError('cannot understand wav header')
  25. wfx = pywintypes.WAVEFORMATEX()
  26. wfx.wFormatTag = format
  27. wfx.nChannels = nchannels
  28. wfx.nSamplesPerSec = samplespersecond
  29. wfx.nAvgBytesPerSec = datarate
  30. wfx.nBlockAlign = blockalign
  31. wfx.wBitsPerSample = bitspersample
  32. return wfx, datalength
  33. def wav_header_pack(wfx, datasize):
  34. return struct.pack('<4sl4s4slhhllhh4sl', 'RIFF', 36 + datasize,
  35. 'WAVE', 'fmt ', 16,
  36. wfx.wFormatTag, wfx.nChannels, wfx.nSamplesPerSec,
  37. wfx.nAvgBytesPerSec, wfx.nBlockAlign,
  38. wfx.wBitsPerSample, 'data', datasize);
  39. class WAVEFORMATTest(unittest.TestCase):
  40. def test_1_Type(self):
  41. 'WAVEFORMATEX type'
  42. w = pywintypes.WAVEFORMATEX()
  43. self.failUnless(type(w) == pywintypes.WAVEFORMATEXType)
  44. def test_2_Attr(self):
  45. 'WAVEFORMATEX attribute access'
  46. # A wav header for a soundfile from a CD should look like this...
  47. w = pywintypes.WAVEFORMATEX()
  48. w.wFormatTag = pywintypes.WAVE_FORMAT_PCM
  49. w.nChannels = 2
  50. w.nSamplesPerSec = 44100
  51. w.nAvgBytesPerSec = 176400
  52. w.nBlockAlign = 4
  53. w.wBitsPerSample = 16
  54. self.failUnless(w.wFormatTag == 1)
  55. self.failUnless(w.nChannels == 2)
  56. self.failUnless(w.nSamplesPerSec == 44100)
  57. self.failUnless(w.nAvgBytesPerSec == 176400)
  58. self.failUnless(w.nBlockAlign == 4)
  59. self.failUnless(w.wBitsPerSample == 16)
  60. class DSCAPSTest(unittest.TestCase):
  61. def test_1_Type(self):
  62. 'DSCAPS type'
  63. c = ds.DSCAPS()
  64. self.failUnless(type(c) == ds.DSCAPSType)
  65. def test_2_Attr(self):
  66. 'DSCAPS attribute access'
  67. c = ds.DSCAPS()
  68. c.dwFlags = 1
  69. c.dwMinSecondarySampleRate = 2
  70. c.dwMaxSecondarySampleRate = 3
  71. c.dwPrimaryBuffers = 4
  72. c.dwMaxHwMixingAllBuffers = 5
  73. c.dwMaxHwMixingStaticBuffers = 6
  74. c.dwMaxHwMixingStreamingBuffers = 7
  75. c.dwFreeHwMixingAllBuffers = 8
  76. c.dwFreeHwMixingStaticBuffers = 9
  77. c.dwFreeHwMixingStreamingBuffers = 10
  78. c.dwMaxHw3DAllBuffers = 11
  79. c.dwMaxHw3DStaticBuffers = 12
  80. c.dwMaxHw3DStreamingBuffers = 13
  81. c.dwFreeHw3DAllBuffers = 14
  82. c.dwFreeHw3DStaticBuffers = 15
  83. c.dwFreeHw3DStreamingBuffers = 16
  84. c.dwTotalHwMemBytes = 17
  85. c.dwFreeHwMemBytes = 18
  86. c.dwMaxContigFreeHwMemBytes = 19
  87. c.dwUnlockTransferRateHwBuffers = 20
  88. c.dwPlayCpuOverheadSwBuffers = 21
  89. self.failUnless(c.dwFlags == 1)
  90. self.failUnless(c.dwMinSecondarySampleRate == 2)
  91. self.failUnless(c.dwMaxSecondarySampleRate == 3)
  92. self.failUnless(c.dwPrimaryBuffers == 4)
  93. self.failUnless(c.dwMaxHwMixingAllBuffers == 5)
  94. self.failUnless(c.dwMaxHwMixingStaticBuffers == 6)
  95. self.failUnless(c.dwMaxHwMixingStreamingBuffers == 7)
  96. self.failUnless(c.dwFreeHwMixingAllBuffers == 8)
  97. self.failUnless(c.dwFreeHwMixingStaticBuffers == 9)
  98. self.failUnless(c.dwFreeHwMixingStreamingBuffers == 10)
  99. self.failUnless(c.dwMaxHw3DAllBuffers == 11)
  100. self.failUnless(c.dwMaxHw3DStaticBuffers == 12)
  101. self.failUnless(c.dwMaxHw3DStreamingBuffers == 13)
  102. self.failUnless(c.dwFreeHw3DAllBuffers == 14)
  103. self.failUnless(c.dwFreeHw3DStaticBuffers == 15)
  104. self.failUnless(c.dwFreeHw3DStreamingBuffers == 16)
  105. self.failUnless(c.dwTotalHwMemBytes == 17)
  106. self.failUnless(c.dwFreeHwMemBytes == 18)
  107. self.failUnless(c.dwMaxContigFreeHwMemBytes == 19)
  108. self.failUnless(c.dwUnlockTransferRateHwBuffers == 20)
  109. self.failUnless(c.dwPlayCpuOverheadSwBuffers == 21)
  110. class DSBCAPSTest(unittest.TestCase):
  111. def test_1_Type(self):
  112. 'DSBCAPS type'
  113. c = ds.DSBCAPS()
  114. self.failUnless(type(c) == ds.DSBCAPSType)
  115. def test_2_Attr(self):
  116. 'DSBCAPS attribute access'
  117. c = ds.DSBCAPS()
  118. c.dwFlags = 1
  119. c.dwBufferBytes = 2
  120. c.dwUnlockTransferRate = 3
  121. c.dwPlayCpuOverhead = 4
  122. self.failUnless(c.dwFlags == 1)
  123. self.failUnless(c.dwBufferBytes == 2)
  124. self.failUnless(c.dwUnlockTransferRate == 3)
  125. self.failUnless(c.dwPlayCpuOverhead == 4)
  126. class DSCCAPSTest(unittest.TestCase):
  127. def test_1_Type(self):
  128. 'DSCCAPS type'
  129. c = ds.DSCCAPS()
  130. self.failUnless(type(c) == ds.DSCCAPSType)
  131. def test_2_Attr(self):
  132. 'DSCCAPS attribute access'
  133. c = ds.DSCCAPS()
  134. c.dwFlags = 1
  135. c.dwFormats = 2
  136. c.dwChannels = 4
  137. self.failUnless(c.dwFlags == 1)
  138. self.failUnless(c.dwFormats == 2)
  139. self.failUnless(c.dwChannels == 4)
  140. class DSCBCAPSTest(unittest.TestCase):
  141. def test_1_Type(self):
  142. 'DSCBCAPS type'
  143. c = ds.DSCBCAPS()
  144. self.failUnless(type(c) == ds.DSCBCAPSType)
  145. def test_2_Attr(self):
  146. 'DSCBCAPS attribute access'
  147. c = ds.DSCBCAPS()
  148. c.dwFlags = 1
  149. c.dwBufferBytes = 2
  150. self.failUnless(c.dwFlags == 1)
  151. self.failUnless(c.dwBufferBytes == 2)
  152. class DSBUFFERDESCTest(unittest.TestCase):
  153. def test_1_Type(self):
  154. 'DSBUFFERDESC type'
  155. c = ds.DSBUFFERDESC()
  156. self.failUnless(type(c) == ds.DSBUFFERDESCType)
  157. def test_2_Attr(self):
  158. 'DSBUFFERDESC attribute access'
  159. c = ds.DSBUFFERDESC()
  160. c.dwFlags = 1
  161. c.dwBufferBytes = 2
  162. c.lpwfxFormat = pywintypes.WAVEFORMATEX()
  163. c.lpwfxFormat.wFormatTag = pywintypes.WAVE_FORMAT_PCM
  164. c.lpwfxFormat.nChannels = 2
  165. c.lpwfxFormat.nSamplesPerSec = 44100
  166. c.lpwfxFormat.nAvgBytesPerSec = 176400
  167. c.lpwfxFormat.nBlockAlign = 4
  168. c.lpwfxFormat.wBitsPerSample = 16
  169. self.failUnless(c.dwFlags == 1)
  170. self.failUnless(c.dwBufferBytes == 2)
  171. self.failUnless(c.lpwfxFormat.wFormatTag == 1)
  172. self.failUnless(c.lpwfxFormat.nChannels == 2)
  173. self.failUnless(c.lpwfxFormat.nSamplesPerSec == 44100)
  174. self.failUnless(c.lpwfxFormat.nAvgBytesPerSec == 176400)
  175. self.failUnless(c.lpwfxFormat.nBlockAlign == 4)
  176. self.failUnless(c.lpwfxFormat.wBitsPerSample == 16)
  177. def invalid_format(self, c):
  178. c.lpwfxFormat = 17
  179. def test_3_invalid_format(self):
  180. 'DSBUFFERDESC invalid lpwfxFormat assignment'
  181. c = ds.DSBUFFERDESC()
  182. self.failUnlessRaises(ValueError, self.invalid_format, c)
  183. class DSCBUFFERDESCTest(unittest.TestCase):
  184. def test_1_Type(self):
  185. 'DSCBUFFERDESC type'
  186. c = ds.DSCBUFFERDESC()
  187. self.failUnless(type(c) == ds.DSCBUFFERDESCType)
  188. def test_2_Attr(self):
  189. 'DSCBUFFERDESC attribute access'
  190. c = ds.DSCBUFFERDESC()
  191. c.dwFlags = 1
  192. c.dwBufferBytes = 2
  193. c.lpwfxFormat = pywintypes.WAVEFORMATEX()
  194. c.lpwfxFormat.wFormatTag = pywintypes.WAVE_FORMAT_PCM
  195. c.lpwfxFormat.nChannels = 2
  196. c.lpwfxFormat.nSamplesPerSec = 44100
  197. c.lpwfxFormat.nAvgBytesPerSec = 176400
  198. c.lpwfxFormat.nBlockAlign = 4
  199. c.lpwfxFormat.wBitsPerSample = 16
  200. self.failUnless(c.dwFlags == 1)
  201. self.failUnless(c.dwBufferBytes == 2)
  202. self.failUnless(c.lpwfxFormat.wFormatTag == 1)
  203. self.failUnless(c.lpwfxFormat.nChannels == 2)
  204. self.failUnless(c.lpwfxFormat.nSamplesPerSec == 44100)
  205. self.failUnless(c.lpwfxFormat.nAvgBytesPerSec == 176400)
  206. self.failUnless(c.lpwfxFormat.nBlockAlign == 4)
  207. self.failUnless(c.lpwfxFormat.wBitsPerSample == 16)
  208. def invalid_format(self, c):
  209. c.lpwfxFormat = 17
  210. def test_3_invalid_format(self):
  211. 'DSCBUFFERDESC invalid lpwfxFormat assignment'
  212. c = ds.DSCBUFFERDESC()
  213. self.failUnlessRaises(ValueError, self.invalid_format, c)
  214. class DirectSoundTest(unittest.TestCase):
  215. # basic tests - mostly just exercise the functions
  216. def testEnumerate(self):
  217. '''DirectSoundEnumerate() sanity tests'''
  218. devices = ds.DirectSoundEnumerate()
  219. # this might fail on machines without a sound card
  220. self.failUnless(len(devices))
  221. # if we have an entry, it must be a tuple of size 3
  222. self.failUnless(len(devices[0]) == 3)
  223. def testCreate(self):
  224. '''DirectSoundCreate()'''
  225. d = ds.DirectSoundCreate(None, None)
  226. def testPlay(self):
  227. '''Mesdames et Messieurs, la cour de Devin Dazzle'''
  228. # look for the test file in various places
  229. candidates = [
  230. os.path.dirname(__file__),
  231. os.path.dirname(sys.argv[0]),
  232. # relative to 'testall.py' in the win32com test suite.
  233. os.path.join(os.path.dirname(sys.argv[0]),
  234. '../../win32comext/directsound/test'),
  235. '.',
  236. ]
  237. for candidate in candidates:
  238. fname=os.path.join(candidate, "01-Intro.wav")
  239. if os.path.isfile(fname):
  240. break
  241. else:
  242. raise TestSkipped("Can't find test .wav file to play")
  243. f = open(fname, 'rb')
  244. hdr = f.read(WAV_HEADER_SIZE)
  245. wfx, size = wav_header_unpack(hdr)
  246. d = ds.DirectSoundCreate(None, None)
  247. d.SetCooperativeLevel(None, ds.DSSCL_PRIORITY)
  248. sdesc = ds.DSBUFFERDESC()
  249. sdesc.dwFlags = ds.DSBCAPS_STICKYFOCUS | ds.DSBCAPS_CTRLPOSITIONNOTIFY
  250. sdesc.dwBufferBytes = size
  251. sdesc.lpwfxFormat = wfx
  252. buffer = d.CreateSoundBuffer(sdesc, None)
  253. event = win32event.CreateEvent(None, 0, 0, None)
  254. notify = buffer.QueryInterface(ds.IID_IDirectSoundNotify)
  255. notify.SetNotificationPositions((ds.DSBPN_OFFSETSTOP, event))
  256. buffer.Update(0, f.read(size))
  257. buffer.Play(0)
  258. win32event.WaitForSingleObject(event, -1)
  259. class DirectSoundCaptureTest(unittest.TestCase):
  260. # basic tests - mostly just exercise the functions
  261. def testEnumerate(self):
  262. '''DirectSoundCaptureEnumerate() sanity tests'''
  263. devices = ds.DirectSoundCaptureEnumerate()
  264. # this might fail on machines without a sound card
  265. self.failUnless(len(devices))
  266. # if we have an entry, it must be a tuple of size 3
  267. self.failUnless(len(devices[0]) == 3)
  268. def testCreate(self):
  269. '''DirectSoundCreate()'''
  270. d = ds.DirectSoundCaptureCreate(None, None)
  271. def testRecord(self):
  272. d = ds.DirectSoundCaptureCreate(None, None)
  273. sdesc = ds.DSCBUFFERDESC()
  274. sdesc.dwBufferBytes = 352800 # 2 seconds
  275. sdesc.lpwfxFormat = pywintypes.WAVEFORMATEX()
  276. sdesc.lpwfxFormat.wFormatTag = pywintypes.WAVE_FORMAT_PCM
  277. sdesc.lpwfxFormat.nChannels = 2
  278. sdesc.lpwfxFormat.nSamplesPerSec = 44100
  279. sdesc.lpwfxFormat.nAvgBytesPerSec = 176400
  280. sdesc.lpwfxFormat.nBlockAlign = 4
  281. sdesc.lpwfxFormat.wBitsPerSample = 16
  282. buffer = d.CreateCaptureBuffer(sdesc)
  283. event = win32event.CreateEvent(None, 0, 0, None)
  284. notify = buffer.QueryInterface(ds.IID_IDirectSoundNotify)
  285. notify.SetNotificationPositions((ds.DSBPN_OFFSETSTOP, event))
  286. buffer.Start(0)
  287. win32event.WaitForSingleObject(event, -1)
  288. event.Close()
  289. data = buffer.Update(0, 352800)
  290. fname=os.path.join(win32api.GetTempPath(), 'test_directsound_record.wav')
  291. f = open(fname, 'wb')
  292. f.write(wav_header_pack(sdesc.lpwfxFormat, 352800))
  293. f.write(data)
  294. f.close()
  295. if __name__ == '__main__':
  296. unittest.main()