portaudio-non-mmap-alsa.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. diff -ur portaudio/src/hostapi/alsa/pa_linux_alsa.c portaudio-pulseaudio/src/hostapi/alsa/pa_linux_alsa.c
  2. --- portaudio/src/hostapi/alsa/pa_linux_alsa.c 2007-09-12 19:39:48.000000000 +0200
  3. +++ portaudio-pulseaudio/src/hostapi/alsa/pa_linux_alsa.c 2008-12-08 19:30:20.000000000 +0100
  4. @@ -6,6 +6,7 @@
  5. *
  6. * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
  7. * Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no>
  8. + * Copyright (c) 2008 Kevin Kofler <kevin.kofler@chello.at>
  9. *
  10. * Based on the Open Source API proposed by Ross Bencina
  11. * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
  12. @@ -118,6 +119,8 @@
  13. unsigned long framesPerBuffer;
  14. int numUserChannels, numHostChannels;
  15. int userInterleaved, hostInterleaved;
  16. + int canMmap;
  17. + void *nonMmapBuffer;
  18. PaDeviceIndex device; /* Keep the device index */
  19. snd_pcm_t *pcm;
  20. @@ -321,7 +324,7 @@
  21. * and a suitable result returned. The device is closed before returning.
  22. */
  23. static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
  24. - PaAlsaDeviceInfo* devInfo, int* canMmap )
  25. + PaAlsaDeviceInfo* devInfo )
  26. {
  27. PaError result = paNoError;
  28. snd_pcm_hw_params_t *hwParams;
  29. @@ -354,9 +357,6 @@
  30. snd_pcm_hw_params_alloca( &hwParams );
  31. snd_pcm_hw_params_any( pcm, hwParams );
  32. - *canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 ||
  33. - snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0;
  34. -
  35. if( defaultSr >= 0 )
  36. {
  37. /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
  38. @@ -566,7 +566,6 @@
  39. PaError result = 0;
  40. PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
  41. snd_pcm_t *pcm;
  42. - int canMmap = -1;
  43. PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
  44. /* Zero fields */
  45. @@ -580,8 +579,7 @@
  46. OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 )
  47. >= 0 )
  48. {
  49. - if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo,
  50. - &canMmap ) != paNoError )
  51. + if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
  52. {
  53. /* Error */
  54. PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
  55. @@ -594,8 +592,7 @@
  56. OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
  57. >= 0 )
  58. {
  59. - if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo,
  60. - &canMmap ) != paNoError )
  61. + if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
  62. {
  63. /* Error */
  64. PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
  65. @@ -603,12 +600,6 @@
  66. }
  67. }
  68. - if( 0 == canMmap )
  69. - {
  70. - PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceName->alsaName));
  71. - goto end;
  72. - }
  73. -
  74. baseDeviceInfo->structVersion = 2;
  75. baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
  76. baseDeviceInfo->name = deviceName->name;
  77. @@ -1197,6 +1188,8 @@
  78. self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
  79. self->numUserChannels = params->channelCount;
  80. self->streamDir = streamDir;
  81. + self->canMmap = 0;
  82. + self->nonMmapBuffer = NULL;
  83. if( !callbackMode && !self->userInterleaved )
  84. {
  85. @@ -1239,6 +1232,7 @@
  86. PaError result = paNoError;
  87. snd_pcm_access_t accessMode, alternateAccessMode;
  88. + snd_pcm_access_t rwAccessMode, alternateRwAccessMode;
  89. int dir = 0;
  90. snd_pcm_t *pcm = self->pcm;
  91. double sr = *sampleRate;
  92. @@ -1258,32 +1252,40 @@
  93. if( self->userInterleaved )
  94. {
  95. accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
  96. + rwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
  97. alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
  98. + alternateRwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
  99. }
  100. else
  101. {
  102. accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
  103. + rwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
  104. alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
  105. + alternateRwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
  106. }
  107. /* If requested access mode fails, try alternate mode */
  108. + self->canMmap = 1;
  109. if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
  110. {
  111. - int err = 0;
  112. - if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0)
  113. + if( snd_pcm_hw_params_set_access( pcm, hwParams, rwAccessMode ) >= 0 )
  114. + self->canMmap = 0;
  115. + else
  116. {
  117. - result = paUnanticipatedHostError;
  118. - if( -EINVAL == err )
  119. + if( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ) < 0 )
  120. {
  121. - PaUtil_SetLastHostErrorInfo( paALSA, err, "PA ALSA requires that a device supports mmap access" );
  122. - }
  123. - else
  124. - {
  125. - PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
  126. + int err = 0;
  127. + if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateRwAccessMode )) >= 0)
  128. + self->canMmap = 0;
  129. + else
  130. + {
  131. + result = paUnanticipatedHostError;
  132. + PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
  133. + goto error;
  134. + }
  135. }
  136. - goto error;
  137. + /* Flip mode */
  138. + self->hostInterleaved = !self->userInterleaved;
  139. }
  140. - /* Flip mode */
  141. - self->hostInterleaved = !self->userInterleaved;
  142. }
  143. ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
  144. @@ -1361,7 +1363,7 @@
  145. ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
  146. ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
  147. - ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
  148. + ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
  149. /* Set the parameters! */
  150. ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
  151. @@ -1589,6 +1591,10 @@
  152. }
  153. }
  154. + /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
  155. + if( !self->canMmap && framesPerHostBuffer < 2048 )
  156. + framesPerHostBuffer = 2048;
  157. +
  158. assert( framesPerHostBuffer > 0 );
  159. {
  160. snd_pcm_uframes_t min = 0, max = 0;
  161. @@ -1831,12 +1837,13 @@
  162. PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
  163. self->maxFramesPerHostBuffer = framesPerHostBuffer;
  164. - if( !accurate )
  165. + if( !self->playback.canMmap || !accurate )
  166. {
  167. /* Don't know the exact size per host buffer */
  168. *hostBufferSizeMode = paUtilBoundedHostBufferSize;
  169. /* Raise upper bound */
  170. - ++self->maxFramesPerHostBuffer;
  171. + if( !accurate )
  172. + ++self->maxFramesPerHostBuffer;
  173. }
  174. error:
  175. @@ -2059,9 +2066,11 @@
  176. {
  177. /* Buffer isn't primed, so prepare and silence */
  178. ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
  179. - SilenceBuffer( stream );
  180. + if( stream->playback.canMmap )
  181. + SilenceBuffer( stream );
  182. }
  183. - ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
  184. + if( stream->playback.canMmap )
  185. + ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
  186. }
  187. else
  188. ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
  189. @@ -2390,6 +2399,7 @@
  190. snd_pcm_status_t *st;
  191. PaTime now = PaUtil_GetTime();
  192. snd_timestamp_t t;
  193. + int errplayback = 0, errcapture = 0;
  194. snd_pcm_status_alloca( &st );
  195. @@ -2400,6 +2410,7 @@
  196. {
  197. snd_pcm_status_get_trigger_tstamp( st, &t );
  198. self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
  199. + errplayback = snd_pcm_recover( self->playback.pcm, -EPIPE, 0 );
  200. }
  201. }
  202. if( self->capture.pcm )
  203. @@ -2409,10 +2420,12 @@
  204. {
  205. snd_pcm_status_get_trigger_tstamp( st, &t );
  206. self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
  207. + errcapture = snd_pcm_recover( self->capture.pcm, -EPIPE, 0 );
  208. }
  209. }
  210. - PA_ENSURE( AlsaRestart( self ) );
  211. + if( errplayback || errcapture )
  212. + PA_ENSURE( AlsaRestart( self ) );
  213. end:
  214. return result;
  215. @@ -2563,7 +2576,7 @@
  216. static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
  217. {
  218. PaError result = paNoError;
  219. - int res;
  220. + int res = 0;
  221. /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
  222. * afterwards
  223. @@ -2571,7 +2584,34 @@
  224. if( !self->ready )
  225. goto end;
  226. - res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
  227. + if( !self->canMmap && StreamDirection_Out == self->streamDir )
  228. + {
  229. + /* Play sound */
  230. + if( self->hostInterleaved )
  231. + res = snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames );
  232. + else
  233. + {
  234. + void *bufs[self->numHostChannels];
  235. + int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
  236. + unsigned char *buffer = self->nonMmapBuffer;
  237. + int i;
  238. + for( i = 0; i < self->numHostChannels; ++i )
  239. + {
  240. + bufs[i] = buffer;
  241. + buffer += bufsize;
  242. + }
  243. + res = snd_pcm_writen( self->pcm, bufs, numFrames );
  244. + }
  245. + }
  246. +
  247. + if( self->canMmap )
  248. + res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
  249. + else
  250. + {
  251. + free( self->nonMmapBuffer );
  252. + self->nonMmapBuffer = NULL;
  253. + }
  254. +
  255. if( res == -EPIPE || res == -ESTRPIPE )
  256. {
  257. *xrun = 1;
  258. @@ -2611,7 +2651,7 @@
  259. if( self->hostInterleaved )
  260. {
  261. int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
  262. - unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset );
  263. + unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer;
  264. /* Start after the last user channel */
  265. p = buffer + self->numUserChannels * swidth;
  266. @@ -2991,13 +3031,23 @@
  267. goto end;
  268. }
  269. - ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
  270. + if( self->canMmap )
  271. + {
  272. + ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
  273. + /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
  274. + self->channelAreas = (snd_pcm_channel_area_t *)areas;
  275. + }
  276. + else
  277. + {
  278. + free( self->nonMmapBuffer );
  279. + self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
  280. + }
  281. if( self->hostInterleaved )
  282. {
  283. int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
  284. - p = buffer = ExtractAddress( areas, self->offset );
  285. + p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer;
  286. for( i = 0; i < self->numUserChannels; ++i )
  287. {
  288. /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
  289. @@ -3007,16 +3057,52 @@
  290. }
  291. else
  292. {
  293. - for( i = 0; i < self->numUserChannels; ++i )
  294. + if( self->canMmap )
  295. + for( i = 0; i < self->numUserChannels; ++i )
  296. + {
  297. + area = areas + i;
  298. + buffer = ExtractAddress( area, self->offset );
  299. + setChannel( bp, i, buffer, 1 );
  300. + }
  301. + else
  302. {
  303. - area = areas + i;
  304. - buffer = ExtractAddress( area, self->offset );
  305. - setChannel( bp, i, buffer, 1 );
  306. + int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
  307. + buffer = self->nonMmapBuffer;
  308. + for( i = 0; i < self->numUserChannels; ++i )
  309. + {
  310. + setChannel( bp, i, buffer, 1 );
  311. + buffer += bufsize;
  312. + }
  313. }
  314. }
  315. - /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
  316. - self->channelAreas = (snd_pcm_channel_area_t *)areas;
  317. + if( !self->canMmap && StreamDirection_In == self->streamDir )
  318. + {
  319. + /* Read sound */
  320. + int res;
  321. + if( self->hostInterleaved )
  322. + res = snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames );
  323. + else
  324. + {
  325. + void *bufs[self->numHostChannels];
  326. + int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
  327. + unsigned char *buffer = self->nonMmapBuffer;
  328. + int i;
  329. + for( i = 0; i < self->numHostChannels; ++i )
  330. + {
  331. + bufs[i] = buffer;
  332. + buffer += bufsize;
  333. + }
  334. + res = snd_pcm_readn( self->pcm, bufs, *numFrames );
  335. + }
  336. + if( res == -EPIPE || res == -ESTRPIPE )
  337. + {
  338. + *xrun = 1;
  339. + *numFrames = 0;
  340. + free( self->nonMmapBuffer );
  341. + self->nonMmapBuffer = NULL;
  342. + }
  343. + }
  344. end:
  345. error:
  346. diff -ur portaudio/src/os/unix/pa_unix_hostapis.c portaudio-pulseaudio/src/os/unix/pa_unix_hostapis.c
  347. --- portaudio/src/os/unix/pa_unix_hostapis.c 2006-08-26 10:27:53.000000000 +0200
  348. +++ portaudio-pulseaudio/src/os/unix/pa_unix_hostapis.c 2008-11-09 04:51:04.000000000 +0100
  349. @@ -75,4 +75,8 @@
  350. 0 /* NULL terminated array */
  351. };
  352. +#if defined(PA_USE_OSS) && defined(PA_USE_ALSA)
  353. +int paDefaultHostApiIndex = 1;
  354. +#else
  355. int paDefaultHostApiIndex = 0;
  356. +#endif