pcm_plugin.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. * PCM Plug-In shared (kernel/library) code
  3. * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
  4. * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
  5. *
  6. *
  7. * This library is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Library General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. #if 0
  23. #define PLUGIN_DEBUG
  24. #endif
  25. #include <linux/slab.h>
  26. #include <linux/time.h>
  27. #include <linux/vmalloc.h>
  28. #include <sound/core.h>
  29. #include <sound/pcm.h>
  30. #include <sound/pcm_params.h>
  31. #include "pcm_plugin.h"
  32. #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
  33. #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
  34. /*
  35. * because some cards might have rates "very close", we ignore
  36. * all "resampling" requests within +-5%
  37. */
  38. static int rate_match(unsigned int src_rate, unsigned int dst_rate)
  39. {
  40. unsigned int low = (src_rate * 95) / 100;
  41. unsigned int high = (src_rate * 105) / 100;
  42. return dst_rate >= low && dst_rate <= high;
  43. }
  44. static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
  45. {
  46. struct snd_pcm_plugin_format *format;
  47. ssize_t width;
  48. size_t size;
  49. unsigned int channel;
  50. struct snd_pcm_plugin_channel *c;
  51. if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  52. format = &plugin->src_format;
  53. } else {
  54. format = &plugin->dst_format;
  55. }
  56. if ((width = snd_pcm_format_physical_width(format->format)) < 0)
  57. return width;
  58. size = frames * format->channels * width;
  59. snd_assert((size % 8) == 0, return -ENXIO);
  60. size /= 8;
  61. if (plugin->buf_frames < frames) {
  62. vfree(plugin->buf);
  63. plugin->buf = vmalloc(size);
  64. plugin->buf_frames = frames;
  65. }
  66. if (!plugin->buf) {
  67. plugin->buf_frames = 0;
  68. return -ENOMEM;
  69. }
  70. c = plugin->buf_channels;
  71. if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
  72. for (channel = 0; channel < format->channels; channel++, c++) {
  73. c->frames = frames;
  74. c->enabled = 1;
  75. c->wanted = 0;
  76. c->area.addr = plugin->buf;
  77. c->area.first = channel * width;
  78. c->area.step = format->channels * width;
  79. }
  80. } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
  81. snd_assert((size % format->channels) == 0,);
  82. size /= format->channels;
  83. for (channel = 0; channel < format->channels; channel++, c++) {
  84. c->frames = frames;
  85. c->enabled = 1;
  86. c->wanted = 0;
  87. c->area.addr = plugin->buf + (channel * size);
  88. c->area.first = 0;
  89. c->area.step = width;
  90. }
  91. } else
  92. return -EINVAL;
  93. return 0;
  94. }
  95. int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
  96. {
  97. int err;
  98. snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
  99. if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
  100. struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
  101. while (plugin->next) {
  102. if (plugin->dst_frames)
  103. frames = plugin->dst_frames(plugin, frames);
  104. snd_assert(frames > 0, return -ENXIO);
  105. plugin = plugin->next;
  106. err = snd_pcm_plugin_alloc(plugin, frames);
  107. if (err < 0)
  108. return err;
  109. }
  110. } else {
  111. struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
  112. while (plugin->prev) {
  113. if (plugin->src_frames)
  114. frames = plugin->src_frames(plugin, frames);
  115. snd_assert(frames > 0, return -ENXIO);
  116. plugin = plugin->prev;
  117. err = snd_pcm_plugin_alloc(plugin, frames);
  118. if (err < 0)
  119. return err;
  120. }
  121. }
  122. return 0;
  123. }
  124. snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
  125. snd_pcm_uframes_t frames,
  126. struct snd_pcm_plugin_channel **channels)
  127. {
  128. *channels = plugin->buf_channels;
  129. return frames;
  130. }
  131. int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
  132. const char *name,
  133. struct snd_pcm_plugin_format *src_format,
  134. struct snd_pcm_plugin_format *dst_format,
  135. size_t extra,
  136. struct snd_pcm_plugin **ret)
  137. {
  138. struct snd_pcm_plugin *plugin;
  139. unsigned int channels;
  140. snd_assert(plug != NULL, return -ENXIO);
  141. snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
  142. plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
  143. if (plugin == NULL)
  144. return -ENOMEM;
  145. plugin->name = name;
  146. plugin->plug = plug;
  147. plugin->stream = snd_pcm_plug_stream(plug);
  148. plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
  149. plugin->src_format = *src_format;
  150. plugin->src_width = snd_pcm_format_physical_width(src_format->format);
  151. snd_assert(plugin->src_width > 0, );
  152. plugin->dst_format = *dst_format;
  153. plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
  154. snd_assert(plugin->dst_width > 0, );
  155. if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
  156. channels = src_format->channels;
  157. else
  158. channels = dst_format->channels;
  159. plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL);
  160. if (plugin->buf_channels == NULL) {
  161. snd_pcm_plugin_free(plugin);
  162. return -ENOMEM;
  163. }
  164. plugin->client_channels = snd_pcm_plugin_client_channels;
  165. *ret = plugin;
  166. return 0;
  167. }
  168. int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
  169. {
  170. if (! plugin)
  171. return 0;
  172. if (plugin->private_free)
  173. plugin->private_free(plugin);
  174. kfree(plugin->buf_channels);
  175. vfree(plugin->buf);
  176. kfree(plugin);
  177. return 0;
  178. }
  179. snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
  180. {
  181. struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
  182. int stream = snd_pcm_plug_stream(plug);
  183. snd_assert(plug != NULL, return -ENXIO);
  184. if (drv_frames == 0)
  185. return 0;
  186. if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
  187. plugin = snd_pcm_plug_last(plug);
  188. while (plugin && drv_frames > 0) {
  189. plugin_prev = plugin->prev;
  190. if (plugin->src_frames)
  191. drv_frames = plugin->src_frames(plugin, drv_frames);
  192. plugin = plugin_prev;
  193. }
  194. } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
  195. plugin = snd_pcm_plug_first(plug);
  196. while (plugin && drv_frames > 0) {
  197. plugin_next = plugin->next;
  198. if (plugin->dst_frames)
  199. drv_frames = plugin->dst_frames(plugin, drv_frames);
  200. plugin = plugin_next;
  201. }
  202. } else
  203. snd_BUG();
  204. return drv_frames;
  205. }
  206. snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
  207. {
  208. struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
  209. snd_pcm_sframes_t frames;
  210. int stream = snd_pcm_plug_stream(plug);
  211. snd_assert(plug != NULL, return -ENXIO);
  212. if (clt_frames == 0)
  213. return 0;
  214. frames = clt_frames;
  215. if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
  216. plugin = snd_pcm_plug_first(plug);
  217. while (plugin && frames > 0) {
  218. plugin_next = plugin->next;
  219. if (plugin->dst_frames) {
  220. frames = plugin->dst_frames(plugin, frames);
  221. if (frames < 0)
  222. return frames;
  223. }
  224. plugin = plugin_next;
  225. }
  226. } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
  227. plugin = snd_pcm_plug_last(plug);
  228. while (plugin) {
  229. plugin_prev = plugin->prev;
  230. if (plugin->src_frames) {
  231. frames = plugin->src_frames(plugin, frames);
  232. if (frames < 0)
  233. return frames;
  234. }
  235. plugin = plugin_prev;
  236. }
  237. } else
  238. snd_BUG();
  239. return frames;
  240. }
  241. static int snd_pcm_plug_formats(struct snd_mask *mask, int format)
  242. {
  243. struct snd_mask formats = *mask;
  244. u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
  245. SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
  246. SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
  247. SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
  248. SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
  249. SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE |
  250. SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
  251. SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
  252. SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
  253. snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
  254. if (formats.bits[0] & (u32)linfmts)
  255. formats.bits[0] |= (u32)linfmts;
  256. if (formats.bits[1] & (u32)(linfmts >> 32))
  257. formats.bits[1] |= (u32)(linfmts >> 32);
  258. return snd_mask_test(&formats, format);
  259. }
  260. static int preferred_formats[] = {
  261. SNDRV_PCM_FORMAT_S16_LE,
  262. SNDRV_PCM_FORMAT_S16_BE,
  263. SNDRV_PCM_FORMAT_U16_LE,
  264. SNDRV_PCM_FORMAT_U16_BE,
  265. SNDRV_PCM_FORMAT_S24_3LE,
  266. SNDRV_PCM_FORMAT_S24_3BE,
  267. SNDRV_PCM_FORMAT_U24_3LE,
  268. SNDRV_PCM_FORMAT_U24_3BE,
  269. SNDRV_PCM_FORMAT_S24_LE,
  270. SNDRV_PCM_FORMAT_S24_BE,
  271. SNDRV_PCM_FORMAT_U24_LE,
  272. SNDRV_PCM_FORMAT_U24_BE,
  273. SNDRV_PCM_FORMAT_S32_LE,
  274. SNDRV_PCM_FORMAT_S32_BE,
  275. SNDRV_PCM_FORMAT_U32_LE,
  276. SNDRV_PCM_FORMAT_U32_BE,
  277. SNDRV_PCM_FORMAT_S8,
  278. SNDRV_PCM_FORMAT_U8
  279. };
  280. int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask)
  281. {
  282. int i;
  283. if (snd_mask_test(format_mask, format))
  284. return format;
  285. if (! snd_pcm_plug_formats(format_mask, format))
  286. return -EINVAL;
  287. if (snd_pcm_format_linear(format)) {
  288. unsigned int width = snd_pcm_format_width(format);
  289. int unsignd = snd_pcm_format_unsigned(format) > 0;
  290. int big = snd_pcm_format_big_endian(format) > 0;
  291. unsigned int badness, best = -1;
  292. int best_format = -1;
  293. for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
  294. int f = preferred_formats[i];
  295. unsigned int w;
  296. if (!snd_mask_test(format_mask, f))
  297. continue;
  298. w = snd_pcm_format_width(f);
  299. if (w >= width)
  300. badness = w - width;
  301. else
  302. badness = width - w + 32;
  303. badness += snd_pcm_format_unsigned(f) != unsignd;
  304. badness += snd_pcm_format_big_endian(f) != big;
  305. if (badness < best) {
  306. best_format = f;
  307. best = badness;
  308. }
  309. }
  310. return best_format >= 0 ? best_format : -EINVAL;
  311. } else {
  312. switch (format) {
  313. case SNDRV_PCM_FORMAT_MU_LAW:
  314. for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
  315. int format1 = preferred_formats[i];
  316. if (snd_mask_test(format_mask, format1))
  317. return format1;
  318. }
  319. default:
  320. return -EINVAL;
  321. }
  322. }
  323. }
  324. int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
  325. struct snd_pcm_hw_params *params,
  326. struct snd_pcm_hw_params *slave_params)
  327. {
  328. struct snd_pcm_plugin_format tmpformat;
  329. struct snd_pcm_plugin_format dstformat;
  330. struct snd_pcm_plugin_format srcformat;
  331. int src_access, dst_access;
  332. struct snd_pcm_plugin *plugin = NULL;
  333. int err;
  334. int stream = snd_pcm_plug_stream(plug);
  335. int slave_interleaved = (params_channels(slave_params) == 1 ||
  336. params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);
  337. switch (stream) {
  338. case SNDRV_PCM_STREAM_PLAYBACK:
  339. dstformat.format = params_format(slave_params);
  340. dstformat.rate = params_rate(slave_params);
  341. dstformat.channels = params_channels(slave_params);
  342. srcformat.format = params_format(params);
  343. srcformat.rate = params_rate(params);
  344. srcformat.channels = params_channels(params);
  345. src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
  346. dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
  347. SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
  348. break;
  349. case SNDRV_PCM_STREAM_CAPTURE:
  350. dstformat.format = params_format(params);
  351. dstformat.rate = params_rate(params);
  352. dstformat.channels = params_channels(params);
  353. srcformat.format = params_format(slave_params);
  354. srcformat.rate = params_rate(slave_params);
  355. srcformat.channels = params_channels(slave_params);
  356. src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
  357. SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
  358. dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
  359. break;
  360. default:
  361. snd_BUG();
  362. return -EINVAL;
  363. }
  364. tmpformat = srcformat;
  365. pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
  366. srcformat.format,
  367. srcformat.rate,
  368. srcformat.channels);
  369. pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
  370. dstformat.format,
  371. dstformat.rate,
  372. dstformat.channels);
  373. /* Format change (linearization) */
  374. if (! rate_match(srcformat.rate, dstformat.rate) &&
  375. ! snd_pcm_format_linear(srcformat.format)) {
  376. if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
  377. return -EINVAL;
  378. tmpformat.format = SNDRV_PCM_FORMAT_S16;
  379. err = snd_pcm_plugin_build_mulaw(plug,
  380. &srcformat, &tmpformat,
  381. &plugin);
  382. if (err < 0)
  383. return err;
  384. err = snd_pcm_plugin_append(plugin);
  385. if (err < 0) {
  386. snd_pcm_plugin_free(plugin);
  387. return err;
  388. }
  389. srcformat = tmpformat;
  390. src_access = dst_access;
  391. }
  392. /* channels reduction */
  393. if (srcformat.channels > dstformat.channels) {
  394. tmpformat.channels = dstformat.channels;
  395. err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
  396. pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
  397. if (err < 0)
  398. return err;
  399. err = snd_pcm_plugin_append(plugin);
  400. if (err < 0) {
  401. snd_pcm_plugin_free(plugin);
  402. return err;
  403. }
  404. srcformat = tmpformat;
  405. src_access = dst_access;
  406. }
  407. /* rate resampling */
  408. if (!rate_match(srcformat.rate, dstformat.rate)) {
  409. if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
  410. /* convert to S16 for resampling */
  411. tmpformat.format = SNDRV_PCM_FORMAT_S16;
  412. err = snd_pcm_plugin_build_linear(plug,
  413. &srcformat, &tmpformat,
  414. &plugin);
  415. if (err < 0)
  416. return err;
  417. err = snd_pcm_plugin_append(plugin);
  418. if (err < 0) {
  419. snd_pcm_plugin_free(plugin);
  420. return err;
  421. }
  422. srcformat = tmpformat;
  423. src_access = dst_access;
  424. }
  425. tmpformat.rate = dstformat.rate;
  426. err = snd_pcm_plugin_build_rate(plug,
  427. &srcformat, &tmpformat,
  428. &plugin);
  429. pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
  430. if (err < 0)
  431. return err;
  432. err = snd_pcm_plugin_append(plugin);
  433. if (err < 0) {
  434. snd_pcm_plugin_free(plugin);
  435. return err;
  436. }
  437. srcformat = tmpformat;
  438. src_access = dst_access;
  439. }
  440. /* format change */
  441. if (srcformat.format != dstformat.format) {
  442. tmpformat.format = dstformat.format;
  443. if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
  444. tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
  445. err = snd_pcm_plugin_build_mulaw(plug,
  446. &srcformat, &tmpformat,
  447. &plugin);
  448. }
  449. else if (snd_pcm_format_linear(srcformat.format) &&
  450. snd_pcm_format_linear(tmpformat.format)) {
  451. err = snd_pcm_plugin_build_linear(plug,
  452. &srcformat, &tmpformat,
  453. &plugin);
  454. }
  455. else
  456. return -EINVAL;
  457. pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
  458. if (err < 0)
  459. return err;
  460. err = snd_pcm_plugin_append(plugin);
  461. if (err < 0) {
  462. snd_pcm_plugin_free(plugin);
  463. return err;
  464. }
  465. srcformat = tmpformat;
  466. src_access = dst_access;
  467. }
  468. /* channels extension */
  469. if (srcformat.channels < dstformat.channels) {
  470. tmpformat.channels = dstformat.channels;
  471. err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
  472. pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
  473. if (err < 0)
  474. return err;
  475. err = snd_pcm_plugin_append(plugin);
  476. if (err < 0) {
  477. snd_pcm_plugin_free(plugin);
  478. return err;
  479. }
  480. srcformat = tmpformat;
  481. src_access = dst_access;
  482. }
  483. /* de-interleave */
  484. if (src_access != dst_access) {
  485. err = snd_pcm_plugin_build_copy(plug,
  486. &srcformat,
  487. &tmpformat,
  488. &plugin);
  489. pdprintf("interleave change (copy: returns %i)\n", err);
  490. if (err < 0)
  491. return err;
  492. err = snd_pcm_plugin_append(plugin);
  493. if (err < 0) {
  494. snd_pcm_plugin_free(plugin);
  495. return err;
  496. }
  497. }
  498. return 0;
  499. }
  500. snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug,
  501. char *buf,
  502. snd_pcm_uframes_t count,
  503. struct snd_pcm_plugin_channel **channels)
  504. {
  505. struct snd_pcm_plugin *plugin;
  506. struct snd_pcm_plugin_channel *v;
  507. struct snd_pcm_plugin_format *format;
  508. int width, nchannels, channel;
  509. int stream = snd_pcm_plug_stream(plug);
  510. snd_assert(buf != NULL, return -ENXIO);
  511. if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
  512. plugin = snd_pcm_plug_first(plug);
  513. format = &plugin->src_format;
  514. } else {
  515. plugin = snd_pcm_plug_last(plug);
  516. format = &plugin->dst_format;
  517. }
  518. v = plugin->buf_channels;
  519. *channels = v;
  520. if ((width = snd_pcm_format_physical_width(format->format)) < 0)
  521. return width;
  522. nchannels = format->channels;
  523. snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
  524. for (channel = 0; channel < nchannels; channel++, v++) {
  525. v->frames = count;
  526. v->enabled = 1;
  527. v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE);
  528. v->area.addr = buf;
  529. v->area.first = channel * width;
  530. v->area.step = nchannels * width;
  531. }
  532. return count;
  533. }
  534. snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size)
  535. {
  536. struct snd_pcm_plugin *plugin, *next;
  537. struct snd_pcm_plugin_channel *dst_channels;
  538. int err;
  539. snd_pcm_sframes_t frames = size;
  540. plugin = snd_pcm_plug_first(plug);
  541. while (plugin && frames > 0) {
  542. if ((next = plugin->next) != NULL) {
  543. snd_pcm_sframes_t frames1 = frames;
  544. if (plugin->dst_frames)
  545. frames1 = plugin->dst_frames(plugin, frames);
  546. if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
  547. return err;
  548. }
  549. if (err != frames1) {
  550. frames = err;
  551. if (plugin->src_frames)
  552. frames = plugin->src_frames(plugin, frames1);
  553. }
  554. } else
  555. dst_channels = NULL;
  556. pdprintf("write plugin: %s, %li\n", plugin->name, frames);
  557. if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
  558. return frames;
  559. src_channels = dst_channels;
  560. plugin = next;
  561. }
  562. return snd_pcm_plug_client_size(plug, frames);
  563. }
  564. snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size)
  565. {
  566. struct snd_pcm_plugin *plugin, *next;
  567. struct snd_pcm_plugin_channel *src_channels, *dst_channels;
  568. snd_pcm_sframes_t frames = size;
  569. int err;
  570. frames = snd_pcm_plug_slave_size(plug, frames);
  571. if (frames < 0)
  572. return frames;
  573. src_channels = NULL;
  574. plugin = snd_pcm_plug_first(plug);
  575. while (plugin && frames > 0) {
  576. if ((next = plugin->next) != NULL) {
  577. if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
  578. return err;
  579. }
  580. frames = err;
  581. } else {
  582. dst_channels = dst_channels_final;
  583. }
  584. pdprintf("read plugin: %s, %li\n", plugin->name, frames);
  585. if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
  586. return frames;
  587. plugin = next;
  588. src_channels = dst_channels;
  589. }
  590. return frames;
  591. }
  592. int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
  593. size_t samples, int format)
  594. {
  595. /* FIXME: sub byte resolution and odd dst_offset */
  596. unsigned char *dst;
  597. unsigned int dst_step;
  598. int width;
  599. const unsigned char *silence;
  600. if (!dst_area->addr)
  601. return 0;
  602. dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
  603. width = snd_pcm_format_physical_width(format);
  604. if (width <= 0)
  605. return -EINVAL;
  606. if (dst_area->step == (unsigned int) width && width >= 8)
  607. return snd_pcm_format_set_silence(format, dst, samples);
  608. silence = snd_pcm_format_silence_64(format);
  609. if (! silence)
  610. return -EINVAL;
  611. dst_step = dst_area->step / 8;
  612. if (width == 4) {
  613. /* Ima ADPCM */
  614. int dstbit = dst_area->first % 8;
  615. int dstbit_step = dst_area->step % 8;
  616. while (samples-- > 0) {
  617. if (dstbit)
  618. *dst &= 0xf0;
  619. else
  620. *dst &= 0x0f;
  621. dst += dst_step;
  622. dstbit += dstbit_step;
  623. if (dstbit == 8) {
  624. dst++;
  625. dstbit = 0;
  626. }
  627. }
  628. } else {
  629. width /= 8;
  630. while (samples-- > 0) {
  631. memcpy(dst, silence, width);
  632. dst += dst_step;
  633. }
  634. }
  635. return 0;
  636. }
  637. int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
  638. const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
  639. size_t samples, int format)
  640. {
  641. /* FIXME: sub byte resolution and odd dst_offset */
  642. char *src, *dst;
  643. int width;
  644. int src_step, dst_step;
  645. src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
  646. if (!src_area->addr)
  647. return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
  648. dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
  649. if (!dst_area->addr)
  650. return 0;
  651. width = snd_pcm_format_physical_width(format);
  652. if (width <= 0)
  653. return -EINVAL;
  654. if (src_area->step == (unsigned int) width &&
  655. dst_area->step == (unsigned int) width && width >= 8) {
  656. size_t bytes = samples * width / 8;
  657. memcpy(dst, src, bytes);
  658. return 0;
  659. }
  660. src_step = src_area->step / 8;
  661. dst_step = dst_area->step / 8;
  662. if (width == 4) {
  663. /* Ima ADPCM */
  664. int srcbit = src_area->first % 8;
  665. int srcbit_step = src_area->step % 8;
  666. int dstbit = dst_area->first % 8;
  667. int dstbit_step = dst_area->step % 8;
  668. while (samples-- > 0) {
  669. unsigned char srcval;
  670. if (srcbit)
  671. srcval = *src & 0x0f;
  672. else
  673. srcval = (*src & 0xf0) >> 4;
  674. if (dstbit)
  675. *dst = (*dst & 0xf0) | srcval;
  676. else
  677. *dst = (*dst & 0x0f) | (srcval << 4);
  678. src += src_step;
  679. srcbit += srcbit_step;
  680. if (srcbit == 8) {
  681. src++;
  682. srcbit = 0;
  683. }
  684. dst += dst_step;
  685. dstbit += dstbit_step;
  686. if (dstbit == 8) {
  687. dst++;
  688. dstbit = 0;
  689. }
  690. }
  691. } else {
  692. width /= 8;
  693. while (samples-- > 0) {
  694. memcpy(dst, src, width);
  695. src += src_step;
  696. dst += dst_step;
  697. }
  698. }
  699. return 0;
  700. }