buffer.c revision 267581
1/*- 2 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 3 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 4 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#ifdef HAVE_KERNEL_OPTION_HEADERS 30#include "opt_snd.h" 31#endif 32 33#include <dev/sound/pcm/sound.h> 34 35#include "feeder_if.h" 36 37#define SND_USE_FXDIV 38#include "snd_fxdiv_gen.h" 39 40SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/buffer.c 267581 2014-06-17 16:07:57Z jhb $"); 41 42struct snd_dbuf * 43sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel) 44{ 45 struct snd_dbuf *b; 46 47 b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); 48 snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc); 49 b->dev = dev; 50 b->channel = channel; 51 52 return b; 53} 54 55void 56sndbuf_destroy(struct snd_dbuf *b) 57{ 58 sndbuf_free(b); 59 free(b, M_DEVBUF); 60} 61 62bus_addr_t 63sndbuf_getbufaddr(struct snd_dbuf *buf) 64{ 65 return (buf->buf_addr); 66} 67 68static void 69sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 70{ 71 struct snd_dbuf *b = (struct snd_dbuf *)arg; 72 73 if (snd_verbose > 3) { 74 device_printf(b->dev, "sndbuf_setmap %lx, %lx; ", 75 (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len); 76 printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr); 77 } 78 if (error == 0) 79 b->buf_addr = segs[0].ds_addr; 80 else 81 b->buf_addr = 0; 82} 83 84/* 85 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 86 * the driver can call malloc(9) and sndbuf_setup() itself. 87 */ 88 89int 90sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags, 91 unsigned int size) 92{ 93 int ret; 94 95 b->dmatag = dmatag; 96 b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT; 97 b->maxsize = size; 98 b->bufsize = b->maxsize; 99 b->buf_addr = 0; 100 b->flags |= SNDBUF_F_MANAGED; 101 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags, 102 &b->dmamap)) { 103 sndbuf_free(b); 104 return (ENOMEM); 105 } 106 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, 107 sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) { 108 sndbuf_free(b); 109 return (ENOMEM); 110 } 111 112 ret = sndbuf_resize(b, 2, b->maxsize / 2); 113 if (ret != 0) 114 sndbuf_free(b); 115 116 return (ret); 117} 118 119int 120sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 121{ 122 b->flags &= ~SNDBUF_F_MANAGED; 123 if (buf) 124 b->flags |= SNDBUF_F_MANAGED; 125 b->buf = buf; 126 b->maxsize = size; 127 b->bufsize = b->maxsize; 128 return sndbuf_resize(b, 2, b->maxsize / 2); 129} 130 131void 132sndbuf_free(struct snd_dbuf *b) 133{ 134 if (b->tmpbuf) 135 free(b->tmpbuf, M_DEVBUF); 136 137 if (b->shadbuf) 138 free(b->shadbuf, M_DEVBUF); 139 140 if (b->buf) { 141 if (b->flags & SNDBUF_F_MANAGED) { 142 if (b->buf_addr) 143 bus_dmamap_unload(b->dmatag, b->dmamap); 144 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 145 } else 146 free(b->buf, M_DEVBUF); 147 } 148 149 b->tmpbuf = NULL; 150 b->shadbuf = NULL; 151 b->buf = NULL; 152 b->sl = 0; 153 b->dmatag = NULL; 154 b->dmamap = NULL; 155} 156 157#define SNDBUF_CACHE_SHIFT 5 158 159int 160sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 161{ 162 unsigned int bufsize, allocsize; 163 u_int8_t *tmpbuf; 164 165 CHN_LOCK(b->channel); 166 if (b->maxsize == 0) 167 goto out; 168 if (blkcnt == 0) 169 blkcnt = b->blkcnt; 170 if (blksz == 0) 171 blksz = b->blksz; 172 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) { 173 CHN_UNLOCK(b->channel); 174 return EINVAL; 175 } 176 if (blkcnt == b->blkcnt && blksz == b->blksz) 177 goto out; 178 179 bufsize = blkcnt * blksz; 180 181 if (bufsize > b->allocsize || 182 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 183 allocsize = round_page(bufsize); 184 CHN_UNLOCK(b->channel); 185 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 186 CHN_LOCK(b->channel); 187 if (snd_verbose > 3) 188 printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n", 189 __func__, b, b->tmpbuf, tmpbuf, 190 b->allocsize, allocsize, bufsize); 191 if (b->tmpbuf != NULL) 192 free(b->tmpbuf, M_DEVBUF); 193 b->tmpbuf = tmpbuf; 194 b->allocsize = allocsize; 195 } else if (snd_verbose > 3) 196 printf("%s(): b=%p %d [%d] NOCHANGE\n", 197 __func__, b, b->allocsize, b->bufsize); 198 199 b->blkcnt = blkcnt; 200 b->blksz = blksz; 201 b->bufsize = bufsize; 202 203 sndbuf_reset(b); 204out: 205 CHN_UNLOCK(b->channel); 206 return 0; 207} 208 209int 210sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 211{ 212 unsigned int bufsize, allocsize; 213 u_int8_t *buf, *tmpbuf, *shadbuf; 214 215 if (blkcnt < 2 || blksz < 16) 216 return EINVAL; 217 218 bufsize = blksz * blkcnt; 219 220 if (bufsize > b->allocsize || 221 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 222 allocsize = round_page(bufsize); 223 CHN_UNLOCK(b->channel); 224 buf = malloc(allocsize, M_DEVBUF, M_WAITOK); 225 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 226 shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 227 CHN_LOCK(b->channel); 228 if (b->buf != NULL) 229 free(b->buf, M_DEVBUF); 230 b->buf = buf; 231 if (b->tmpbuf != NULL) 232 free(b->tmpbuf, M_DEVBUF); 233 b->tmpbuf = tmpbuf; 234 if (b->shadbuf != NULL) 235 free(b->shadbuf, M_DEVBUF); 236 b->shadbuf = shadbuf; 237 if (snd_verbose > 3) 238 printf("%s(): b=%p %d -> %d [%d]\n", 239 __func__, b, b->allocsize, allocsize, bufsize); 240 b->allocsize = allocsize; 241 } else if (snd_verbose > 3) 242 printf("%s(): b=%p %d [%d] NOCHANGE\n", 243 __func__, b, b->allocsize, b->bufsize); 244 245 b->blkcnt = blkcnt; 246 b->blksz = blksz; 247 b->bufsize = bufsize; 248 b->maxsize = bufsize; 249 b->sl = bufsize; 250 251 sndbuf_reset(b); 252 253 return 0; 254} 255 256/** 257 * @brief Zero out space in buffer free area 258 * 259 * This function clears a chunk of @c length bytes in the buffer free area 260 * (i.e., where the next write will be placed). 261 * 262 * @param b buffer context 263 * @param length number of bytes to blank 264 */ 265void 266sndbuf_clear(struct snd_dbuf *b, unsigned int length) 267{ 268 int i; 269 u_char data, *p; 270 271 if (length == 0) 272 return; 273 if (length > b->bufsize) 274 length = b->bufsize; 275 276 data = sndbuf_zerodata(b->fmt); 277 278 i = sndbuf_getfreeptr(b); 279 p = sndbuf_getbuf(b); 280 while (length > 0) { 281 p[i] = data; 282 length--; 283 i++; 284 if (i >= b->bufsize) 285 i = 0; 286 } 287} 288 289/** 290 * @brief Zap buffer contents, resetting "ready area" fields 291 * 292 * @param b buffer context 293 */ 294void 295sndbuf_fillsilence(struct snd_dbuf *b) 296{ 297 if (b->bufsize > 0) 298 memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 299 b->rp = 0; 300 b->rl = b->bufsize; 301} 302 303void 304sndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl) 305{ 306 if (b->bufsize > 0) 307 memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 308 b->rp = 0; 309 b->rl = min(b->bufsize, rl); 310} 311 312/** 313 * @brief Reset buffer w/o flushing statistics 314 * 315 * This function just zeroes out buffer contents and sets the "ready length" 316 * to zero. This was originally to facilitate minimal playback interruption 317 * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls. 318 * 319 * @param b buffer context 320 */ 321void 322sndbuf_softreset(struct snd_dbuf *b) 323{ 324 b->rl = 0; 325 if (b->buf && b->bufsize > 0) 326 sndbuf_clear(b, b->bufsize); 327} 328 329void 330sndbuf_reset(struct snd_dbuf *b) 331{ 332 b->hp = 0; 333 b->rp = 0; 334 b->rl = 0; 335 b->dl = 0; 336 b->prev_total = 0; 337 b->total = 0; 338 b->xrun = 0; 339 if (b->buf && b->bufsize > 0) 340 sndbuf_clear(b, b->bufsize); 341 sndbuf_clearshadow(b); 342} 343 344u_int32_t 345sndbuf_getfmt(struct snd_dbuf *b) 346{ 347 return b->fmt; 348} 349 350int 351sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 352{ 353 b->fmt = fmt; 354 b->bps = AFMT_BPS(b->fmt); 355 b->align = AFMT_ALIGN(b->fmt); 356#if 0 357 b->bps = AFMT_CHANNEL(b->fmt); 358 if (b->fmt & AFMT_16BIT) 359 b->bps <<= 1; 360 else if (b->fmt & AFMT_24BIT) 361 b->bps *= 3; 362 else if (b->fmt & AFMT_32BIT) 363 b->bps <<= 2; 364#endif 365 return 0; 366} 367 368unsigned int 369sndbuf_getspd(struct snd_dbuf *b) 370{ 371 return b->spd; 372} 373 374void 375sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 376{ 377 b->spd = spd; 378} 379 380unsigned int 381sndbuf_getalign(struct snd_dbuf *b) 382{ 383 return (b->align); 384} 385 386unsigned int 387sndbuf_getblkcnt(struct snd_dbuf *b) 388{ 389 return b->blkcnt; 390} 391 392void 393sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 394{ 395 b->blkcnt = blkcnt; 396} 397 398unsigned int 399sndbuf_getblksz(struct snd_dbuf *b) 400{ 401 return b->blksz; 402} 403 404void 405sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 406{ 407 b->blksz = blksz; 408} 409 410unsigned int 411sndbuf_getbps(struct snd_dbuf *b) 412{ 413 return b->bps; 414} 415 416void * 417sndbuf_getbuf(struct snd_dbuf *b) 418{ 419 return b->buf; 420} 421 422void * 423sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 424{ 425 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 426 427 return b->buf + ofs; 428} 429 430unsigned int 431sndbuf_getsize(struct snd_dbuf *b) 432{ 433 return b->bufsize; 434} 435 436unsigned int 437sndbuf_getmaxsize(struct snd_dbuf *b) 438{ 439 return b->maxsize; 440} 441 442unsigned int 443sndbuf_getallocsize(struct snd_dbuf *b) 444{ 445 return b->allocsize; 446} 447 448unsigned int 449sndbuf_runsz(struct snd_dbuf *b) 450{ 451 return b->dl; 452} 453 454void 455sndbuf_setrun(struct snd_dbuf *b, int go) 456{ 457 b->dl = go? b->blksz : 0; 458} 459 460struct selinfo * 461sndbuf_getsel(struct snd_dbuf *b) 462{ 463 return &b->sel; 464} 465 466/************************************************************/ 467unsigned int 468sndbuf_getxrun(struct snd_dbuf *b) 469{ 470 SNDBUF_LOCKASSERT(b); 471 472 return b->xrun; 473} 474 475void 476sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 477{ 478 SNDBUF_LOCKASSERT(b); 479 480 b->xrun = xrun; 481} 482 483unsigned int 484sndbuf_gethwptr(struct snd_dbuf *b) 485{ 486 SNDBUF_LOCKASSERT(b); 487 488 return b->hp; 489} 490 491void 492sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 493{ 494 SNDBUF_LOCKASSERT(b); 495 496 b->hp = ptr; 497} 498 499unsigned int 500sndbuf_getready(struct snd_dbuf *b) 501{ 502 SNDBUF_LOCKASSERT(b); 503 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 504 505 return b->rl; 506} 507 508unsigned int 509sndbuf_getreadyptr(struct snd_dbuf *b) 510{ 511 SNDBUF_LOCKASSERT(b); 512 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 513 514 return b->rp; 515} 516 517unsigned int 518sndbuf_getfree(struct snd_dbuf *b) 519{ 520 SNDBUF_LOCKASSERT(b); 521 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 522 523 return b->bufsize - b->rl; 524} 525 526unsigned int 527sndbuf_getfreeptr(struct snd_dbuf *b) 528{ 529 SNDBUF_LOCKASSERT(b); 530 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 531 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 532 533 return (b->rp + b->rl) % b->bufsize; 534} 535 536u_int64_t 537sndbuf_getblocks(struct snd_dbuf *b) 538{ 539 SNDBUF_LOCKASSERT(b); 540 541 return b->total / b->blksz; 542} 543 544u_int64_t 545sndbuf_getprevblocks(struct snd_dbuf *b) 546{ 547 SNDBUF_LOCKASSERT(b); 548 549 return b->prev_total / b->blksz; 550} 551 552u_int64_t 553sndbuf_gettotal(struct snd_dbuf *b) 554{ 555 SNDBUF_LOCKASSERT(b); 556 557 return b->total; 558} 559 560u_int64_t 561sndbuf_getprevtotal(struct snd_dbuf *b) 562{ 563 SNDBUF_LOCKASSERT(b); 564 565 return b->prev_total; 566} 567 568void 569sndbuf_updateprevtotal(struct snd_dbuf *b) 570{ 571 SNDBUF_LOCKASSERT(b); 572 573 b->prev_total = b->total; 574} 575 576unsigned int 577sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 578{ 579 if (from == NULL || to == NULL || v == 0) 580 return 0; 581 582 return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from), 583 sndbuf_getalign(to) * sndbuf_getspd(to)); 584} 585 586u_int8_t 587sndbuf_zerodata(u_int32_t fmt) 588{ 589 if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 590 return (0x00); 591 else if (fmt & AFMT_MU_LAW) 592 return (0x7f); 593 else if (fmt & AFMT_A_LAW) 594 return (0x55); 595 return (0x80); 596} 597 598/************************************************************/ 599 600/** 601 * @brief Acquire buffer space to extend ready area 602 * 603 * This function extends the ready area length by @c count bytes, and may 604 * optionally copy samples from another location stored in @c from. The 605 * counter @c snd_dbuf::total is also incremented by @c count bytes. 606 * 607 * @param b audio buffer 608 * @param from sample source (optional) 609 * @param count number of bytes to acquire 610 * 611 * @retval 0 Unconditional 612 */ 613int 614sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 615{ 616 int l; 617 618 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 619 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 620 b->total += count; 621 if (from != NULL) { 622 while (count > 0) { 623 l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 624 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 625 from += l; 626 b->rl += l; 627 count -= l; 628 } 629 } else 630 b->rl += count; 631 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 632 633 return 0; 634} 635 636/** 637 * @brief Dispose samples from channel buffer, increasing size of ready area 638 * 639 * This function discards samples from the supplied buffer by advancing the 640 * ready area start pointer and decrementing the ready area length. If 641 * @c to is not NULL, then the discard samples will be copied to the location 642 * it points to. 643 * 644 * @param b PCM channel sound buffer 645 * @param to destination buffer (optional) 646 * @param count number of bytes to discard 647 * 648 * @returns 0 unconditionally 649 */ 650int 651sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 652{ 653 int l; 654 655 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 656 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 657 if (to != NULL) { 658 while (count > 0) { 659 l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 660 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 661 to += l; 662 b->rl -= l; 663 b->rp = (b->rp + l) % b->bufsize; 664 count -= l; 665 } 666 } else { 667 b->rl -= count; 668 b->rp = (b->rp + count) % b->bufsize; 669 } 670 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 671 672 return 0; 673} 674 675#ifdef SND_DIAGNOSTIC 676static uint32_t snd_feeder_maxfeed = 0; 677SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD, 678 &snd_feeder_maxfeed, 0, "maximum feeder count request"); 679 680static uint32_t snd_feeder_maxcycle = 0; 681SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD, 682 &snd_feeder_maxcycle, 0, "maximum feeder cycle"); 683#endif 684 685/* count is number of bytes we want added to destination buffer */ 686int 687sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 688{ 689 unsigned int cnt, maxfeed; 690#ifdef SND_DIAGNOSTIC 691 unsigned int cycle; 692 693 if (count > snd_feeder_maxfeed) 694 snd_feeder_maxfeed = count; 695 696 cycle = 0; 697#endif 698 699 KASSERT(count > 0, ("can't feed 0 bytes")); 700 701 if (sndbuf_getfree(to) < count) 702 return (EINVAL); 703 704 maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to)); 705 706 do { 707 cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 708 min(count, maxfeed), from); 709 if (cnt == 0) 710 break; 711 sndbuf_acquire(to, to->tmpbuf, cnt); 712 count -= cnt; 713#ifdef SND_DIAGNOSTIC 714 cycle++; 715#endif 716 } while (count != 0); 717 718#ifdef SND_DIAGNOSTIC 719 if (cycle > snd_feeder_maxcycle) 720 snd_feeder_maxcycle = cycle; 721#endif 722 723 return (0); 724} 725 726/************************************************************/ 727 728void 729sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 730{ 731 printf("%s: [", s); 732 if (what & 0x01) 733 printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 734 if (what & 0x02) 735 printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 736 if (what & 0x04) 737 printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun); 738 if (what & 0x08) 739 printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 740 if (what & 0x10) 741 printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 742 printf(" ]\n"); 743} 744 745/************************************************************/ 746u_int32_t 747sndbuf_getflags(struct snd_dbuf *b) 748{ 749 return b->flags; 750} 751 752void 753sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 754{ 755 b->flags &= ~flags; 756 if (on) 757 b->flags |= flags; 758} 759 760/** 761 * @brief Clear the shadow buffer by filling with samples equal to zero. 762 * 763 * @param b buffer to clear 764 */ 765void 766sndbuf_clearshadow(struct snd_dbuf *b) 767{ 768 KASSERT(b != NULL, ("b is a null pointer")); 769 KASSERT(b->sl >= 0, ("illegal shadow length")); 770 771 if ((b->shadbuf != NULL) && (b->sl > 0)) 772 memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 773} 774 775#ifdef OSSV4_EXPERIMENT 776/** 777 * @brief Return peak value from samples in buffer ready area. 778 * 779 * Peak ranges from 0-32767. If channel is monaural, most significant 16 780 * bits will be zero. For now, only expects to work with 1-2 channel 781 * buffers. 782 * 783 * @note Currently only operates with linear PCM formats. 784 * 785 * @param b buffer to analyze 786 * @param lpeak pointer to store left peak value 787 * @param rpeak pointer to store right peak value 788 */ 789void 790sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 791{ 792 u_int32_t lpeak, rpeak; 793 794 lpeak = 0; 795 rpeak = 0; 796 797 /** 798 * @todo fill this in later 799 */ 800} 801#endif 802