mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 09:35:40 +00:00
Merge pull request #1164 from ggrtk/update-cubeb
dep/cubeb: Update to 70fadbf
This commit is contained in:
commit
986e52990e
|
@ -22,7 +22,10 @@ endif()
|
||||||
set(CMAKE_CXX_WARNING_LEVEL 4)
|
set(CMAKE_CXX_WARNING_LEVEL 4)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -fno-exceptions -fno-rtti")
|
||||||
|
else()
|
||||||
|
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable RTTI
|
||||||
|
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable Exceptions
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(cubeb
|
add_library(cubeb
|
||||||
|
@ -122,6 +125,26 @@ if(HAVE_SYS_SOUNDCARD_H)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
check_include_files(aaudio/AAudio.h USE_AAUDIO)
|
||||||
|
if(USE_AAUDIO)
|
||||||
|
target_sources(cubeb PRIVATE
|
||||||
|
src/cubeb_aaudio.cpp)
|
||||||
|
target_compile_definitions(cubeb PRIVATE USE_AAUDIO)
|
||||||
|
|
||||||
|
# set this definition to enable low latency mode. Possibly bad for battery
|
||||||
|
target_compile_definitions(cubeb PRIVATE CUBEB_AAUDIO_LOW_LATENCY)
|
||||||
|
|
||||||
|
# set this definition to enable power saving mode. Possibly resulting
|
||||||
|
# in high latency
|
||||||
|
# target_compile_definitions(cubeb PRIVATE CUBEB_AAUDIO_LOW_POWER_SAVING)
|
||||||
|
|
||||||
|
# set this mode to make the backend use an exclusive stream.
|
||||||
|
# will decrease latency.
|
||||||
|
# target_compile_definitions(cubeb PRIVATE CUBEB_AAUDIO_EXCLUSIVE_STREAM)
|
||||||
|
|
||||||
|
target_link_libraries(cubeb PRIVATE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
check_include_files(android/log.h USE_AUDIOTRACK)
|
check_include_files(android/log.h USE_AUDIOTRACK)
|
||||||
if(USE_AUDIOTRACK)
|
if(USE_AUDIOTRACK)
|
||||||
target_sources(cubeb PRIVATE
|
target_sources(cubeb PRIVATE
|
||||||
|
|
|
@ -509,7 +509,9 @@ CUBEB_EXPORT void cubeb_destroy(cubeb * context);
|
||||||
cubeb_devid allows the stream to follow that device type's
|
cubeb_devid allows the stream to follow that device type's
|
||||||
OS default.
|
OS default.
|
||||||
@param output_stream_params Parameters for the output side of the stream, or
|
@param output_stream_params Parameters for the output side of the stream, or
|
||||||
NULL if this stream is input only.
|
NULL if this stream is input only. When input
|
||||||
|
and output stream parameters are supplied, their
|
||||||
|
rate has to be the same.
|
||||||
@param latency_frames Stream latency in frames. Valid range
|
@param latency_frames Stream latency in frames. Valid range
|
||||||
is [1, 96000].
|
is [1, 96000].
|
||||||
@param data_callback Will be called to preroll data before playback is
|
@param data_callback Will be called to preroll data before playback is
|
||||||
|
|
|
@ -63,6 +63,9 @@ int opensl_init(cubeb ** context, char const * context_name);
|
||||||
#if defined(USE_OSS)
|
#if defined(USE_OSS)
|
||||||
int oss_init(cubeb ** context, char const * context_name);
|
int oss_init(cubeb ** context, char const * context_name);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(USE_AAUDIO)
|
||||||
|
int aaudio_init(cubeb ** context, char const * context_name);
|
||||||
|
#endif
|
||||||
#if defined(USE_AUDIOTRACK)
|
#if defined(USE_AUDIOTRACK)
|
||||||
int audiotrack_init(cubeb ** context, char const * context_name);
|
int audiotrack_init(cubeb ** context, char const * context_name);
|
||||||
#endif
|
#endif
|
||||||
|
@ -172,6 +175,10 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam
|
||||||
} else if (!strcmp(backend_name, "oss")) {
|
} else if (!strcmp(backend_name, "oss")) {
|
||||||
#if defined(USE_OSS)
|
#if defined(USE_OSS)
|
||||||
init_oneshot = oss_init;
|
init_oneshot = oss_init;
|
||||||
|
#endif
|
||||||
|
} else if (!strcmp(backend_name, "aaudio")) {
|
||||||
|
#if defined(USE_AAUDIO)
|
||||||
|
init_oneshot = aaudio_init;
|
||||||
#endif
|
#endif
|
||||||
} else if (!strcmp(backend_name, "audiotrack")) {
|
} else if (!strcmp(backend_name, "audiotrack")) {
|
||||||
#if defined(USE_AUDIOTRACK)
|
#if defined(USE_AUDIOTRACK)
|
||||||
|
@ -227,6 +234,11 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_OPENSL)
|
#if defined(USE_OPENSL)
|
||||||
opensl_init,
|
opensl_init,
|
||||||
|
#endif
|
||||||
|
// TODO: should probably be preferred over OpenSLES when available.
|
||||||
|
// Initialization will fail on old android devices.
|
||||||
|
#if defined(USE_AAUDIO)
|
||||||
|
aaudio_init,
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_AUDIOTRACK)
|
#if defined(USE_AUDIOTRACK)
|
||||||
audiotrack_init,
|
audiotrack_init,
|
||||||
|
|
1488
dep/cubeb/src/cubeb_aaudio.cpp
Normal file
1488
dep/cubeb/src/cubeb_aaudio.cpp
Normal file
File diff suppressed because it is too large
Load diff
17
dep/cubeb/src/cubeb_android.h
Normal file
17
dep/cubeb/src/cubeb_android.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef CUBEB_ANDROID_H
|
||||||
|
#define CUBEB_ANDROID_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
// If the latency requested is above this threshold, this stream is considered
|
||||||
|
// intended for playback (vs. real-time). Tell Android it should favor saving
|
||||||
|
// power over performance or latency.
|
||||||
|
// This is around 100ms at 44100 or 48000
|
||||||
|
const uint16_t POWERSAVE_LATENCY_FRAMES_THRESHOLD = 4000;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CUBEB_ANDROID_H
|
|
@ -46,6 +46,7 @@ void cubeb_async_log_reset_threads();
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* Asynchronous verbose logging, to log in real-time callbacks. */
|
/* Asynchronous verbose logging, to log in real-time callbacks. */
|
||||||
|
/* Should not be used on android due to the use of global/static variables. */
|
||||||
#define ALOGV(fmt, ...) \
|
#define ALOGV(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
cubeb_async_log(fmt, ##__VA_ARGS__); \
|
cubeb_async_log(fmt, ##__VA_ARGS__); \
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "cubeb-sles.h"
|
#include "cubeb-sles.h"
|
||||||
#include "cubeb_array_queue.h"
|
#include "cubeb_array_queue.h"
|
||||||
#include "android/cubeb-output-latency.h"
|
#include "android/cubeb-output-latency.h"
|
||||||
|
#include "cubeb_android.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
|
@ -65,11 +66,6 @@
|
||||||
|
|
||||||
#define DEFAULT_SAMPLE_RATE 48000
|
#define DEFAULT_SAMPLE_RATE 48000
|
||||||
#define DEFAULT_NUM_OF_FRAMES 480
|
#define DEFAULT_NUM_OF_FRAMES 480
|
||||||
// If the latency requested is above this threshold, this stream is considered
|
|
||||||
// intended for playback (vs. real-time). Tell Android it should favor saving
|
|
||||||
// power over performance or latency.
|
|
||||||
// This is around 100ms at 44100 or 48000
|
|
||||||
#define POWERSAVE_LATENCY_FRAMES_THRESHOLD 4000
|
|
||||||
|
|
||||||
static struct cubeb_ops const opensl_ops;
|
static struct cubeb_ops const opensl_ops;
|
||||||
|
|
||||||
|
@ -1702,7 +1698,7 @@ opensl_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
|
||||||
assert(latency);
|
assert(latency);
|
||||||
|
|
||||||
uint32_t stream_latency_frames =
|
uint32_t stream_latency_frames =
|
||||||
stm->user_output_rate * (stm->output_latency_ms / 1000);
|
stm->user_output_rate * stm->output_latency_ms / 1000;
|
||||||
|
|
||||||
return stream_latency_frames + cubeb_resampler_latency(stm->resampler);
|
return stream_latency_frames + cubeb_resampler_latency(stm->resampler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -741,6 +741,46 @@ oss_linear16_set_vol(int16_t * buf, unsigned sample_count, float vol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
oss_get_rec_frames(cubeb_stream * s, unsigned int nframes)
|
||||||
|
{
|
||||||
|
size_t rem = nframes * s->record.frame_size;
|
||||||
|
size_t read_ofs = 0;
|
||||||
|
while (rem > 0) {
|
||||||
|
ssize_t n;
|
||||||
|
if ((n = read(s->record.fd, (uint8_t *)s->record.buf + read_ofs, rem)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return CUBEB_ERROR;
|
||||||
|
}
|
||||||
|
read_ofs += n;
|
||||||
|
rem -= n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
oss_put_play_frames(cubeb_stream * s, unsigned int nframes)
|
||||||
|
{
|
||||||
|
size_t rem = nframes * s->play.frame_size;
|
||||||
|
size_t write_ofs = 0;
|
||||||
|
while (rem > 0) {
|
||||||
|
ssize_t n;
|
||||||
|
if ((n = write(s->play.fd, (uint8_t *)s->play.buf + write_ofs, rem)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return CUBEB_ERROR;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&s->mtx);
|
||||||
|
s->frames_written += n / s->play.frame_size;
|
||||||
|
pthread_mutex_unlock(&s->mtx);
|
||||||
|
write_ofs += n;
|
||||||
|
rem -= n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 1 - Stopped by cubeb_stream_stop, otherwise 0 */
|
/* 1 - Stopped by cubeb_stream_stop, otherwise 0 */
|
||||||
static int
|
static int
|
||||||
oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
||||||
|
@ -748,18 +788,10 @@ oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
||||||
cubeb_state state = CUBEB_STATE_STOPPED;
|
cubeb_state state = CUBEB_STATE_STOPPED;
|
||||||
int trig = 0;
|
int trig = 0;
|
||||||
int drain = 0;
|
int drain = 0;
|
||||||
struct pollfd pfds[2];
|
const bool play_on = s->play.fd != -1, record_on = s->record.fd != -1;
|
||||||
unsigned int ppending, rpending;
|
long nfr = s->bufframes;
|
||||||
|
|
||||||
pfds[0].fd = s->play.fd;
|
if (record_on) {
|
||||||
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)) {
|
if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig)) {
|
||||||
LOG("Error %d occured when setting trigger on record fd", errno);
|
LOG("Error %d occured when setting trigger on record fd", errno);
|
||||||
state = CUBEB_STATE_ERROR;
|
state = CUBEB_STATE_ERROR;
|
||||||
|
@ -771,43 +803,35 @@ oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
||||||
state = CUBEB_STATE_ERROR;
|
state = CUBEB_STATE_ERROR;
|
||||||
goto breakdown;
|
goto breakdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(s->record.buf, 0, s->bufframes * s->record.frame_size);
|
memset(s->record.buf, 0, s->bufframes * s->record.frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
if (!play_on && !record_on) {
|
||||||
long nfr = 0;
|
/*
|
||||||
|
* Stop here if the stream is not play & record stream,
|
||||||
|
* play-only stream or record-only stream
|
||||||
|
*/
|
||||||
|
|
||||||
|
goto breakdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
pthread_mutex_lock(&s->mtx);
|
pthread_mutex_lock(&s->mtx);
|
||||||
if (!s->running || s->destroying) {
|
if (!s->running || s->destroying) {
|
||||||
pthread_mutex_unlock(&s->mtx);
|
pthread_mutex_unlock(&s->mtx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&s->mtx);
|
pthread_mutex_unlock(&s->mtx);
|
||||||
if (s->play.fd == -1 && s->record.fd == -1) {
|
|
||||||
/*
|
|
||||||
* Stop here if the stream is not play & record stream,
|
|
||||||
* play-only stream or record-only stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
goto breakdown;
|
long got = 0;
|
||||||
}
|
if (nfr > 0) {
|
||||||
|
got = s->data_cb(s, s->user_ptr, s->record.buf, s->play.buf, nfr);
|
||||||
while ((s->bufframes - ppending) >= s->nfr && rpending >= s->nfr) {
|
if (got == CUBEB_ERROR) {
|
||||||
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;
|
state = CUBEB_STATE_ERROR;
|
||||||
goto breakdown;
|
goto breakdown;
|
||||||
}
|
}
|
||||||
if (pptr) {
|
if (play_on) {
|
||||||
float vol;
|
float vol;
|
||||||
|
|
||||||
pthread_mutex_lock(&s->mtx);
|
pthread_mutex_lock(&s->mtx);
|
||||||
|
@ -815,25 +839,15 @@ oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
||||||
pthread_mutex_unlock(&s->mtx);
|
pthread_mutex_unlock(&s->mtx);
|
||||||
|
|
||||||
if (s->play.floating) {
|
if (s->play.floating) {
|
||||||
oss_float_to_linear32(pptr, s->play.info.channels * nfr, vol);
|
oss_float_to_linear32(s->play.buf, s->play.info.channels * got, vol);
|
||||||
} else {
|
} else {
|
||||||
oss_linear16_set_vol((int16_t *)pptr, s->play.info.channels * nfr, vol);
|
oss_linear16_set_vol((int16_t *)s->play.buf,
|
||||||
|
s->play.info.channels * got, vol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pptr) {
|
if (got < nfr) {
|
||||||
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) {
|
if (s->play.fd != -1) {
|
||||||
drain = 1;
|
drain = 1;
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* This is a record-only stream and number of frames
|
* This is a record-only stream and number of frames
|
||||||
|
@ -845,74 +859,48 @@ oss_audio_loop(cubeb_stream * s, cubeb_state *new_state)
|
||||||
goto breakdown;
|
goto breakdown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nfr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t n, frames;
|
if (got > 0) {
|
||||||
int nfds;
|
if (play_on && oss_put_play_frames(s, got) < 0) {
|
||||||
|
|
||||||
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 breakdown;
|
|
||||||
} 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 breakdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
state = CUBEB_STATE_ERROR;
|
||||||
goto breakdown;
|
goto breakdown;
|
||||||
}
|
|
||||||
frames = n / s->play.frame_size;
|
|
||||||
pthread_mutex_lock(&s->mtx);
|
|
||||||
s->frames_written += frames;
|
|
||||||
pthread_mutex_unlock(&s->mtx);
|
|
||||||
ppending -= frames;
|
|
||||||
memmove(s->play.buf, (uint8_t *)s->play.buf + n,
|
|
||||||
(s->bufframes - frames) * s->play.frame_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 breakdown;
|
|
||||||
}
|
|
||||||
frames = n / s->record.frame_size;
|
|
||||||
rpending += frames;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drain) {
|
if (drain) {
|
||||||
state = CUBEB_STATE_DRAINED;
|
state = CUBEB_STATE_DRAINED;
|
||||||
goto breakdown;
|
goto breakdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio_buf_info bi;
|
||||||
|
if (play_on) {
|
||||||
|
if (ioctl(s->play.fd, SNDCTL_DSP_GETOSPACE, &bi)) {
|
||||||
|
state = CUBEB_STATE_ERROR;
|
||||||
|
goto breakdown;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* In duplex mode, playback direction drives recording direction to
|
||||||
|
* prevent building up latencies.
|
||||||
|
*/
|
||||||
|
nfr = bi.fragsize * bi.fragments / s->play.frame_size;
|
||||||
|
if (nfr > s->bufframes) {
|
||||||
|
nfr = s->bufframes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record_on) {
|
||||||
|
if (nfr == 0) {
|
||||||
|
nfr = s->nfr;
|
||||||
|
}
|
||||||
|
if (oss_get_rec_frames(s, nfr) == CUBEB_ERROR) {
|
||||||
|
state = CUBEB_STATE_ERROR;
|
||||||
|
goto breakdown;
|
||||||
|
}
|
||||||
|
if (s->record.floating) {
|
||||||
|
oss_linear32_to_float(s->record.buf, s->record.info.channels * nfr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1035,7 +1023,7 @@ oss_stream_init(cubeb * context,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (s->record.fd == -1) {
|
if (s->record.fd == -1) {
|
||||||
if ((s->record.fd = open(s->record.name, O_RDONLY | O_NONBLOCK)) == -1) {
|
if ((s->record.fd = open(s->record.name, O_RDONLY)) == -1) {
|
||||||
LOG("Audio device \"%s\" could not be opened as read-only",
|
LOG("Audio device \"%s\" could not be opened as read-only",
|
||||||
s->record.name);
|
s->record.name);
|
||||||
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||||
|
@ -1066,7 +1054,7 @@ oss_stream_init(cubeb * context,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (s->play.fd == -1) {
|
if (s->play.fd == -1) {
|
||||||
if ((s->play.fd = open(s->play.name, O_WRONLY | O_NONBLOCK)) == -1) {
|
if ((s->play.fd = open(s->play.name, O_WRONLY)) == -1) {
|
||||||
LOG("Audio device \"%s\" could not be opened as write-only",
|
LOG("Audio device \"%s\" could not be opened as write-only",
|
||||||
s->play.name);
|
s->play.name);
|
||||||
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
|
||||||
|
@ -1082,22 +1070,40 @@ oss_stream_init(cubeb * context,
|
||||||
s->play.frame_size = s->play.info.channels * (s->play.info.precision / 8);
|
s->play.frame_size = s->play.info.channels * (s->play.info.precision / 8);
|
||||||
playnfr = (1 << oss_calc_frag_shift(s->nfr, s->play.frame_size)) / s->play.frame_size;
|
playnfr = (1 << oss_calc_frag_shift(s->nfr, s->play.frame_size)) / s->play.frame_size;
|
||||||
}
|
}
|
||||||
/* Use the largest nframes among playing and recording streams */
|
/*
|
||||||
|
* Use the largest nframes among playing and recording streams to set OSS buffer size.
|
||||||
|
* After that, use the smallest allocated nframes among both direction to allocate our
|
||||||
|
* temporary buffers.
|
||||||
|
*/
|
||||||
s->nfr = (playnfr > recnfr) ? playnfr : recnfr;
|
s->nfr = (playnfr > recnfr) ? playnfr : recnfr;
|
||||||
s->nfrags = OSS_NFRAGS;
|
s->nfrags = OSS_NFRAGS;
|
||||||
s->bufframes = s->nfr * s->nfrags;
|
|
||||||
if (s->play.fd != -1) {
|
if (s->play.fd != -1) {
|
||||||
int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->play.frame_size));
|
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))
|
if (ioctl(s->play.fd, SNDCTL_DSP_SETFRAGMENT, &frag))
|
||||||
LOG("Failed to set record fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
|
LOG("Failed to set play fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
|
||||||
frag);
|
frag);
|
||||||
|
audio_buf_info bi;
|
||||||
|
if (ioctl(s->play.fd, SNDCTL_DSP_GETOSPACE, &bi))
|
||||||
|
LOG("Failed to get play fd's buffer info.");
|
||||||
|
else {
|
||||||
|
if (bi.fragsize / s->play.frame_size < s->nfr)
|
||||||
|
s->nfr = bi.fragsize / s->play.frame_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (s->record.fd != -1) {
|
if (s->record.fd != -1) {
|
||||||
int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->record.frame_size));
|
int frag = oss_get_frag_params(oss_calc_frag_shift(s->nfr, s->record.frame_size));
|
||||||
if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag))
|
if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag))
|
||||||
LOG("Failed to set record fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
|
LOG("Failed to set record fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
|
||||||
frag);
|
frag);
|
||||||
|
audio_buf_info bi;
|
||||||
|
if (ioctl(s->record.fd, SNDCTL_DSP_GETISPACE, &bi))
|
||||||
|
LOG("Failed to get record fd's buffer info.");
|
||||||
|
else {
|
||||||
|
if (bi.fragsize / s->record.frame_size < s->nfr)
|
||||||
|
s->nfr = bi.fragsize / s->record.frame_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
s->bufframes = s->nfr * s->nfrags;
|
||||||
s->context = context;
|
s->context = context;
|
||||||
s->volume = 1.0;
|
s->volume = 1.0;
|
||||||
s->state_cb = state_callback;
|
s->state_cb = state_callback;
|
||||||
|
|
|
@ -2030,6 +2030,23 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
||||||
com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
|
com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
|
||||||
|
|
||||||
mix_format->wBitsPerSample = stm->bytes_per_sample * 8;
|
mix_format->wBitsPerSample = stm->bytes_per_sample * 8;
|
||||||
|
if (mix_format->wFormatTag == WAVE_FORMAT_PCM ||
|
||||||
|
mix_format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
|
||||||
|
switch (mix_format->wBitsPerSample) {
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
mix_format->wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
mix_format->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG("%u bits per sample is incompatible with PCM wave formats",
|
||||||
|
mix_format->wBitsPerSample);
|
||||||
|
return CUBEB_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mix_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
if (mix_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||||
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
|
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
|
||||||
format_pcm->SubFormat = stm->waveformatextensible_sub_format;
|
format_pcm->SubFormat = stm->waveformatextensible_sub_format;
|
||||||
|
@ -2085,9 +2102,11 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
||||||
cubeb_device_info device_info;
|
cubeb_device_info device_info;
|
||||||
int rv = wasapi_create_device(stm->context, device_info, stm->device_enumerator.get(), device.get());
|
int rv = wasapi_create_device(stm->context, device_info, stm->device_enumerator.get(), device.get());
|
||||||
if (rv == CUBEB_OK) {
|
if (rv == CUBEB_OK) {
|
||||||
const char* HANDSFREE_TAG = "BTHHFEENUM";
|
const char* HANDSFREE_TAG = "BTHHFENUM";
|
||||||
size_t len = sizeof(HANDSFREE_TAG);
|
size_t len = sizeof(HANDSFREE_TAG);
|
||||||
if (direction == eCapture && strncmp(device_info.group_id, HANDSFREE_TAG, len) == 0) {
|
if (direction == eCapture &&
|
||||||
|
strlen(device_info.group_id) >= len &&
|
||||||
|
strncmp(device_info.group_id, HANDSFREE_TAG, len) == 0) {
|
||||||
// Rather high-latency to prevent constant under-runs in this particular
|
// Rather high-latency to prevent constant under-runs in this particular
|
||||||
// case of an input device using bluetooth handsfree.
|
// case of an input device using bluetooth handsfree.
|
||||||
uint32_t default_period_frames = hns_to_frames(device_info.default_rate, default_period);
|
uint32_t default_period_frames = hns_to_frames(device_info.default_rate, default_period);
|
||||||
|
@ -2202,7 +2221,7 @@ void wasapi_find_matching_output_device(cubeb_stream * stm) {
|
||||||
for (uint32_t i = 0; i < collection.count; i++) {
|
for (uint32_t i = 0; i < collection.count; i++) {
|
||||||
cubeb_device_info dev = collection.device[i];
|
cubeb_device_info dev = collection.device[i];
|
||||||
if (dev.type == CUBEB_DEVICE_TYPE_OUTPUT &&
|
if (dev.type == CUBEB_DEVICE_TYPE_OUTPUT &&
|
||||||
dev.group_id && input_device && !strcmp(dev.group_id, input_device->group_id) &&
|
dev.group_id && !strcmp(dev.group_id, input_device->group_id) &&
|
||||||
dev.default_rate == input_device->default_rate) {
|
dev.default_rate == input_device->default_rate) {
|
||||||
LOG("Found matching device for %s: %s", input_device->friendly_name, dev.friendly_name);
|
LOG("Found matching device for %s: %s", input_device->friendly_name, dev.friendly_name);
|
||||||
stm->output_device_id = utf8_to_wstr(reinterpret_cast<char const *>(dev.devid));
|
stm->output_device_id = utf8_to_wstr(reinterpret_cast<char const *>(dev.devid));
|
||||||
|
|
Loading…
Reference in a new issue