buffer.c revision 217368
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 217368 2011-01-13 18:20:27Z mdf $"); 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 (bootverbose) { 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; 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->dmamap) 143 bus_dmamap_unload(b->dmatag, b->dmamap); 144 if (b->dmatag) 145 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 146 } else 147 free(b->buf, M_DEVBUF); 148 } 149 150 b->tmpbuf = NULL; 151 b->shadbuf = NULL; 152 b->buf = NULL; 153 b->sl = 0; 154 b->dmatag = NULL; 155 b->dmamap = NULL; 156} 157 158#define SNDBUF_CACHE_SHIFT 5 159 160int 161sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 162{ 163 unsigned int bufsize, allocsize; 164 u_int8_t *tmpbuf; 165 166 CHN_LOCK(b->channel); 167 if (b->maxsize == 0) 168 goto out; 169 if (blkcnt == 0) 170 blkcnt = b->blkcnt; 171 if (blksz == 0) 172 blksz = b->blksz; 173 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) { 174 CHN_UNLOCK(b->channel); 175 return EINVAL; 176 } 177 if (blkcnt == b->blkcnt && blksz == b->blksz) 178 goto out; 179 180 bufsize = blkcnt * blksz; 181 182 if (bufsize > b->allocsize || 183 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 184 allocsize = round_page(bufsize); 185 CHN_UNLOCK(b->channel); 186 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 187 CHN_LOCK(b->channel); 188 if (snd_verbose > 3) 189 printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n", 190 __func__, b, b->tmpbuf, tmpbuf, 191 b->allocsize, allocsize, bufsize); 192 if (b->tmpbuf != NULL) 193 free(b->tmpbuf, M_DEVBUF); 194 b->tmpbuf = tmpbuf; 195 b->allocsize = allocsize; 196 } else if (snd_verbose > 3) 197 printf("%s(): b=%p %d [%d] NOCHANGE\n", 198 __func__, b, b->allocsize, b->bufsize); 199 200 b->blkcnt = blkcnt; 201 b->blksz = blksz; 202 b->bufsize = bufsize; 203 204 sndbuf_reset(b); 205out: 206 CHN_UNLOCK(b->channel); 207 return 0; 208} 209 210int 211sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 212{ 213 unsigned int bufsize, allocsize; 214 u_int8_t *buf, *tmpbuf, *shadbuf; 215 216 if (blkcnt < 2 || blksz < 16) 217 return EINVAL; 218 219 bufsize = blksz * blkcnt; 220 221 if (bufsize > b->allocsize || 222 bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) { 223 allocsize = round_page(bufsize); 224 CHN_UNLOCK(b->channel); 225 buf = malloc(allocsize, M_DEVBUF, M_WAITOK); 226 tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 227 shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK); 228 CHN_LOCK(b->channel); 229 if (b->buf != NULL) 230 free(b->buf, M_DEVBUF); 231 b->buf = buf; 232 if (b->tmpbuf != NULL) 233 free(b->tmpbuf, M_DEVBUF); 234 b->tmpbuf = tmpbuf; 235 if (b->shadbuf != NULL) 236 free(b->shadbuf, M_DEVBUF); 237 b->shadbuf = shadbuf; 238 if (snd_verbose > 3) 239 printf("%s(): b=%p %d -> %d [%d]\n", 240 __func__, b, b->allocsize, allocsize, bufsize); 241 b->allocsize = allocsize; 242 } else if (snd_verbose > 3) 243 printf("%s(): b=%p %d [%d] NOCHANGE\n", 244 __func__, b, b->allocsize, b->bufsize); 245 246 b->blkcnt = blkcnt; 247 b->blksz = blksz; 248 b->bufsize = bufsize; 249 b->maxsize = bufsize; 250 b->sl = bufsize; 251 252 sndbuf_reset(b); 253 254 return 0; 255} 256 257/** 258 * @brief Zero out space in buffer free area 259 * 260 * This function clears a chunk of @c length bytes in the buffer free area 261 * (i.e., where the next write will be placed). 262 * 263 * @param b buffer context 264 * @param length number of bytes to blank 265 */ 266void 267sndbuf_clear(struct snd_dbuf *b, unsigned int length) 268{ 269 int i; 270 u_char data, *p; 271 272 if (length == 0) 273 return; 274 if (length > b->bufsize) 275 length = b->bufsize; 276 277 data = sndbuf_zerodata(b->fmt); 278 279 i = sndbuf_getfreeptr(b); 280 p = sndbuf_getbuf(b); 281 while (length > 0) { 282 p[i] = data; 283 length--; 284 i++; 285 if (i >= b->bufsize) 286 i = 0; 287 } 288} 289 290/** 291 * @brief Zap buffer contents, resetting "ready area" fields 292 * 293 * @param b buffer context 294 */ 295void 296sndbuf_fillsilence(struct snd_dbuf *b) 297{ 298 if (b->bufsize > 0) 299 memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize); 300 b->rp = 0; 301 b->rl = b->bufsize; 302} 303 304/** 305 * @brief Reset buffer w/o flushing statistics 306 * 307 * This function just zeroes out buffer contents and sets the "ready length" 308 * to zero. This was originally to facilitate minimal playback interruption 309 * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls. 310 * 311 * @param b buffer context 312 */ 313void 314sndbuf_softreset(struct snd_dbuf *b) 315{ 316 b->rl = 0; 317 if (b->buf && b->bufsize > 0) 318 sndbuf_clear(b, b->bufsize); 319} 320 321void 322sndbuf_reset(struct snd_dbuf *b) 323{ 324 b->hp = 0; 325 b->rp = 0; 326 b->rl = 0; 327 b->dl = 0; 328 b->prev_total = 0; 329 b->total = 0; 330 b->xrun = 0; 331 if (b->buf && b->bufsize > 0) 332 sndbuf_clear(b, b->bufsize); 333 sndbuf_clearshadow(b); 334} 335 336u_int32_t 337sndbuf_getfmt(struct snd_dbuf *b) 338{ 339 return b->fmt; 340} 341 342int 343sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 344{ 345 b->fmt = fmt; 346 b->bps = AFMT_BPS(b->fmt); 347 b->align = AFMT_ALIGN(b->fmt); 348#if 0 349 b->bps = AFMT_CHANNEL(b->fmt); 350 if (b->fmt & AFMT_16BIT) 351 b->bps <<= 1; 352 else if (b->fmt & AFMT_24BIT) 353 b->bps *= 3; 354 else if (b->fmt & AFMT_32BIT) 355 b->bps <<= 2; 356#endif 357 return 0; 358} 359 360unsigned int 361sndbuf_getspd(struct snd_dbuf *b) 362{ 363 return b->spd; 364} 365 366void 367sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 368{ 369 b->spd = spd; 370} 371 372unsigned int 373sndbuf_getalign(struct snd_dbuf *b) 374{ 375 return (b->align); 376} 377 378unsigned int 379sndbuf_getblkcnt(struct snd_dbuf *b) 380{ 381 return b->blkcnt; 382} 383 384void 385sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 386{ 387 b->blkcnt = blkcnt; 388} 389 390unsigned int 391sndbuf_getblksz(struct snd_dbuf *b) 392{ 393 return b->blksz; 394} 395 396void 397sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 398{ 399 b->blksz = blksz; 400} 401 402unsigned int 403sndbuf_getbps(struct snd_dbuf *b) 404{ 405 return b->bps; 406} 407 408void * 409sndbuf_getbuf(struct snd_dbuf *b) 410{ 411 return b->buf; 412} 413 414void * 415sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 416{ 417 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 418 419 return b->buf + ofs; 420} 421 422unsigned int 423sndbuf_getsize(struct snd_dbuf *b) 424{ 425 return b->bufsize; 426} 427 428unsigned int 429sndbuf_getmaxsize(struct snd_dbuf *b) 430{ 431 return b->maxsize; 432} 433 434unsigned int 435sndbuf_getallocsize(struct snd_dbuf *b) 436{ 437 return b->allocsize; 438} 439 440unsigned int 441sndbuf_runsz(struct snd_dbuf *b) 442{ 443 return b->dl; 444} 445 446void 447sndbuf_setrun(struct snd_dbuf *b, int go) 448{ 449 b->dl = go? b->blksz : 0; 450} 451 452struct selinfo * 453sndbuf_getsel(struct snd_dbuf *b) 454{ 455 return &b->sel; 456} 457 458/************************************************************/ 459unsigned int 460sndbuf_getxrun(struct snd_dbuf *b) 461{ 462 SNDBUF_LOCKASSERT(b); 463 464 return b->xrun; 465} 466 467void 468sndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun) 469{ 470 SNDBUF_LOCKASSERT(b); 471 472 b->xrun = xrun; 473} 474 475unsigned int 476sndbuf_gethwptr(struct snd_dbuf *b) 477{ 478 SNDBUF_LOCKASSERT(b); 479 480 return b->hp; 481} 482 483void 484sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 485{ 486 SNDBUF_LOCKASSERT(b); 487 488 b->hp = ptr; 489} 490 491unsigned int 492sndbuf_getready(struct snd_dbuf *b) 493{ 494 SNDBUF_LOCKASSERT(b); 495 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 496 497 return b->rl; 498} 499 500unsigned int 501sndbuf_getreadyptr(struct snd_dbuf *b) 502{ 503 SNDBUF_LOCKASSERT(b); 504 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 505 506 return b->rp; 507} 508 509unsigned int 510sndbuf_getfree(struct snd_dbuf *b) 511{ 512 SNDBUF_LOCKASSERT(b); 513 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 514 515 return b->bufsize - b->rl; 516} 517 518unsigned int 519sndbuf_getfreeptr(struct snd_dbuf *b) 520{ 521 SNDBUF_LOCKASSERT(b); 522 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 523 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 524 525 return (b->rp + b->rl) % b->bufsize; 526} 527 528u_int64_t 529sndbuf_getblocks(struct snd_dbuf *b) 530{ 531 SNDBUF_LOCKASSERT(b); 532 533 return b->total / b->blksz; 534} 535 536u_int64_t 537sndbuf_getprevblocks(struct snd_dbuf *b) 538{ 539 SNDBUF_LOCKASSERT(b); 540 541 return b->prev_total / b->blksz; 542} 543 544u_int64_t 545sndbuf_gettotal(struct snd_dbuf *b) 546{ 547 SNDBUF_LOCKASSERT(b); 548 549 return b->total; 550} 551 552u_int64_t 553sndbuf_getprevtotal(struct snd_dbuf *b) 554{ 555 SNDBUF_LOCKASSERT(b); 556 557 return b->prev_total; 558} 559 560void 561sndbuf_updateprevtotal(struct snd_dbuf *b) 562{ 563 SNDBUF_LOCKASSERT(b); 564 565 b->prev_total = b->total; 566} 567 568unsigned int 569sndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to) 570{ 571 if (from == NULL || to == NULL || v == 0) 572 return 0; 573 574 return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from), 575 sndbuf_getalign(to) * sndbuf_getspd(to)); 576} 577 578u_int8_t 579sndbuf_zerodata(u_int32_t fmt) 580{ 581 if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH)) 582 return (0x00); 583 else if (fmt & AFMT_MU_LAW) 584 return (0x7f); 585 else if (fmt & AFMT_A_LAW) 586 return (0x55); 587 return (0x80); 588} 589 590/************************************************************/ 591 592/** 593 * @brief Acquire buffer space to extend ready area 594 * 595 * This function extends the ready area length by @c count bytes, and may 596 * optionally copy samples from another location stored in @c from. The 597 * counter @c snd_dbuf::total is also incremented by @c count bytes. 598 * 599 * @param b audio buffer 600 * @param from sample source (optional) 601 * @param count number of bytes to acquire 602 * 603 * @retval 0 Unconditional 604 */ 605int 606sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 607{ 608 int l; 609 610 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 611 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 612 b->total += count; 613 if (from != NULL) { 614 while (count > 0) { 615 l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 616 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 617 from += l; 618 b->rl += l; 619 count -= l; 620 } 621 } else 622 b->rl += count; 623 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 624 625 return 0; 626} 627 628/** 629 * @brief Dispose samples from channel buffer, increasing size of ready area 630 * 631 * This function discards samples from the supplied buffer by advancing the 632 * ready area start pointer and decrementing the ready area length. If 633 * @c to is not NULL, then the discard samples will be copied to the location 634 * it points to. 635 * 636 * @param b PCM channel sound buffer 637 * @param to destination buffer (optional) 638 * @param count number of bytes to discard 639 * 640 * @returns 0 unconditionally 641 */ 642int 643sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 644{ 645 int l; 646 647 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 648 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 649 if (to != NULL) { 650 while (count > 0) { 651 l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 652 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 653 to += l; 654 b->rl -= l; 655 b->rp = (b->rp + l) % b->bufsize; 656 count -= l; 657 } 658 } else { 659 b->rl -= count; 660 b->rp = (b->rp + count) % b->bufsize; 661 } 662 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 663 664 return 0; 665} 666 667#ifdef SND_DIAGNOSTIC 668static uint32_t snd_feeder_maxfeed = 0; 669SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD, 670 &snd_feeder_maxfeed, 0, "maximum feeder count request"); 671 672static uint32_t snd_feeder_maxcycle = 0; 673SYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD, 674 &snd_feeder_maxcycle, 0, "maximum feeder cycle"); 675#endif 676 677/* count is number of bytes we want added to destination buffer */ 678int 679sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 680{ 681 unsigned int cnt, maxfeed; 682#ifdef SND_DIAGNOSTIC 683 unsigned int cycle; 684 685 if (count > snd_feeder_maxfeed) 686 snd_feeder_maxfeed = count; 687 688 cycle = 0; 689#endif 690 691 KASSERT(count > 0, ("can't feed 0 bytes")); 692 693 if (sndbuf_getfree(to) < count) 694 return (EINVAL); 695 696 maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to)); 697 698 do { 699 cnt = FEEDER_FEED(feeder, channel, to->tmpbuf, 700 min(count, maxfeed), from); 701 if (cnt == 0) 702 break; 703 sndbuf_acquire(to, to->tmpbuf, cnt); 704 count -= cnt; 705#ifdef SND_DIAGNOSTIC 706 cycle++; 707#endif 708 } while (count != 0); 709 710#ifdef SND_DIAGNOSTIC 711 if (cycle > snd_feeder_maxcycle) 712 snd_feeder_maxcycle = cycle; 713#endif 714 715 return (0); 716} 717 718/************************************************************/ 719 720void 721sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 722{ 723 printf("%s: [", s); 724 if (what & 0x01) 725 printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 726 if (what & 0x02) 727 printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 728 if (what & 0x04) 729 printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun); 730 if (what & 0x08) 731 printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 732 if (what & 0x10) 733 printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 734 printf(" ]\n"); 735} 736 737/************************************************************/ 738u_int32_t 739sndbuf_getflags(struct snd_dbuf *b) 740{ 741 return b->flags; 742} 743 744void 745sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 746{ 747 b->flags &= ~flags; 748 if (on) 749 b->flags |= flags; 750} 751 752/** 753 * @brief Clear the shadow buffer by filling with samples equal to zero. 754 * 755 * @param b buffer to clear 756 */ 757void 758sndbuf_clearshadow(struct snd_dbuf *b) 759{ 760 KASSERT(b != NULL, ("b is a null pointer")); 761 KASSERT(b->sl >= 0, ("illegal shadow length")); 762 763 if ((b->shadbuf != NULL) && (b->sl > 0)) 764 memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl); 765} 766 767#ifdef OSSV4_EXPERIMENT 768/** 769 * @brief Return peak value from samples in buffer ready area. 770 * 771 * Peak ranges from 0-32767. If channel is monaural, most significant 16 772 * bits will be zero. For now, only expects to work with 1-2 channel 773 * buffers. 774 * 775 * @note Currently only operates with linear PCM formats. 776 * 777 * @param b buffer to analyze 778 * @param lpeak pointer to store left peak value 779 * @param rpeak pointer to store right peak value 780 */ 781void 782sndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp) 783{ 784 u_int32_t lpeak, rpeak; 785 786 lpeak = 0; 787 rpeak = 0; 788 789 /** 790 * @todo fill this in later 791 */ 792} 793#endif 794