📄 pcm_plugin.c
字号:
snd_pcm_plugin_free(plugin); return err; } err = snd_pcm_plugin_append(plugin); if (err < 0) { snd_pcm_plugin_free(plugin); return err; } srcformat = tmpformat; src_access = dst_access; } /* format change */ if (srcformat.format != dstformat.format) { tmpformat.format = dstformat.format; if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { err = snd_pcm_plugin_build_mulaw(plug, &srcformat, &tmpformat, &plugin); } else if (snd_pcm_format_linear(srcformat.format) && snd_pcm_format_linear(tmpformat.format)) { err = snd_pcm_plugin_build_linear(plug, &srcformat, &tmpformat, &plugin); } else return -EINVAL; pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); if (err < 0) return err; err = snd_pcm_plugin_append(plugin); if (err < 0) { snd_pcm_plugin_free(plugin); return err; } srcformat = tmpformat; src_access = dst_access; } /* de-interleave */ if (src_access != dst_access) { err = snd_pcm_plugin_build_copy(plug, &srcformat, &tmpformat, &plugin); pdprintf("interleave change (copy: returns %i)\n", err); if (err < 0) return err; err = snd_pcm_plugin_append(plugin); if (err < 0) { snd_pcm_plugin_free(plugin); return err; } } return 0;}snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug, char *buf, snd_pcm_uframes_t count, snd_pcm_plugin_channel_t **channels){ snd_pcm_plugin_t *plugin; snd_pcm_plugin_channel_t *v; snd_pcm_plugin_format_t *format; int width, nchannels, channel; int stream = snd_pcm_plug_stream(plug); snd_assert(buf != NULL, return -ENXIO); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { plugin = snd_pcm_plug_first(plug); format = &plugin->src_format; } else { plugin = snd_pcm_plug_last(plug); format = &plugin->dst_format; } v = plugin->buf_channels; *channels = v; if ((width = snd_pcm_format_physical_width(format->format)) < 0) return width; nchannels = format->channels; snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO); for (channel = 0; channel < nchannels; channel++, v++) { v->enabled = 1; v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE); v->area.addr = buf; v->area.first = channel * width; v->area.step = nchannels * width; } return count;}int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug, bitset_t *client_vmask){ snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); if (plugin == NULL) { return 0; } else { int schannels = plugin->dst_format.channels; bitset_t bs[bitset_size(schannels)]; bitset_t *srcmask; bitset_t *dstmask = bs; int err; bitset_one(dstmask, schannels); if (plugin == NULL) { bitset_and(client_vmask, dstmask, schannels); return 0; } while (1) { err = plugin->src_channels_mask(plugin, dstmask, &srcmask); if (err < 0) return err; dstmask = srcmask; if (plugin->prev == NULL) break; plugin = plugin->prev; } bitset_and(client_vmask, dstmask, plugin->src_format.channels); return 0; }}int snd_pcm_plug_capture_channels_mask(snd_pcm_plug_t *plug, bitset_t *client_vmask){ snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug); if (plugin == NULL) { return 0; } else { int schannels = plugin->src_format.channels; bitset_t bs[bitset_size(schannels)]; bitset_t *srcmask = bs; bitset_t *dstmask; int err; bitset_one(srcmask, schannels); while (1) { err = plugin->dst_channels_mask(plugin, srcmask, &dstmask); if (err < 0) return err; srcmask = dstmask; if (plugin->next == NULL) break; plugin = plugin->next; } bitset_and(client_vmask, srcmask, plugin->dst_format.channels); return 0; }}static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels){ snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug); unsigned int nchannels = plugin->src_format.channels; bitset_t bs[bitset_size(nchannels)]; bitset_t *srcmask = bs; int err; unsigned int channel; for (channel = 0; channel < nchannels; channel++) { if (src_channels[channel].enabled) bitset_set(srcmask, channel); else bitset_reset(srcmask, channel); } err = snd_pcm_plug_playback_channels_mask(plug, srcmask); if (err < 0) return err; for (channel = 0; channel < nchannels; channel++) { if (!bitset_get(srcmask, channel)) src_channels[channel].enabled = 0; } return 0;}static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, snd_pcm_plugin_channel_t *client_channels){ snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); unsigned int nchannels = plugin->dst_format.channels; bitset_t bs[bitset_size(nchannels)]; bitset_t *dstmask = bs; bitset_t *srcmask; int err; unsigned int channel; for (channel = 0; channel < nchannels; channel++) { if (client_channels[channel].enabled) bitset_set(dstmask, channel); else bitset_reset(dstmask, channel); } while (plugin) { err = plugin->src_channels_mask(plugin, dstmask, &srcmask); if (err < 0) return err; dstmask = srcmask; plugin = plugin->prev; } plugin = snd_pcm_plug_first(plug); nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; channel++) { if (!bitset_get(dstmask, channel)) src_channels[channel].enabled = 0; } return 0;}snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size){ snd_pcm_plugin_t *plugin, *next; snd_pcm_plugin_channel_t *dst_channels; int err; snd_pcm_sframes_t frames = size; if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0) return err; plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { if ((next = plugin->next) != NULL) { snd_pcm_sframes_t frames1 = frames; if (plugin->dst_frames) frames1 = plugin->dst_frames(plugin, frames); if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { return err; } if (err != frames1) { frames = err; if (plugin->src_frames) frames = plugin->src_frames(plugin, frames1); } } else dst_channels = 0; pdprintf("write plugin: %s, %li\n", plugin->name, frames); if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) return frames; src_channels = dst_channels; plugin = next; } return snd_pcm_plug_client_size(plug, frames);}snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size){ snd_pcm_plugin_t *plugin, *next; snd_pcm_plugin_channel_t *src_channels, *dst_channels; snd_pcm_sframes_t frames = size; int err; frames = snd_pcm_plug_slave_size(plug, frames); if (frames < 0) return frames; src_channels = 0; plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { if ((next = plugin->next) != NULL) { if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { return err; } frames = err; if (!plugin->prev) { if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final) < 0)) return err; } } else { dst_channels = dst_channels_final; } pdprintf("read plugin: %s, %li\n", plugin->name, frames); if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) return frames; plugin = next; src_channels = dst_channels; } return frames;}int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset, size_t samples, int format){ /* FIXME: sub byte resolution and odd dst_offset */ char *dst; unsigned int dst_step; int width; u_int64_t silence; if (!dst_area->addr) return 0; dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; width = snd_pcm_format_physical_width(format); silence = snd_pcm_format_silence_64(format); if (dst_area->step == (unsigned int) width) { size_t dwords = samples * width / 64; samples -= dwords * 64 / width; while (dwords-- > 0) *((u_int64_t*)dst)++ = silence; if (samples == 0) return 0; } dst_step = dst_area->step / 8; switch (width) { case 4: { u_int8_t s0 = silence & 0xf0; u_int8_t s1 = silence & 0x0f; int dstbit = dst_area->first % 8; int dstbit_step = dst_area->step % 8; while (samples-- > 0) { if (dstbit) { *dst &= 0xf0; *dst |= s1; } else { *dst &= 0x0f; *dst |= s0; } dst += dst_step; dstbit += dstbit_step; if (dstbit == 8) { dst++; dstbit = 0; } } break; } case 8: { u_int8_t sil = silence; while (samples-- > 0) { *dst = sil; dst += dst_step; } break; } case 16: { u_int16_t sil = silence; while (samples-- > 0) { *(u_int16_t*)dst = sil; dst += dst_step; } break; } case 32: { u_int32_t sil = silence; while (samples-- > 0) { *(u_int32_t*)dst = sil; dst += dst_step; } break; } case 64: { while (samples-- > 0) { *(u_int64_t*)dst = silence; dst += dst_step; } break; } default: snd_BUG(); } return 0;}int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, unsigned int channels, snd_pcm_uframes_t frames, int format){ int width = snd_pcm_format_physical_width(format); while (channels > 0) { void *addr = dst_areas->addr; unsigned int step = dst_areas->step; const snd_pcm_channel_area_t *begin = dst_areas; int vc = channels; unsigned int v = 0; int err; while (1) { vc--; v++; dst_areas++; if (vc == 0 || dst_areas->addr != addr || dst_areas->step != step || dst_areas->first != dst_areas[-1].first + width) break; } if (v > 1 && v * width == step) { /* Collapse the areas */ snd_pcm_channel_area_t d; d.addr = begin->addr; d.first = begin->first; d.step = width; err = snd_pcm_area_silence(&d, dst_offset * v, frames * v, format); channels -= v; } else { err = snd_pcm_area_silence(begin, dst_offset, frames, format); dst_areas = begin + 1; channels--; } if (err < 0) return err; } return 0;}int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset, const snd_pcm_channel_area_t *dst_area, size_t dst_offset, size_t samples, int format){ /* FIXME: sub byte resolution and odd dst_offset */ char *src, *dst; int width; int src_step, dst_step; src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; if (!src_area->addr) return snd_pcm_area_silence(dst_area, dst_offset, samples, format); dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; if (!dst_area->addr) return 0; width = snd_pcm_format_physical_width(format); if (src_area->step == (unsigned int) width && dst_area->step == (unsigned int) width) { size_t bytes = samples * width / 8; samples -= bytes * 8 / width; memcpy(dst, src, bytes); if (samples == 0) return 0; } src_step = src_area->step / 8; dst_step = dst_area->step / 8; switch (width) { case 4: { int srcbit = src_area->first % 8; int srcbit_step = src_area->step % 8; int dstbit = dst_area->first % 8; int dstbit_step = dst_area->step % 8; while (samples-- > 0) { unsigned char srcval; if (srcbit) srcval = *src & 0x0f; else srcval = *src & 0xf0; if (dstbit) *dst &= 0xf0; else *dst &= 0x0f; *dst |= srcval; src += src_step; srcbit += srcbit_step; if (srcbit == 8) { src++; srcbit = 0; } dst += dst_step; dstbit += dstbit_step; if (dstbit == 8) { dst++; dstbit = 0; } } break; } case 8: { while (samples-- > 0) { *dst = *src; src += src_step; dst += dst_step; } break; } case 16: { while (samples-- > 0) { *(u_int16_t*)dst = *(u_int16_t*)src; src += src_step; dst += dst_step; } break; } case 32: { while (samples-- > 0) { *(u_int32_t*)dst = *(u_int32_t*)src; src += src_step; dst += dst_step; } break; } case 64: { while (samples-- > 0) { *(u_int64_t*)dst = *(u_int64_t*)src; src += src_step; dst += dst_step; } break; } default: snd_BUG(); } return 0;}int snd_pcm_areas_copy(const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, unsigned int channels, snd_pcm_uframes_t frames, int format){ int width = snd_pcm_format_physical_width(format); while (channels > 0) { unsigned int step = src_areas->step; void *src_addr = src_areas->addr; const snd_pcm_channel_area_t *src_start = src_areas; void *dst_addr = dst_areas->addr; const snd_pcm_channel_area_t *dst_start = dst_areas; int vc = channels; unsigned int v = 0; while (dst_areas->step == step) { vc--; v++; src_areas++; dst_areas++; if (vc == 0 || src_areas->step != step || src_areas->addr != src_addr || dst_areas->addr != dst_addr || src_areas->first != src_areas[-1].first + width || dst_areas->first != dst_areas[-1].first + width) break; } if (v > 1 && v * width == step) { /* Collapse the areas */ snd_pcm_channel_area_t s, d; s.addr = src_start->addr; s.first = src_start->first; s.step = width; d.addr = dst_start->addr; d.first = dst_start->first; d.step = width; snd_pcm_area_copy(&s, src_offset * v, &d, dst_offset * v, frames * v, format); channels -= v; } else { snd_pcm_area_copy(src_start, src_offset, dst_start, dst_offset, frames, format); src_areas = src_start + 1; dst_areas = dst_start + 1; channels--; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -