Index: mail/thunderbird/Makefile =================================================================== --- mail/thunderbird/Makefile +++ mail/thunderbird/Makefile @@ -3,7 +3,7 @@ PORTNAME= thunderbird DISTVERSION= 78.3.0 -PORTREVISION= 2 +PORTREVISION= 3 CATEGORIES= mail news net-im MASTER_SITES= MOZILLA/${PORTNAME}/releases/${DISTVERSION}/source \ MOZILLA/${PORTNAME}/candidates/${DISTVERSION}-candidates/build2/source Index: mail/thunderbird/files/patch-cubeb-oss =================================================================== --- mail/thunderbird/files/patch-cubeb-oss +++ mail/thunderbird/files/patch-cubeb-oss @@ -61,10 +61,14 @@ #endif --- /dev/null +++ media/libcubeb/src/cubeb_oss.c -@@ -0,0 +1,1210 @@ +@@ -0,0 +1,1245 @@ +/* + * Copyright © 2019-2020 Nia Alarie + * Copyright © 2020 Ka Ho Ng ++ * Copyright © 2020 The FreeBSD Foundation ++ * ++ * Portions of this software were developed by Ka Ho Ng ++ * under sponsorship from the FreeBSD Foundation. + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. @@ -103,6 +107,10 @@ +#define OSS_LATENCY_MS (8) +#endif + ++#ifndef OSS_NFRAGS ++#define OSS_NFRAGS (4) ++#endif ++ +#ifndef OSS_DEFAULT_DEVICE +#define OSS_DEFAULT_DEVICE "/dev/dsp" +#endif @@ -185,6 +193,8 @@ + cubeb_state_callback state_cb; + uint64_t frames_written; + unsigned int nfr; /* Number of frames allocated */ ++ unsigned int nfrags; ++ unsigned int bufframes; +}; + +static char const * @@ -794,17 +804,19 @@ +oss_audio_loop(cubeb_stream * s) +{ + int state = CUBEB_STATE_STARTED; -+ long nfr = 0; + int trig = 0; + int drain = 0; + struct pollfd pfds[2]; -+ bool cbready = true; ++ unsigned int ppending, rpending; + + pfds[0].fd = s->play.fd; + pfds[0].events = POLLOUT; + pfds[1].fd = s->record.fd; + pfds[1].events = POLLIN; + ++ ppending = 0; ++ rpending = s->bufframes; ++ + if (s->record.fd != -1) { + if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig)) { + LOG("Error %d occured when setting trigger on record fd", errno); @@ -817,12 +829,12 @@ + state = CUBEB_STATE_ERROR; + goto out; + } ++ memset(s->record.buf, 0, s->bufframes * s->record.frame_size); + } + -+ if (s->record.fd != -1) -+ memset(s->record.buf, 0, s->nfr); -+ + while (1) { ++ long nfr = 0; ++ + pthread_mutex_lock(&s->mtx); + if (!s->running || s->destroying) { + pthread_mutex_unlock(&s->mtx); @@ -840,77 +852,95 @@ + break; + } + -+ if (s->record.fd != -1 && s->record.floating) { -+ oss_linear32_to_float(s->record.buf, s->record.info.channels * s->nfr); -+ } -+ if (cbready) { -+ nfr = s->data_cb(s, s->user_ptr, s->record.buf, s->play.buf, s->nfr); ++ while ((s->bufframes - ppending) >= s->nfr && rpending >= s->nfr) { ++ long n = ((s->bufframes - ppending) < rpending) ? s->bufframes - ppending : rpending; ++ char *rptr = NULL, *pptr = NULL; ++ if (s->record.fd != -1) ++ rptr = (char *)s->record.buf; ++ if (s->play.fd != -1) ++ pptr = (char *)s->play.buf + ppending * s->play.frame_size; ++ if (s->record.fd != -1 && s->record.floating) { ++ oss_linear32_to_float(s->record.buf, s->record.info.channels * n); ++ } ++ nfr = s->data_cb(s, s->user_ptr, rptr, pptr, n); + if (nfr == CUBEB_ERROR) { + state = CUBEB_STATE_ERROR; + goto out; + } -+ cbready = false; -+ } -+ if (s->play.fd != -1) { -+ float vol; ++ if (pptr) { ++ float vol; + -+ pthread_mutex_lock(&s->mtx); -+ vol = s->volume; -+ pthread_mutex_unlock(&s->mtx); ++ pthread_mutex_lock(&s->mtx); ++ vol = s->volume; ++ pthread_mutex_unlock(&s->mtx); + -+ if (s->play.floating) { -+ oss_float_to_linear32(s->play.buf, s->play.info.channels * nfr, vol); -+ } else { -+ oss_linear16_set_vol(s->play.buf, s->play.info.channels * nfr, vol); ++ if (s->play.floating) { ++ oss_float_to_linear32(pptr, s->play.info.channels * nfr, vol); ++ } else { ++ oss_linear16_set_vol((int16_t *)pptr, s->play.info.channels * nfr, vol); ++ } + } -+ } -+ if (nfr < (long)s->nfr) { -+ if (s->play.fd != -1) { -+ drain = 1; -+ } else { -+ /* -+ * This is a record-only stream and number of frames -+ * returned from data_cb() is smaller than number -+ * of frames required to read. Stop here. -+ */ -+ -+ state = CUBEB_STATE_STOPPED; -+ break; ++ if (pptr) { ++ ppending += nfr; ++ assert(ppending <= s->bufframes); ++ } ++ if (rptr) { ++ assert(rpending >= nfr); ++ rpending -= nfr; ++ memmove(rptr, rptr + nfr * s->record.frame_size, ++ (s->bufframes - nfr) * s->record.frame_size); ++ } ++ if (nfr < n) { ++ if (s->play.fd != -1) { ++ drain = 1; ++ break; ++ } else { ++ /* ++ * This is a record-only stream and number of frames ++ * returned from data_cb() is smaller than number ++ * of frames required to read. Stop here. ++ */ ++ ++ state = CUBEB_STATE_STOPPED; ++ goto out; ++ } + } + } + -+ size_t to_write = s->play.fd != -1 ? nfr : 0; -+ size_t to_read = s->record.fd != -1 ? s->nfr : 0; -+ size_t write_ofs = 0; -+ size_t read_ofs = 0; -+ while (to_write > 0 || to_read > 0) { -+ size_t bytes; -+ ssize_t n, frames; -+ int nfds; -+ -+ pfds[0].revents = 0; -+ pfds[1].revents = 0; -+ -+ nfds = poll(pfds, 2, 1000); -+ if (nfds == -1) { -+ if (errno == EINTR) -+ continue; -+ LOG("Error %d occured when polling playback and record fd", errno); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } else if (nfds == 0) ++ ssize_t n, frames; ++ int nfds; ++ ++ pfds[0].revents = 0; ++ pfds[1].revents = 0; ++ ++ nfds = poll(pfds, 2, 1000); ++ if (nfds == -1) { ++ if (errno == EINTR) + continue; ++ LOG("Error %d occured when polling playback and record fd", errno); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } else if (nfds == 0) ++ continue; + -+ if ((pfds[0].revents & (POLLERR | POLLHUP)) || -+ (pfds[1].revents & (POLLERR | POLLHUP))) { -+ LOG("Error occured on playback, record fds"); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } ++ if ((pfds[0].revents & (POLLERR | POLLHUP)) || ++ (pfds[1].revents & (POLLERR | POLLHUP))) { ++ LOG("Error occured on playback, record fds"); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } + -+ if (to_write > 0 && pfds[0].revents) { -+ bytes = to_write * s->play.frame_size; -+ if ((n = write(s->play.fd, (uint8_t *)s->play.buf + write_ofs, bytes)) < 0) { ++ if (pfds[0].revents) { ++ while (ppending > 0) { ++ size_t bytes = ppending * s->play.frame_size; ++ if ((n = write(s->play.fd, (uint8_t *)s->play.buf, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) { ++ if (drain) ++ continue; ++ break; ++ } + state = CUBEB_STATE_ERROR; + goto out; + } @@ -918,26 +948,31 @@ + pthread_mutex_lock(&s->mtx); + s->frames_written += frames; + pthread_mutex_unlock(&s->mtx); -+ to_write -= frames; -+ write_ofs += n; ++ ppending -= frames; ++ memmove(s->play.buf, (uint8_t *)s->play.buf + n, ++ (s->bufframes - frames) * s->play.frame_size); + } -+ if (to_read > 0 && pfds[1].revents) { -+ bytes = to_read * s->record.frame_size; -+ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, -+ bytes)) < 0) { ++ } ++ if (pfds[1].revents) { ++ while (s->bufframes - rpending > 0) { ++ size_t bytes = (s->bufframes - rpending) * s->record.frame_size; ++ size_t read_ofs = rpending * s->record.frame_size; ++ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) ++ break; + state = CUBEB_STATE_ERROR; + goto out; + } + frames = n / s->record.frame_size; -+ to_read -= frames; -+ read_ofs += n; ++ rpending += frames; + } + } + if (drain) { + state = CUBEB_STATE_DRAINED; + break; + } -+ cbready = true; + } + +out: @@ -958,6 +993,7 @@ + } + pthread_mutex_unlock(&s->mtx); + ++ state = CUBEB_STATE_STARTED; + s->state_cb(s, s->user_ptr, state); + + state = oss_audio_loop(s); @@ -990,7 +1026,7 @@ +oss_calc_frag_shift(unsigned int frames, unsigned int frame_size) +{ + int n = 4; -+ int blksize = (frames * frame_size + 4 - 1) / 4; ++ int blksize = (frames * frame_size + OSS_NFRAGS - 1) / OSS_NFRAGS; + while ((1 << n) < blksize) + n++; + return n; @@ -999,7 +1035,7 @@ +static inline int +oss_get_frag_params(unsigned int shift) +{ -+ return (8 << 16) | shift; ++ return (OSS_NFRAGS << 16) | shift; +} + +static int @@ -1055,7 +1091,7 @@ + goto error; + } + if (s->record.fd == -1) { -+ if ((s->record.fd = open(s->record.name, O_RDONLY)) == -1) { ++ if ((s->record.fd = open(s->record.name, O_RDONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as read-only", + s->record.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1086,7 +1122,7 @@ + goto error; + } + if (s->play.fd == -1) { -+ if ((s->play.fd = open(s->play.name, O_WRONLY)) == -1) { ++ if ((s->play.fd = open(s->play.name, O_WRONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as write-only", + s->play.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1104,6 +1140,8 @@ + } + /* Use the largest nframes among playing and recording streams */ + s->nfr = (playnfr > recnfr) ? playnfr : recnfr; ++ s->nfrags = OSS_NFRAGS; ++ s->bufframes = s->nfr * s->nfrags; + if (s->play.fd != -1) { + int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->play.frame_size)); + if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag)) @@ -1136,13 +1174,13 @@ + } + + if (s->play.fd != -1) { -+ if ((s->play.buf = calloc(s->nfr, s->play.frame_size)) == NULL) { ++ if ((s->play.buf = calloc(s->bufframes, s->play.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } + } + if (s->record.fd != -1) { -+ if ((s->record.buf = calloc(s->nfr, s->record.frame_size)) == NULL) { ++ if ((s->record.buf = calloc(s->bufframes, s->record.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } @@ -1161,10 +1199,7 @@ +oss_stream_thr_create(cubeb_stream * s) +{ + if (s->thread_created) { -+ pthread_mutex_lock(&s->mtx); + pthread_cond_signal(&s->doorbell_cv); -+ pthread_mutex_unlock(&s->mtx); -+ + return CUBEB_OK; + } + Index: www/firefox-esr/Makefile =================================================================== --- www/firefox-esr/Makefile +++ www/firefox-esr/Makefile @@ -3,7 +3,7 @@ PORTNAME= firefox DISTVERSION= 78.3.0 -PORTREVISION= 1 +PORTREVISION= 2 PORTEPOCH= 1 CATEGORIES= www MASTER_SITES= MOZILLA/${PORTNAME}/releases/${DISTVERSION}esr/source \ Index: www/firefox-esr/files/patch-cubeb-oss =================================================================== --- www/firefox-esr/files/patch-cubeb-oss +++ www/firefox-esr/files/patch-cubeb-oss @@ -61,10 +61,14 @@ #endif --- /dev/null +++ media/libcubeb/src/cubeb_oss.c -@@ -0,0 +1,1210 @@ +@@ -0,0 +1,1245 @@ +/* + * Copyright © 2019-2020 Nia Alarie + * Copyright © 2020 Ka Ho Ng ++ * Copyright © 2020 The FreeBSD Foundation ++ * ++ * Portions of this software were developed by Ka Ho Ng ++ * under sponsorship from the FreeBSD Foundation. + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. @@ -103,6 +107,10 @@ +#define OSS_LATENCY_MS (8) +#endif + ++#ifndef OSS_NFRAGS ++#define OSS_NFRAGS (4) ++#endif ++ +#ifndef OSS_DEFAULT_DEVICE +#define OSS_DEFAULT_DEVICE "/dev/dsp" +#endif @@ -185,6 +193,8 @@ + cubeb_state_callback state_cb; + uint64_t frames_written; + unsigned int nfr; /* Number of frames allocated */ ++ unsigned int nfrags; ++ unsigned int bufframes; +}; + +static char const * @@ -794,17 +804,19 @@ +oss_audio_loop(cubeb_stream * s) +{ + int state = CUBEB_STATE_STARTED; -+ long nfr = 0; + int trig = 0; + int drain = 0; + struct pollfd pfds[2]; -+ bool cbready = true; ++ unsigned int ppending, rpending; + + pfds[0].fd = s->play.fd; + pfds[0].events = POLLOUT; + pfds[1].fd = s->record.fd; + pfds[1].events = POLLIN; + ++ ppending = 0; ++ rpending = s->bufframes; ++ + if (s->record.fd != -1) { + if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig)) { + LOG("Error %d occured when setting trigger on record fd", errno); @@ -817,12 +829,12 @@ + state = CUBEB_STATE_ERROR; + goto out; + } ++ memset(s->record.buf, 0, s->bufframes * s->record.frame_size); + } + -+ if (s->record.fd != -1) -+ memset(s->record.buf, 0, s->nfr); -+ + while (1) { ++ long nfr = 0; ++ + pthread_mutex_lock(&s->mtx); + if (!s->running || s->destroying) { + pthread_mutex_unlock(&s->mtx); @@ -840,77 +852,95 @@ + break; + } + -+ if (s->record.fd != -1 && s->record.floating) { -+ oss_linear32_to_float(s->record.buf, s->record.info.channels * s->nfr); -+ } -+ if (cbready) { -+ nfr = s->data_cb(s, s->user_ptr, s->record.buf, s->play.buf, s->nfr); ++ while ((s->bufframes - ppending) >= s->nfr && rpending >= s->nfr) { ++ long n = ((s->bufframes - ppending) < rpending) ? s->bufframes - ppending : rpending; ++ char *rptr = NULL, *pptr = NULL; ++ if (s->record.fd != -1) ++ rptr = (char *)s->record.buf; ++ if (s->play.fd != -1) ++ pptr = (char *)s->play.buf + ppending * s->play.frame_size; ++ if (s->record.fd != -1 && s->record.floating) { ++ oss_linear32_to_float(s->record.buf, s->record.info.channels * n); ++ } ++ nfr = s->data_cb(s, s->user_ptr, rptr, pptr, n); + if (nfr == CUBEB_ERROR) { + state = CUBEB_STATE_ERROR; + goto out; + } -+ cbready = false; -+ } -+ if (s->play.fd != -1) { -+ float vol; ++ if (pptr) { ++ float vol; + -+ pthread_mutex_lock(&s->mtx); -+ vol = s->volume; -+ pthread_mutex_unlock(&s->mtx); ++ pthread_mutex_lock(&s->mtx); ++ vol = s->volume; ++ pthread_mutex_unlock(&s->mtx); + -+ if (s->play.floating) { -+ oss_float_to_linear32(s->play.buf, s->play.info.channels * nfr, vol); -+ } else { -+ oss_linear16_set_vol(s->play.buf, s->play.info.channels * nfr, vol); ++ if (s->play.floating) { ++ oss_float_to_linear32(pptr, s->play.info.channels * nfr, vol); ++ } else { ++ oss_linear16_set_vol((int16_t *)pptr, s->play.info.channels * nfr, vol); ++ } + } -+ } -+ if (nfr < (long)s->nfr) { -+ if (s->play.fd != -1) { -+ drain = 1; -+ } else { -+ /* -+ * This is a record-only stream and number of frames -+ * returned from data_cb() is smaller than number -+ * of frames required to read. Stop here. -+ */ -+ -+ state = CUBEB_STATE_STOPPED; -+ break; ++ if (pptr) { ++ ppending += nfr; ++ assert(ppending <= s->bufframes); ++ } ++ if (rptr) { ++ assert(rpending >= nfr); ++ rpending -= nfr; ++ memmove(rptr, rptr + nfr * s->record.frame_size, ++ (s->bufframes - nfr) * s->record.frame_size); ++ } ++ if (nfr < n) { ++ if (s->play.fd != -1) { ++ drain = 1; ++ break; ++ } else { ++ /* ++ * This is a record-only stream and number of frames ++ * returned from data_cb() is smaller than number ++ * of frames required to read. Stop here. ++ */ ++ ++ state = CUBEB_STATE_STOPPED; ++ goto out; ++ } + } + } + -+ size_t to_write = s->play.fd != -1 ? nfr : 0; -+ size_t to_read = s->record.fd != -1 ? s->nfr : 0; -+ size_t write_ofs = 0; -+ size_t read_ofs = 0; -+ while (to_write > 0 || to_read > 0) { -+ size_t bytes; -+ ssize_t n, frames; -+ int nfds; -+ -+ pfds[0].revents = 0; -+ pfds[1].revents = 0; -+ -+ nfds = poll(pfds, 2, 1000); -+ if (nfds == -1) { -+ if (errno == EINTR) -+ continue; -+ LOG("Error %d occured when polling playback and record fd", errno); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } else if (nfds == 0) ++ ssize_t n, frames; ++ int nfds; ++ ++ pfds[0].revents = 0; ++ pfds[1].revents = 0; ++ ++ nfds = poll(pfds, 2, 1000); ++ if (nfds == -1) { ++ if (errno == EINTR) + continue; ++ LOG("Error %d occured when polling playback and record fd", errno); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } else if (nfds == 0) ++ continue; + -+ if ((pfds[0].revents & (POLLERR | POLLHUP)) || -+ (pfds[1].revents & (POLLERR | POLLHUP))) { -+ LOG("Error occured on playback, record fds"); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } ++ if ((pfds[0].revents & (POLLERR | POLLHUP)) || ++ (pfds[1].revents & (POLLERR | POLLHUP))) { ++ LOG("Error occured on playback, record fds"); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } + -+ if (to_write > 0 && pfds[0].revents) { -+ bytes = to_write * s->play.frame_size; -+ if ((n = write(s->play.fd, (uint8_t *)s->play.buf + write_ofs, bytes)) < 0) { ++ if (pfds[0].revents) { ++ while (ppending > 0) { ++ size_t bytes = ppending * s->play.frame_size; ++ if ((n = write(s->play.fd, (uint8_t *)s->play.buf, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) { ++ if (drain) ++ continue; ++ break; ++ } + state = CUBEB_STATE_ERROR; + goto out; + } @@ -918,26 +948,31 @@ + pthread_mutex_lock(&s->mtx); + s->frames_written += frames; + pthread_mutex_unlock(&s->mtx); -+ to_write -= frames; -+ write_ofs += n; ++ ppending -= frames; ++ memmove(s->play.buf, (uint8_t *)s->play.buf + n, ++ (s->bufframes - frames) * s->play.frame_size); + } -+ if (to_read > 0 && pfds[1].revents) { -+ bytes = to_read * s->record.frame_size; -+ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, -+ bytes)) < 0) { ++ } ++ if (pfds[1].revents) { ++ while (s->bufframes - rpending > 0) { ++ size_t bytes = (s->bufframes - rpending) * s->record.frame_size; ++ size_t read_ofs = rpending * s->record.frame_size; ++ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) ++ break; + state = CUBEB_STATE_ERROR; + goto out; + } + frames = n / s->record.frame_size; -+ to_read -= frames; -+ read_ofs += n; ++ rpending += frames; + } + } + if (drain) { + state = CUBEB_STATE_DRAINED; + break; + } -+ cbready = true; + } + +out: @@ -958,6 +993,7 @@ + } + pthread_mutex_unlock(&s->mtx); + ++ state = CUBEB_STATE_STARTED; + s->state_cb(s, s->user_ptr, state); + + state = oss_audio_loop(s); @@ -990,7 +1026,7 @@ +oss_calc_frag_shift(unsigned int frames, unsigned int frame_size) +{ + int n = 4; -+ int blksize = (frames * frame_size + 4 - 1) / 4; ++ int blksize = (frames * frame_size + OSS_NFRAGS - 1) / OSS_NFRAGS; + while ((1 << n) < blksize) + n++; + return n; @@ -999,7 +1035,7 @@ +static inline int +oss_get_frag_params(unsigned int shift) +{ -+ return (8 << 16) | shift; ++ return (OSS_NFRAGS << 16) | shift; +} + +static int @@ -1055,7 +1091,7 @@ + goto error; + } + if (s->record.fd == -1) { -+ if ((s->record.fd = open(s->record.name, O_RDONLY)) == -1) { ++ if ((s->record.fd = open(s->record.name, O_RDONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as read-only", + s->record.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1086,7 +1122,7 @@ + goto error; + } + if (s->play.fd == -1) { -+ if ((s->play.fd = open(s->play.name, O_WRONLY)) == -1) { ++ if ((s->play.fd = open(s->play.name, O_WRONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as write-only", + s->play.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1104,6 +1140,8 @@ + } + /* Use the largest nframes among playing and recording streams */ + s->nfr = (playnfr > recnfr) ? playnfr : recnfr; ++ s->nfrags = OSS_NFRAGS; ++ s->bufframes = s->nfr * s->nfrags; + if (s->play.fd != -1) { + int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->play.frame_size)); + if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag)) @@ -1136,13 +1174,13 @@ + } + + if (s->play.fd != -1) { -+ if ((s->play.buf = calloc(s->nfr, s->play.frame_size)) == NULL) { ++ if ((s->play.buf = calloc(s->bufframes, s->play.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } + } + if (s->record.fd != -1) { -+ if ((s->record.buf = calloc(s->nfr, s->record.frame_size)) == NULL) { ++ if ((s->record.buf = calloc(s->bufframes, s->record.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } @@ -1161,10 +1199,7 @@ +oss_stream_thr_create(cubeb_stream * s) +{ + if (s->thread_created) { -+ pthread_mutex_lock(&s->mtx); + pthread_cond_signal(&s->doorbell_cv); -+ pthread_mutex_unlock(&s->mtx); -+ + return CUBEB_OK; + } + Index: www/firefox/Makefile =================================================================== --- www/firefox/Makefile +++ www/firefox/Makefile @@ -3,7 +3,7 @@ PORTNAME= firefox DISTVERSION= 81.0 -PORTREVISION= 1 +PORTREVISION= 2 PORTEPOCH= 2 CATEGORIES= www MASTER_SITES= MOZILLA/${PORTNAME}/releases/${DISTVERSION}/source \ Index: www/firefox/files/patch-cubeb-oss =================================================================== --- www/firefox/files/patch-cubeb-oss +++ www/firefox/files/patch-cubeb-oss @@ -61,10 +61,14 @@ #endif --- /dev/null +++ media/libcubeb/src/cubeb_oss.c -@@ -0,0 +1,1210 @@ +@@ -0,0 +1,1245 @@ +/* + * Copyright © 2019-2020 Nia Alarie + * Copyright © 2020 Ka Ho Ng ++ * Copyright © 2020 The FreeBSD Foundation ++ * ++ * Portions of this software were developed by Ka Ho Ng ++ * under sponsorship from the FreeBSD Foundation. + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. @@ -103,6 +107,10 @@ +#define OSS_LATENCY_MS (8) +#endif + ++#ifndef OSS_NFRAGS ++#define OSS_NFRAGS (4) ++#endif ++ +#ifndef OSS_DEFAULT_DEVICE +#define OSS_DEFAULT_DEVICE "/dev/dsp" +#endif @@ -185,6 +193,8 @@ + cubeb_state_callback state_cb; + uint64_t frames_written; + unsigned int nfr; /* Number of frames allocated */ ++ unsigned int nfrags; ++ unsigned int bufframes; +}; + +static char const * @@ -794,17 +804,19 @@ +oss_audio_loop(cubeb_stream * s) +{ + int state = CUBEB_STATE_STARTED; -+ long nfr = 0; + int trig = 0; + int drain = 0; + struct pollfd pfds[2]; -+ bool cbready = true; ++ unsigned int ppending, rpending; + + pfds[0].fd = s->play.fd; + pfds[0].events = POLLOUT; + pfds[1].fd = s->record.fd; + pfds[1].events = POLLIN; + ++ ppending = 0; ++ rpending = s->bufframes; ++ + if (s->record.fd != -1) { + if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig)) { + LOG("Error %d occured when setting trigger on record fd", errno); @@ -817,12 +829,12 @@ + state = CUBEB_STATE_ERROR; + goto out; + } ++ memset(s->record.buf, 0, s->bufframes * s->record.frame_size); + } + -+ if (s->record.fd != -1) -+ memset(s->record.buf, 0, s->nfr); -+ + while (1) { ++ long nfr = 0; ++ + pthread_mutex_lock(&s->mtx); + if (!s->running || s->destroying) { + pthread_mutex_unlock(&s->mtx); @@ -840,77 +852,95 @@ + break; + } + -+ if (s->record.fd != -1 && s->record.floating) { -+ oss_linear32_to_float(s->record.buf, s->record.info.channels * s->nfr); -+ } -+ if (cbready) { -+ nfr = s->data_cb(s, s->user_ptr, s->record.buf, s->play.buf, s->nfr); ++ while ((s->bufframes - ppending) >= s->nfr && rpending >= s->nfr) { ++ long n = ((s->bufframes - ppending) < rpending) ? s->bufframes - ppending : rpending; ++ char *rptr = NULL, *pptr = NULL; ++ if (s->record.fd != -1) ++ rptr = (char *)s->record.buf; ++ if (s->play.fd != -1) ++ pptr = (char *)s->play.buf + ppending * s->play.frame_size; ++ if (s->record.fd != -1 && s->record.floating) { ++ oss_linear32_to_float(s->record.buf, s->record.info.channels * n); ++ } ++ nfr = s->data_cb(s, s->user_ptr, rptr, pptr, n); + if (nfr == CUBEB_ERROR) { + state = CUBEB_STATE_ERROR; + goto out; + } -+ cbready = false; -+ } -+ if (s->play.fd != -1) { -+ float vol; ++ if (pptr) { ++ float vol; + -+ pthread_mutex_lock(&s->mtx); -+ vol = s->volume; -+ pthread_mutex_unlock(&s->mtx); ++ pthread_mutex_lock(&s->mtx); ++ vol = s->volume; ++ pthread_mutex_unlock(&s->mtx); + -+ if (s->play.floating) { -+ oss_float_to_linear32(s->play.buf, s->play.info.channels * nfr, vol); -+ } else { -+ oss_linear16_set_vol(s->play.buf, s->play.info.channels * nfr, vol); ++ if (s->play.floating) { ++ oss_float_to_linear32(pptr, s->play.info.channels * nfr, vol); ++ } else { ++ oss_linear16_set_vol((int16_t *)pptr, s->play.info.channels * nfr, vol); ++ } + } -+ } -+ if (nfr < (long)s->nfr) { -+ if (s->play.fd != -1) { -+ drain = 1; -+ } else { -+ /* -+ * This is a record-only stream and number of frames -+ * returned from data_cb() is smaller than number -+ * of frames required to read. Stop here. -+ */ -+ -+ state = CUBEB_STATE_STOPPED; -+ break; ++ if (pptr) { ++ ppending += nfr; ++ assert(ppending <= s->bufframes); ++ } ++ if (rptr) { ++ assert(rpending >= nfr); ++ rpending -= nfr; ++ memmove(rptr, rptr + nfr * s->record.frame_size, ++ (s->bufframes - nfr) * s->record.frame_size); ++ } ++ if (nfr < n) { ++ if (s->play.fd != -1) { ++ drain = 1; ++ break; ++ } else { ++ /* ++ * This is a record-only stream and number of frames ++ * returned from data_cb() is smaller than number ++ * of frames required to read. Stop here. ++ */ ++ ++ state = CUBEB_STATE_STOPPED; ++ goto out; ++ } + } + } + -+ size_t to_write = s->play.fd != -1 ? nfr : 0; -+ size_t to_read = s->record.fd != -1 ? s->nfr : 0; -+ size_t write_ofs = 0; -+ size_t read_ofs = 0; -+ while (to_write > 0 || to_read > 0) { -+ size_t bytes; -+ ssize_t n, frames; -+ int nfds; -+ -+ pfds[0].revents = 0; -+ pfds[1].revents = 0; -+ -+ nfds = poll(pfds, 2, 1000); -+ if (nfds == -1) { -+ if (errno == EINTR) -+ continue; -+ LOG("Error %d occured when polling playback and record fd", errno); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } else if (nfds == 0) ++ ssize_t n, frames; ++ int nfds; ++ ++ pfds[0].revents = 0; ++ pfds[1].revents = 0; ++ ++ nfds = poll(pfds, 2, 1000); ++ if (nfds == -1) { ++ if (errno == EINTR) + continue; ++ LOG("Error %d occured when polling playback and record fd", errno); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } else if (nfds == 0) ++ continue; + -+ if ((pfds[0].revents & (POLLERR | POLLHUP)) || -+ (pfds[1].revents & (POLLERR | POLLHUP))) { -+ LOG("Error occured on playback, record fds"); -+ state = CUBEB_STATE_ERROR; -+ goto out; -+ } ++ if ((pfds[0].revents & (POLLERR | POLLHUP)) || ++ (pfds[1].revents & (POLLERR | POLLHUP))) { ++ LOG("Error occured on playback, record fds"); ++ state = CUBEB_STATE_ERROR; ++ goto out; ++ } + -+ if (to_write > 0 && pfds[0].revents) { -+ bytes = to_write * s->play.frame_size; -+ if ((n = write(s->play.fd, (uint8_t *)s->play.buf + write_ofs, bytes)) < 0) { ++ if (pfds[0].revents) { ++ while (ppending > 0) { ++ size_t bytes = ppending * s->play.frame_size; ++ if ((n = write(s->play.fd, (uint8_t *)s->play.buf, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) { ++ if (drain) ++ continue; ++ break; ++ } + state = CUBEB_STATE_ERROR; + goto out; + } @@ -918,26 +948,31 @@ + pthread_mutex_lock(&s->mtx); + s->frames_written += frames; + pthread_mutex_unlock(&s->mtx); -+ to_write -= frames; -+ write_ofs += n; ++ ppending -= frames; ++ memmove(s->play.buf, (uint8_t *)s->play.buf + n, ++ (s->bufframes - frames) * s->play.frame_size); + } -+ if (to_read > 0 && pfds[1].revents) { -+ bytes = to_read * s->record.frame_size; -+ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, -+ bytes)) < 0) { ++ } ++ if (pfds[1].revents) { ++ while (s->bufframes - rpending > 0) { ++ size_t bytes = (s->bufframes - rpending) * s->record.frame_size; ++ size_t read_ofs = rpending * s->record.frame_size; ++ if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, bytes)) < 0) { ++ if (errno == EINTR) ++ continue; ++ if (errno == EAGAIN) ++ break; + state = CUBEB_STATE_ERROR; + goto out; + } + frames = n / s->record.frame_size; -+ to_read -= frames; -+ read_ofs += n; ++ rpending += frames; + } + } + if (drain) { + state = CUBEB_STATE_DRAINED; + break; + } -+ cbready = true; + } + +out: @@ -958,6 +993,7 @@ + } + pthread_mutex_unlock(&s->mtx); + ++ state = CUBEB_STATE_STARTED; + s->state_cb(s, s->user_ptr, state); + + state = oss_audio_loop(s); @@ -990,7 +1026,7 @@ +oss_calc_frag_shift(unsigned int frames, unsigned int frame_size) +{ + int n = 4; -+ int blksize = (frames * frame_size + 4 - 1) / 4; ++ int blksize = (frames * frame_size + OSS_NFRAGS - 1) / OSS_NFRAGS; + while ((1 << n) < blksize) + n++; + return n; @@ -999,7 +1035,7 @@ +static inline int +oss_get_frag_params(unsigned int shift) +{ -+ return (8 << 16) | shift; ++ return (OSS_NFRAGS << 16) | shift; +} + +static int @@ -1055,7 +1091,7 @@ + goto error; + } + if (s->record.fd == -1) { -+ if ((s->record.fd = open(s->record.name, O_RDONLY)) == -1) { ++ if ((s->record.fd = open(s->record.name, O_RDONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as read-only", + s->record.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1086,7 +1122,7 @@ + goto error; + } + if (s->play.fd == -1) { -+ if ((s->play.fd = open(s->play.name, O_WRONLY)) == -1) { ++ if ((s->play.fd = open(s->play.name, O_WRONLY | O_NONBLOCK)) == -1) { + LOG("Audio device \"%s\" could not be opened as write-only", + s->play.name); + ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; @@ -1104,6 +1140,8 @@ + } + /* Use the largest nframes among playing and recording streams */ + s->nfr = (playnfr > recnfr) ? playnfr : recnfr; ++ s->nfrags = OSS_NFRAGS; ++ s->bufframes = s->nfr * s->nfrags; + if (s->play.fd != -1) { + int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->play.frame_size)); + if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag)) @@ -1136,13 +1174,13 @@ + } + + if (s->play.fd != -1) { -+ if ((s->play.buf = calloc(s->nfr, s->play.frame_size)) == NULL) { ++ if ((s->play.buf = calloc(s->bufframes, s->play.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } + } + if (s->record.fd != -1) { -+ if ((s->record.buf = calloc(s->nfr, s->record.frame_size)) == NULL) { ++ if ((s->record.buf = calloc(s->bufframes, s->record.frame_size)) == NULL) { + ret = CUBEB_ERROR; + goto error; + } @@ -1161,10 +1199,7 @@ +oss_stream_thr_create(cubeb_stream * s) +{ + if (s->thread_created) { -+ pthread_mutex_lock(&s->mtx); + pthread_cond_signal(&s->doorbell_cv); -+ pthread_mutex_unlock(&s->mtx); -+ + return CUBEB_OK; + } +