зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1895787
- Update libcubeb. r=cubeb-reviewers,padenot
Patches have conflicts so they are updated and applied in separate patches. Differential Revision: https://phabricator.services.mozilla.com/D211044
This commit is contained in:
Родитель
e71ae3a83f
Коммит
6b01a9d1e2
|
@ -9,8 +9,8 @@ origin:
|
|||
description: "Cross platform audio library"
|
||||
url: https://github.com/mozilla/cubeb
|
||||
license: ISC
|
||||
release: 74d6b0546576d9ee13a078ed51f87a6eede62014 (2024-02-15T12:42:53Z).
|
||||
revision: 74d6b0546576d9ee13a078ed51f87a6eede62014
|
||||
release: 6c1a6e151c1f981a2800d40af7c041cfcccc710e (2024-05-21T16:11:12Z).
|
||||
revision: 6c1a6e151c1f981a2800d40af7c041cfcccc710e
|
||||
|
||||
vendoring:
|
||||
url: https://github.com/mozilla/cubeb
|
||||
|
|
|
@ -95,7 +95,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
|
|||
XASSERT(input_stream_params || output_stream_params);
|
||||
if (output_stream_params) {
|
||||
if (output_stream_params->rate < 1000 ||
|
||||
output_stream_params->rate > 384000 ||
|
||||
output_stream_params->rate > 768000 ||
|
||||
output_stream_params->channels < 1 ||
|
||||
output_stream_params->channels > UINT8_MAX) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
|
@ -103,7 +103,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
|
|||
}
|
||||
if (input_stream_params) {
|
||||
if (input_stream_params->rate < 1000 ||
|
||||
input_stream_params->rate > 384000 ||
|
||||
input_stream_params->rate > 768000 ||
|
||||
input_stream_params->channels < 1 ||
|
||||
input_stream_params->channels > UINT8_MAX) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "cubeb_resampler.h"
|
||||
#include "cubeb_triple_buffer.h"
|
||||
#include <aaudio/AAudio.h>
|
||||
#include <android/api-level.h>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
|
@ -245,13 +244,24 @@ shutdown_with_error(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
int64_t poll_frequency_ns = NS_PER_S * stm->out_frame_size / stm->sample_rate;
|
||||
int rv;
|
||||
if (stm->istream) {
|
||||
wait_for_state_change(stm->istream, AAUDIO_STREAM_STATE_STOPPED,
|
||||
rv = wait_for_state_change(stm->istream, AAUDIO_STREAM_STATE_STOPPED,
|
||||
poll_frequency_ns);
|
||||
if (rv != CUBEB_OK) {
|
||||
LOG("Failure when waiting for stream change on the input side when "
|
||||
"shutting down in error");
|
||||
// Not much we can do, carry on
|
||||
}
|
||||
}
|
||||
if (stm->ostream) {
|
||||
wait_for_state_change(stm->ostream, AAUDIO_STREAM_STATE_STOPPED,
|
||||
rv = wait_for_state_change(stm->ostream, AAUDIO_STREAM_STATE_STOPPED,
|
||||
poll_frequency_ns);
|
||||
if (rv != CUBEB_OK) {
|
||||
LOG("Failure when waiting for stream change on the output side when "
|
||||
"shutting down in error");
|
||||
// Not much we can do, carry on
|
||||
}
|
||||
}
|
||||
|
||||
assert(!stm->in_data_callback.load());
|
||||
|
@ -921,7 +931,7 @@ aaudio_error_cb(AAudioStream * astream, void * user_data, aaudio_result_t error)
|
|||
assert(stm->ostream == astream || stm->istream == astream);
|
||||
|
||||
// Device change -- reinitialize on the new default device.
|
||||
if (error == AAUDIO_ERROR_DISCONNECTED) {
|
||||
if (error == AAUDIO_ERROR_DISCONNECTED || error == AAUDIO_ERROR_TIMEOUT) {
|
||||
LOG("Audio device change, reinitializing stream");
|
||||
reinitialize_stream(stm);
|
||||
return;
|
||||
|
@ -1762,9 +1772,6 @@ const static struct cubeb_ops aaudio_ops = {
|
|||
extern "C" /*static*/ int
|
||||
aaudio_init(cubeb ** context, char const * /* context_name */)
|
||||
{
|
||||
if (android_get_device_api_level() <= 30) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
// load api
|
||||
void * libaaudio = nullptr;
|
||||
#ifndef DISABLE_LIBAAUDIO_DLOPEN
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright © 2023 Mozilla Foundation
|
||||
*
|
||||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
*/
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include "cubeb_audio_dump.h"
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "cubeb_ringbuffer.h"
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using std::thread;
|
||||
using std::vector;
|
||||
|
||||
uint32_t
|
||||
bytes_per_sample(cubeb_stream_params params)
|
||||
{
|
||||
switch (params.format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
case CUBEB_SAMPLE_S16BE:
|
||||
return sizeof(int16_t);
|
||||
case CUBEB_SAMPLE_FLOAT32LE:
|
||||
case CUBEB_SAMPLE_FLOAT32BE:
|
||||
return sizeof(float);
|
||||
};
|
||||
}
|
||||
|
||||
struct cubeb_audio_dump_stream {
|
||||
public:
|
||||
explicit cubeb_audio_dump_stream(cubeb_stream_params params)
|
||||
: sample_size(bytes_per_sample(params)),
|
||||
ringbuffer(
|
||||
static_cast<int>(params.rate * params.channels * sample_size))
|
||||
{
|
||||
}
|
||||
|
||||
int open(const char * name)
|
||||
{
|
||||
file = fopen(name, "wb");
|
||||
if (!file) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
int close()
|
||||
{
|
||||
if (fclose(file)) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
// Directly write to the file. Useful to write the header.
|
||||
size_t write(uint8_t * data, uint32_t count)
|
||||
{
|
||||
return fwrite(data, count, 1, file);
|
||||
}
|
||||
|
||||
size_t write_all()
|
||||
{
|
||||
size_t written = 0;
|
||||
const int buf_sz = 16 * 1024;
|
||||
uint8_t buf[buf_sz];
|
||||
while (int rv = ringbuffer.dequeue(buf, buf_sz)) {
|
||||
written += fwrite(buf, rv, 1, file);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
int dump(void * samples, uint32_t count)
|
||||
{
|
||||
int bytes = static_cast<int>(count * sample_size);
|
||||
int rv = ringbuffer.enqueue(static_cast<uint8_t *>(samples), bytes);
|
||||
return rv == bytes;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t sample_size;
|
||||
FILE * file{};
|
||||
lock_free_queue<uint8_t> ringbuffer;
|
||||
};
|
||||
|
||||
struct cubeb_audio_dump_session {
|
||||
public:
|
||||
cubeb_audio_dump_session() = default;
|
||||
~cubeb_audio_dump_session()
|
||||
{
|
||||
assert(streams.empty());
|
||||
session_thread.join();
|
||||
}
|
||||
cubeb_audio_dump_session(const cubeb_audio_dump_session &) = delete;
|
||||
cubeb_audio_dump_session &
|
||||
operator=(const cubeb_audio_dump_session &) = delete;
|
||||
cubeb_audio_dump_session & operator=(cubeb_audio_dump_session &&) = delete;
|
||||
|
||||
cubeb_audio_dump_stream_t create_stream(cubeb_stream_params params,
|
||||
const char * name)
|
||||
{
|
||||
if (running) {
|
||||
return nullptr;
|
||||
}
|
||||
auto * stream = new cubeb_audio_dump_stream(params);
|
||||
streams.push_back(stream);
|
||||
int rv = stream->open(name);
|
||||
if (rv != CUBEB_OK) {
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct riff_header {
|
||||
char chunk_id[4] = {'R', 'I', 'F', 'F'};
|
||||
int32_t chunk_size = 0;
|
||||
char format[4] = {'W', 'A', 'V', 'E'};
|
||||
|
||||
char subchunk_id_1[4] = {'f', 'm', 't', 0x20};
|
||||
int32_t subchunk_1_size = 16;
|
||||
int16_t audio_format{};
|
||||
int16_t num_channels{};
|
||||
int32_t sample_rate{};
|
||||
int32_t byte_rate{};
|
||||
int16_t block_align{};
|
||||
int16_t bits_per_sample{};
|
||||
|
||||
char subchunk_id_2[4] = {'d', 'a', 't', 'a'};
|
||||
int32_t subchunkd_2_size = std::numeric_limits<int32_t>::max();
|
||||
};
|
||||
|
||||
riff_header header;
|
||||
// 1 is integer PCM, 3 is float PCM
|
||||
header.audio_format = bytes_per_sample(params) == 2 ? 1 : 3;
|
||||
header.num_channels = params.channels;
|
||||
header.sample_rate = params.rate;
|
||||
header.byte_rate = bytes_per_sample(params) * params.rate * params.channels;
|
||||
header.block_align = params.channels * bytes_per_sample(params);
|
||||
header.bits_per_sample = bytes_per_sample(params) * 8;
|
||||
|
||||
stream->write(reinterpret_cast<uint8_t *>(&header), sizeof(riff_header));
|
||||
|
||||
return stream;
|
||||
}
|
||||
int delete_stream(cubeb_audio_dump_stream * stream)
|
||||
{
|
||||
assert(!running);
|
||||
stream->close();
|
||||
streams.erase(std::remove(streams.begin(), streams.end(), stream),
|
||||
streams.end());
|
||||
return CUBEB_OK;
|
||||
}
|
||||
int start()
|
||||
{
|
||||
assert(!running);
|
||||
running = true;
|
||||
session_thread = std::thread([this] {
|
||||
while (running) {
|
||||
for (auto * stream : streams) {
|
||||
stream->write_all();
|
||||
}
|
||||
const int DUMP_INTERVAL = 10;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(DUMP_INTERVAL));
|
||||
}
|
||||
});
|
||||
return CUBEB_OK;
|
||||
}
|
||||
int stop()
|
||||
{
|
||||
assert(running);
|
||||
running = false;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
thread session_thread;
|
||||
vector<cubeb_audio_dump_stream_t> streams{};
|
||||
std::atomic<bool> running = false;
|
||||
};
|
||||
|
||||
int
|
||||
cubeb_audio_dump_init(cubeb_audio_dump_session_t * session)
|
||||
{
|
||||
*session = new cubeb_audio_dump_session;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_shutdown(cubeb_audio_dump_session_t session)
|
||||
{
|
||||
delete session;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_stream_init(cubeb_audio_dump_session_t session,
|
||||
cubeb_audio_dump_stream_t * stream,
|
||||
cubeb_stream_params stream_params,
|
||||
const char * name)
|
||||
{
|
||||
*stream = session->create_stream(stream_params, name);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_stream_shutdown(cubeb_audio_dump_session_t session,
|
||||
cubeb_audio_dump_stream_t stream)
|
||||
{
|
||||
return session->delete_stream(stream);
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_start(cubeb_audio_dump_session_t session)
|
||||
{
|
||||
return session->start();
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_stop(cubeb_audio_dump_session_t session)
|
||||
{
|
||||
return session->stop();
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_audio_dump_write(cubeb_audio_dump_stream_t stream, void * audio_samples,
|
||||
uint32_t count)
|
||||
{
|
||||
stream->dump(audio_samples, count);
|
||||
return CUBEB_OK;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright © 2023 Mozilla Foundation
|
||||
*
|
||||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef CUBEB_AUDIO_DUMP
|
||||
#define CUBEB_AUDIO_DUMP
|
||||
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct cubeb_audio_dump_stream * cubeb_audio_dump_stream_t;
|
||||
typedef struct cubeb_audio_dump_session * cubeb_audio_dump_session_t;
|
||||
|
||||
// Start audio dumping session
|
||||
// This can only be called if the other API functions
|
||||
// aren't currently being called: synchronized externally.
|
||||
// This is not real-time safe.
|
||||
//
|
||||
// This is generally called when deciding to start logging some audio.
|
||||
//
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_init(cubeb_audio_dump_session_t * session);
|
||||
|
||||
// End audio dumping session
|
||||
// This can only be called if the other API functions
|
||||
// aren't currently being called: synchronized externally.
|
||||
//
|
||||
// This is generally called when deciding to stop logging some audio.
|
||||
//
|
||||
// This is not real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_shutdown(cubeb_audio_dump_session_t session);
|
||||
|
||||
// Register a stream for dumping to a file
|
||||
// This can only be called if cubeb_audio_dump_write
|
||||
// isn't currently being called: synchronized externally.
|
||||
//
|
||||
// This is generally called when setting up a system-level stream side (either
|
||||
// input or output).
|
||||
//
|
||||
// This is not real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_stream_init(cubeb_audio_dump_session_t session,
|
||||
cubeb_audio_dump_stream_t * stream,
|
||||
cubeb_stream_params stream_params,
|
||||
const char * name);
|
||||
|
||||
// Unregister a stream for dumping to a file
|
||||
// This can only be called if cubeb_audio_dump_write
|
||||
// isn't currently being called: synchronized externally.
|
||||
//
|
||||
// This is generally called when a system-level audio stream side
|
||||
// (input/output) has been stopped and drained, and the audio callback isn't
|
||||
// going to be called.
|
||||
//
|
||||
// This is not real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_stream_shutdown(cubeb_audio_dump_session_t session,
|
||||
cubeb_audio_dump_stream_t stream);
|
||||
|
||||
// Start dumping.
|
||||
// cubeb_audio_dump_write can now be called.
|
||||
//
|
||||
// This starts dumping the audio to disk. Generally this is called when
|
||||
// cubeb_stream_start is caled is called, but can be called at the beginning of
|
||||
// the application.
|
||||
//
|
||||
// This is not real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_start(cubeb_audio_dump_session_t session);
|
||||
|
||||
// Stop dumping.
|
||||
// cubeb_audio_dump_write can't be called at this point.
|
||||
//
|
||||
// This stops dumping the audio to disk cubeb_stream_stop is caled is called,
|
||||
// but can be called before exiting the application.
|
||||
//
|
||||
// This is not real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_stop(cubeb_audio_dump_session_t session);
|
||||
|
||||
// Dump some audio samples for audio stream id.
|
||||
//
|
||||
// This is generally called from the real-time audio callback.
|
||||
//
|
||||
// This is real-time safe.
|
||||
// Returns 0 in case of success.
|
||||
int
|
||||
cubeb_audio_dump_write(cubeb_audio_dump_stream_t stream, void * audio_samples,
|
||||
uint32_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -41,15 +41,6 @@ using namespace std;
|
|||
typedef UInt32 AudioFormatFlags;
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
typedef UInt32 AudioDeviceID;
|
||||
typedef UInt32 AudioObjectID;
|
||||
const UInt32 kAudioObjectUnknown = 0;
|
||||
|
||||
#define AudioGetCurrentHostTime mach_absolute_time
|
||||
|
||||
#endif
|
||||
|
||||
#define AU_OUT_BUS 0
|
||||
#define AU_IN_BUS 1
|
||||
|
||||
|
@ -74,7 +65,6 @@ const char * PRIVATE_AGGREGATE_DEVICE_NAME = "CubebAggregateDevice";
|
|||
LOG(msg, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
/* Testing empirically, some headsets report a minimal latency that is very
|
||||
* low, but this does not work in practice. Lie and say the minimum is 256
|
||||
* frames. */
|
||||
|
@ -83,28 +73,27 @@ const uint32_t SAFE_MAX_LATENCY_FRAMES = 512;
|
|||
|
||||
const AudioObjectPropertyAddress DEFAULT_INPUT_DEVICE_PROPERTY_ADDRESS = {
|
||||
kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
const AudioObjectPropertyAddress DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
const AudioObjectPropertyAddress DEVICE_IS_ALIVE_PROPERTY_ADDRESS = {
|
||||
kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
const AudioObjectPropertyAddress DEVICES_PROPERTY_ADDRESS = {
|
||||
kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
const AudioObjectPropertyAddress INPUT_DATA_SOURCE_PROPERTY_ADDRESS = {
|
||||
kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeInput,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
const AudioObjectPropertyAddress OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS = {
|
||||
kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain};
|
||||
#endif
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
typedef uint32_t device_flags_value;
|
||||
|
||||
|
@ -125,22 +114,22 @@ static void
|
|||
audiounit_close_stream(cubeb_stream * stm);
|
||||
static int
|
||||
audiounit_setup_stream(cubeb_stream * stm);
|
||||
#if !TARGET_OS_IPHONE
|
||||
static vector<AudioObjectID>
|
||||
audiounit_get_devices_of_type(cubeb_device_type devtype);
|
||||
static UInt32
|
||||
audiounit_get_device_presentation_latency(AudioObjectID devid,
|
||||
AudioObjectPropertyScope scope);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static AudioObjectID
|
||||
audiounit_get_default_device_id(cubeb_device_type type);
|
||||
static int
|
||||
audiounit_uninstall_device_changed_callback(cubeb_stream * stm);
|
||||
static int
|
||||
audiounit_uninstall_system_changed_callback(cubeb_stream * stm);
|
||||
#endif
|
||||
|
||||
static void
|
||||
audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags);
|
||||
#endif
|
||||
|
||||
extern cubeb_ops const audiounit_ops;
|
||||
|
||||
|
@ -155,11 +144,9 @@ struct cubeb {
|
|||
cubeb_device_collection_changed_callback output_collection_changed_callback =
|
||||
nullptr;
|
||||
void * output_collection_changed_user_ptr = nullptr;
|
||||
#if !TARGET_OS_IPHONE
|
||||
// Store list of devices to detect changes
|
||||
vector<AudioObjectID> input_device_array;
|
||||
vector<AudioObjectID> output_device_array;
|
||||
#endif
|
||||
// The queue should be released when it’s no longer needed.
|
||||
dispatch_queue_t serial_queue =
|
||||
dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL);
|
||||
|
@ -199,7 +186,6 @@ struct device_info {
|
|||
device_flags_value flags = DEV_UNKNOWN;
|
||||
};
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
struct property_listener {
|
||||
AudioDeviceID device_id;
|
||||
const AudioObjectPropertyAddress * property_address;
|
||||
|
@ -213,7 +199,6 @@ struct property_listener {
|
|||
{
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct cubeb_stream {
|
||||
explicit cubeb_stream(cubeb * context);
|
||||
|
@ -272,26 +257,22 @@ struct cubeb_stream {
|
|||
/* This is true if a device change callback is currently running. */
|
||||
atomic<bool> switching_device{false};
|
||||
atomic<bool> buffer_size_change_state{false};
|
||||
#if !TARGET_OS_IPHONE
|
||||
AudioDeviceID aggregate_device_id =
|
||||
kAudioObjectUnknown; // the aggregate device id
|
||||
AudioObjectID plugin_id =
|
||||
kAudioObjectUnknown; // used to create aggregate device
|
||||
#endif
|
||||
/* Mixer interface */
|
||||
unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer;
|
||||
/* Buffer where remixing/resampling will occur when upmixing is required */
|
||||
/* Only accessed from callback thread */
|
||||
unique_ptr<uint8_t[]> temp_buffer;
|
||||
size_t temp_buffer_size = 0; // size in bytes.
|
||||
#if !TARGET_OS_IPHONE
|
||||
/* Listeners indicating what system events are monitored. */
|
||||
unique_ptr<property_listener> default_input_listener;
|
||||
unique_ptr<property_listener> default_output_listener;
|
||||
unique_ptr<property_listener> input_alive_listener;
|
||||
unique_ptr<property_listener> input_source_listener;
|
||||
unique_ptr<property_listener> output_source_listener;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -405,6 +386,14 @@ is_common_sample_rate(Float64 sample_rate)
|
|||
sample_rate == 88200 || sample_rate == 96000;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
typedef UInt32 AudioDeviceID;
|
||||
typedef UInt32 AudioObjectID;
|
||||
|
||||
#define AudioGetCurrentHostTime mach_absolute_time
|
||||
|
||||
#endif
|
||||
|
||||
uint64_t
|
||||
ConvertHostTimeToNanos(uint64_t host_time)
|
||||
{
|
||||
|
@ -772,13 +761,13 @@ audiounit_get_backend_id(cubeb * /* ctx */)
|
|||
return "audiounit";
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
|
||||
static int
|
||||
audiounit_stream_get_volume(cubeb_stream * stm, float * volume);
|
||||
static int
|
||||
audiounit_stream_set_volume(cubeb_stream * stm, float volume);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static int
|
||||
audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side)
|
||||
{
|
||||
|
@ -822,7 +811,6 @@ audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side)
|
|||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags)
|
||||
|
@ -834,13 +822,10 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags)
|
|||
audiounit_stream_stop_internal(stm);
|
||||
}
|
||||
|
||||
int r;
|
||||
#if !TARGET_OS_IPHONE
|
||||
r = audiounit_uninstall_device_changed_callback(stm);
|
||||
int r = audiounit_uninstall_device_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall all device change listeners.", stm);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
auto_lock lock(stm->mutex);
|
||||
|
@ -852,7 +837,6 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags)
|
|||
|
||||
audiounit_close_stream(stm);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
/* Reinit occurs in one of the following case:
|
||||
* - When the device is not alive any more
|
||||
* - When the default system device change.
|
||||
|
@ -882,11 +866,8 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (audiounit_setup_stream(stm) != CUBEB_OK) {
|
||||
LOG("(%p) Stream reinit failed.", stm);
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (flags & DEV_INPUT && input_device != kAudioObjectUnknown) {
|
||||
// Attempt to re-use the same device-id failed, so attempt again with
|
||||
// default input device.
|
||||
|
@ -898,7 +879,6 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vol_rv == CUBEB_OK) {
|
||||
|
@ -934,11 +914,9 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags)
|
|||
}
|
||||
|
||||
if (audiounit_reinit_stream(stm, flags) != CUBEB_OK) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall system changed callback", stm);
|
||||
}
|
||||
#endif
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
||||
LOG("(%p) Could not reopen the stream after switching.", stm);
|
||||
}
|
||||
|
@ -947,7 +925,6 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags)
|
|||
});
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static char const *
|
||||
event_addr_to_string(AudioObjectPropertySelector selector)
|
||||
{
|
||||
|
@ -1119,7 +1096,6 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
|||
return r;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static int
|
||||
audiounit_install_system_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
|
@ -1160,7 +1136,6 @@ audiounit_install_system_changed_callback(cubeb_stream * stm)
|
|||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
||||
|
@ -1237,7 +1212,7 @@ audiounit_get_acceptable_latency_range(AudioValueRange * latency_range)
|
|||
AudioDeviceID output_device_id;
|
||||
AudioObjectPropertyAddress output_device_buffer_size_range = {
|
||||
kAudioDevicePropertyBufferFrameSizeRange, kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT);
|
||||
if (output_device_id == kAudioObjectUnknown) {
|
||||
|
@ -1258,6 +1233,7 @@ audiounit_get_acceptable_latency_range(AudioValueRange * latency_range)
|
|||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
static AudioObjectID
|
||||
audiounit_get_default_device_id(cubeb_device_type type)
|
||||
|
@ -1280,7 +1256,6 @@ audiounit_get_default_device_id(cubeb_device_type type)
|
|||
|
||||
return devid;
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
int
|
||||
audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
||||
|
@ -1295,7 +1270,7 @@ audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
|||
AudioStreamBasicDescription stream_format;
|
||||
AudioObjectPropertyAddress stream_format_address = {
|
||||
kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
assert(ctx && max_channels);
|
||||
|
||||
|
@ -1334,16 +1309,17 @@ audiounit_get_min_latency(cubeb * /* ctx */, cubeb_stream_params /* params */,
|
|||
|
||||
*latency_frames =
|
||||
max<uint32_t>(latency_range.mMinimum, SAFE_MIN_LATENCY_FRAMES);
|
||||
return CUBEB_OK;
|
||||
#endif
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
*rate = 44100;
|
||||
return CUBEB_OK;
|
||||
// TODO
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
#else
|
||||
UInt32 size;
|
||||
OSStatus r;
|
||||
|
@ -1351,7 +1327,7 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
|
|||
AudioDeviceID output_device_id;
|
||||
AudioObjectPropertyAddress samplerate_address = {
|
||||
kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT);
|
||||
if (output_device_id == kAudioObjectUnknown) {
|
||||
|
@ -1367,9 +1343,8 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
|
|||
}
|
||||
|
||||
*rate = static_cast<uint32_t>(fsamplerate);
|
||||
|
||||
return CUBEB_OK;
|
||||
#endif
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static cubeb_channel_layout
|
||||
|
@ -1410,9 +1385,6 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout)
|
|||
static cubeb_channel_layout
|
||||
audiounit_get_preferred_channel_layout(AudioUnit output_unit)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return CUBEB_LAYOUT_STEREO;
|
||||
#else
|
||||
OSStatus rv = noErr;
|
||||
UInt32 size = 0;
|
||||
rv = AudioUnitGetPropertyInfo(
|
||||
|
@ -1437,7 +1409,6 @@ audiounit_get_preferred_channel_layout(AudioUnit output_unit)
|
|||
}
|
||||
|
||||
return audiounit_convert_channel_layout(layout.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
static cubeb_channel_layout
|
||||
|
@ -1471,10 +1442,8 @@ audiounit_get_current_channel_layout(AudioUnit output_unit)
|
|||
static int
|
||||
audiounit_create_unit(AudioUnit * unit, device_info * device);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static OSStatus
|
||||
audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype);
|
||||
#endif
|
||||
|
||||
static void
|
||||
audiounit_destroy(cubeb * ctx)
|
||||
|
@ -1496,7 +1465,6 @@ audiounit_destroy(cubeb * ctx)
|
|||
!ctx->output_collection_changed_callback &&
|
||||
!ctx->output_collection_changed_user_ptr);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
/* Unregister the callback if necessary. */
|
||||
if (ctx->input_collection_changed_callback) {
|
||||
audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_INPUT);
|
||||
|
@ -1504,7 +1472,6 @@ audiounit_destroy(cubeb * ctx)
|
|||
if (ctx->output_collection_changed_callback) {
|
||||
audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_OUTPUT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dispatch_release(ctx->serial_queue);
|
||||
|
@ -1632,14 +1599,13 @@ audiounit_layout_init(cubeb_stream * stm, io_side side)
|
|||
stm->context->layout);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static vector<AudioObjectID>
|
||||
audiounit_get_sub_devices(AudioDeviceID device_id)
|
||||
{
|
||||
vector<AudioDeviceID> sub_devices;
|
||||
AudioObjectPropertyAddress property_address = {
|
||||
kAudioAggregateDevicePropertyActiveSubDeviceList,
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
|
||||
UInt32 size = 0;
|
||||
OSStatus rv = AudioObjectGetPropertyDataSize(device_id, &property_address, 0,
|
||||
nullptr, &size);
|
||||
|
@ -1668,7 +1634,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id,
|
|||
{
|
||||
AudioObjectPropertyAddress address_plugin_bundle_id = {
|
||||
kAudioHardwarePropertyPlugInForBundleID, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
UInt32 size = 0;
|
||||
OSStatus r = AudioObjectGetPropertyDataSize(
|
||||
kAudioObjectSystemObject, &address_plugin_bundle_id, 0, NULL, &size);
|
||||
|
@ -1698,7 +1664,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id,
|
|||
|
||||
AudioObjectPropertyAddress create_aggregate_device_address = {
|
||||
kAudioPlugInCreateAggregateDevice, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
r = AudioObjectGetPropertyDataSize(
|
||||
*plugin_id, &create_aggregate_device_address, 0, nullptr, &size);
|
||||
if (r != noErr) {
|
||||
|
@ -1770,7 +1736,7 @@ get_device_name(AudioDeviceID id)
|
|||
CFStringRef UIname = nullptr;
|
||||
AudioObjectPropertyAddress address_uuid = {kAudioDevicePropertyDeviceUID,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
OSStatus err =
|
||||
AudioObjectGetPropertyData(id, &address_uuid, 0, nullptr, &size, &UIname);
|
||||
return (err == noErr) ? UIname : NULL;
|
||||
|
@ -1813,7 +1779,7 @@ audiounit_set_aggregate_sub_device_list(AudioDeviceID aggregate_device_id,
|
|||
|
||||
AudioObjectPropertyAddress aggregate_sub_device_list = {
|
||||
kAudioAggregateDevicePropertyFullSubDeviceList,
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
|
||||
UInt32 size = sizeof(CFMutableArrayRef);
|
||||
OSStatus rv = AudioObjectSetPropertyData(
|
||||
aggregate_device_id, &aggregate_sub_device_list, 0, nullptr, size,
|
||||
|
@ -1835,7 +1801,7 @@ audiounit_set_master_aggregate_device(const AudioDeviceID aggregate_device_id)
|
|||
assert(aggregate_device_id != kAudioObjectUnknown);
|
||||
AudioObjectPropertyAddress master_aggregate_sub_device = {
|
||||
kAudioAggregateDevicePropertyMasterSubDevice,
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
|
||||
|
||||
// Master become the 1st output sub device
|
||||
AudioDeviceID output_device_id =
|
||||
|
@ -1868,7 +1834,7 @@ audiounit_activate_clock_drift_compensation(
|
|||
assert(aggregate_device_id != kAudioObjectUnknown);
|
||||
AudioObjectPropertyAddress address_owned = {
|
||||
kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
UInt32 qualifier_data_size = sizeof(AudioObjectID);
|
||||
AudioClassID class_id = kAudioSubDeviceClassID;
|
||||
|
@ -1900,7 +1866,7 @@ audiounit_activate_clock_drift_compensation(
|
|||
|
||||
AudioObjectPropertyAddress address_drift = {
|
||||
kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
// Start from the second device since the first is the master clock
|
||||
for (UInt32 i = 1; i < subdevices_num; ++i) {
|
||||
|
@ -1969,7 +1935,7 @@ audiounit_workaround_for_airpod(cubeb_stream * stm)
|
|||
Float64 rate = input_nominal_rate;
|
||||
AudioObjectPropertyAddress addr = {kAudioDevicePropertyNominalSampleRate,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
OSStatus rv = AudioObjectSetPropertyData(stm->aggregate_device_id, &addr, 0,
|
||||
nullptr, sizeof(Float64), &rate);
|
||||
|
@ -2053,7 +2019,7 @@ audiounit_destroy_aggregate_device(AudioObjectID plugin_id,
|
|||
plugin_id != kAudioObjectUnknown);
|
||||
AudioObjectPropertyAddress destroy_aggregate_device_addr = {
|
||||
kAudioPlugInDestroyAggregateDevice, kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
UInt32 size;
|
||||
OSStatus rv = AudioObjectGetPropertyDataSize(
|
||||
plugin_id, &destroy_aggregate_device_addr, 0, NULL, &size);
|
||||
|
@ -2076,7 +2042,6 @@ audiounit_destroy_aggregate_device(AudioObjectID plugin_id,
|
|||
*aggregate_device_id = kAudioObjectUnknown;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
audiounit_new_unit_instance(AudioUnit * unit, device_info * device)
|
||||
|
@ -2213,9 +2178,6 @@ audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
|
|||
static uint32_t
|
||||
audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return latency_frames;
|
||||
#else
|
||||
// For the 1st stream set anything within safe min-max
|
||||
assert(audiounit_active_streams(stm->context) > 0);
|
||||
if (audiounit_active_streams(stm->context) == 1) {
|
||||
|
@ -2276,10 +2238,8 @@ audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
|
|||
|
||||
return max(min<uint32_t>(latency_frames, upper_latency_limit),
|
||||
SAFE_MIN_LATENCY_FRAMES);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
/*
|
||||
* Change buffer size is prone to deadlock thus we change it
|
||||
* following the steps:
|
||||
|
@ -2330,15 +2290,11 @@ buffer_size_changed_callback(void * inClientData, AudioUnit inUnit,
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames,
|
||||
io_side side)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return CUBEB_OK;
|
||||
#else
|
||||
AudioUnit au = stm->output_unit;
|
||||
AudioUnitScope au_scope = kAudioUnitScope_Input;
|
||||
AudioUnitElement au_element = AU_OUT_BUS;
|
||||
|
@ -2426,7 +2382,6 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames,
|
|||
LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side),
|
||||
new_size_frames);
|
||||
return CUBEB_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2643,7 +2598,6 @@ audiounit_setup_stream(cubeb_stream * stm)
|
|||
device_info in_dev_info = stm->input_device;
|
||||
device_info out_dev_info = stm->output_device;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (has_input(stm) && has_output(stm) &&
|
||||
stm->input_device.id != stm->output_device.id) {
|
||||
r = audiounit_create_aggregate_device(stm);
|
||||
|
@ -2661,10 +2615,6 @@ audiounit_setup_stream(cubeb_stream * stm)
|
|||
out_dev_info.flags = DEV_OUTPUT;
|
||||
}
|
||||
}
|
||||
#else
|
||||
in_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_INPUT;
|
||||
out_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_OUTPUT;
|
||||
#endif
|
||||
|
||||
if (has_input(stm)) {
|
||||
r = audiounit_create_unit(&stm->input_unit, &in_dev_info);
|
||||
|
@ -2806,10 +2756,8 @@ audiounit_setup_stream(cubeb_stream * stm)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
stm->current_latency_frames = audiounit_get_device_presentation_latency(
|
||||
stm->output_device.id, kAudioDevicePropertyScopeOutput);
|
||||
#endif
|
||||
|
||||
Float64 unit_s;
|
||||
UInt32 size = sizeof(unit_s);
|
||||
|
@ -2829,12 +2777,10 @@ audiounit_setup_stream(cubeb_stream * stm)
|
|||
ceilf(stm->output_hw_rate / stm->input_hw_rate);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
r = audiounit_install_device_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not install all device change callback.", stm);
|
||||
}
|
||||
#endif
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
@ -2882,25 +2828,21 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
}
|
||||
if (input_stream_params) {
|
||||
stm->input_stream_params = *input_stream_params;
|
||||
#if !TARGET_OS_IPHONE
|
||||
r = audiounit_set_device_info(
|
||||
stm.get(), reinterpret_cast<uintptr_t>(input_device), io_side::INPUT);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Fail to set device info for input.", stm.get());
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (output_stream_params) {
|
||||
stm->output_stream_params = *output_stream_params;
|
||||
#if !TARGET_OS_IPHONE
|
||||
r = audiounit_set_device_info(
|
||||
stm.get(), reinterpret_cast<uintptr_t>(output_device), io_side::OUTPUT);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Fail to set device info for output.", stm.get());
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -2916,13 +2858,11 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
return r;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
r = audiounit_install_system_changed_callback(stm.get());
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not install the device change callback.", stm.get());
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
*stream = stm.release();
|
||||
LOG("(%p) Cubeb stream init successful.", *stream);
|
||||
|
@ -2951,13 +2891,11 @@ audiounit_close_stream(cubeb_stream * stm)
|
|||
stm->resampler.reset();
|
||||
stm->mixer.reset();
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (stm->aggregate_device_id != kAudioObjectUnknown) {
|
||||
audiounit_destroy_aggregate_device(stm->plugin_id,
|
||||
&stm->aggregate_device_id);
|
||||
stm->aggregate_device_id = kAudioObjectUnknown;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2965,7 +2903,6 @@ audiounit_stream_destroy_internal(cubeb_stream * stm)
|
|||
{
|
||||
stm->context->mutex.assert_current_thread_owns();
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
int r = audiounit_uninstall_system_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
|
@ -2974,7 +2911,6 @@ audiounit_stream_destroy_internal(cubeb_stream * stm)
|
|||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall all device change listeners", stm);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto_lock lock(stm->mutex);
|
||||
audiounit_close_stream(stm);
|
||||
|
@ -2985,7 +2921,6 @@ audiounit_stream_destroy_internal(cubeb_stream * stm)
|
|||
static void
|
||||
audiounit_stream_destroy(cubeb_stream * stm)
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
int r = audiounit_uninstall_system_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
|
@ -2994,7 +2929,6 @@ audiounit_stream_destroy(cubeb_stream * stm)
|
|||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall all device change listeners", stm);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!stm->shutdown.load()) {
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
|
@ -3152,7 +3086,6 @@ convert_uint32_into_string(UInt32 data)
|
|||
return str;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
int
|
||||
audiounit_get_default_device_datasource(cubeb_device_type type, UInt32 * data)
|
||||
{
|
||||
|
@ -3174,16 +3107,12 @@ audiounit_get_default_device_datasource(cubeb_device_type type, UInt32 * data)
|
|||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
audiounit_get_default_device_name(cubeb_stream * stm,
|
||||
cubeb_device * const device,
|
||||
cubeb_device_type type)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
#else
|
||||
assert(stm);
|
||||
assert(device);
|
||||
|
||||
|
@ -3200,7 +3129,6 @@ audiounit_get_default_device_name(cubeb_stream * stm,
|
|||
type == CUBEB_DEVICE_TYPE_INPUT ? "input" : "output");
|
||||
}
|
||||
return CUBEB_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -3255,7 +3183,6 @@ audiounit_stream_register_device_changed_callback(
|
|||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static char *
|
||||
audiounit_strref_to_cstr_utf8(CFStringRef strref)
|
||||
{
|
||||
|
@ -3277,14 +3204,12 @@ audiounit_strref_to_cstr_utf8(CFStringRef strref)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static uint32_t
|
||||
audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope)
|
||||
{
|
||||
AudioObjectPropertyAddress adr = {0, scope,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
UInt32 size = 0;
|
||||
uint32_t i, ret = 0;
|
||||
|
||||
|
@ -3310,7 +3235,7 @@ audiounit_get_available_samplerate(AudioObjectID devid,
|
|||
uint32_t * def)
|
||||
{
|
||||
AudioObjectPropertyAddress adr = {0, scope,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
adr.mSelector = kAudioDevicePropertyNominalSampleRate;
|
||||
if (AudioObjectHasProperty(devid, &adr)) {
|
||||
|
@ -3352,7 +3277,7 @@ audiounit_get_device_presentation_latency(AudioObjectID devid,
|
|||
AudioObjectPropertyScope scope)
|
||||
{
|
||||
AudioObjectPropertyAddress adr = {0, scope,
|
||||
kAudioObjectPropertyElementMain};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
UInt32 size, dev, stream = 0;
|
||||
AudioStreamID sid[1];
|
||||
|
||||
|
@ -3377,7 +3302,7 @@ static int
|
|||
audiounit_create_device_from_hwdev(cubeb_device_info * dev_info,
|
||||
AudioObjectID devid, cubeb_device_type type)
|
||||
{
|
||||
AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMain};
|
||||
AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMaster};
|
||||
UInt32 size;
|
||||
|
||||
if (type == CUBEB_DEVICE_TYPE_OUTPUT) {
|
||||
|
@ -3388,11 +3313,7 @@ audiounit_create_device_from_hwdev(cubeb_device_info * dev_info,
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
UINT32 ch = 2;
|
||||
#else
|
||||
UInt32 ch = audiounit_get_channel_count(devid, adr.mScope);
|
||||
#endif
|
||||
if (ch == 0) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
@ -3496,16 +3417,7 @@ is_aggregate_device(cubeb_device_info * device_info)
|
|||
return !strncmp(device_info->friendly_name, PRIVATE_AGGREGATE_DEVICE_NAME,
|
||||
strlen(PRIVATE_AGGREGATE_DEVICE_NAME));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
static int
|
||||
audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
|
||||
cubeb_device_collection * collection)
|
||||
{
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
|
||||
cubeb_device_collection * collection)
|
||||
|
@ -3571,25 +3483,19 @@ audiounit_device_destroy(cubeb_device_info * device)
|
|||
delete[] device->friendly_name;
|
||||
delete[] device->vendor_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
audiounit_device_collection_destroy(cubeb * /* context */,
|
||||
cubeb_device_collection * collection)
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
#else
|
||||
for (size_t i = 0; i < collection->count; i++) {
|
||||
audiounit_device_destroy(&collection->device[i]);
|
||||
}
|
||||
delete[] collection->device;
|
||||
|
||||
return CUBEB_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static vector<AudioObjectID>
|
||||
audiounit_get_devices_of_type(cubeb_device_type devtype)
|
||||
{
|
||||
|
@ -3752,18 +3658,7 @@ audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype)
|
|||
kAudioObjectSystemObject, &DEVICES_PROPERTY_ADDRESS,
|
||||
audiounit_collection_changed_callback, context);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
int
|
||||
audiounit_register_device_collection_changed(
|
||||
cubeb * context, cubeb_device_type devtype,
|
||||
cubeb_device_collection_changed_callback collection_changed_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
#else
|
||||
int
|
||||
audiounit_register_device_collection_changed(
|
||||
cubeb * context, cubeb_device_type devtype,
|
||||
|
@ -3783,7 +3678,6 @@ audiounit_register_device_collection_changed(
|
|||
}
|
||||
return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
cubeb_ops const audiounit_ops = {
|
||||
/*.init =*/audiounit_init,
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright © 2023 Mozilla Foundation
|
||||
*
|
||||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
*/
|
||||
|
||||
#define NOMINMAX
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include "cubeb/cubeb.h"
|
||||
#include <ratio>
|
||||
|
||||
#include "cubeb_audio_dump.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
TEST(cubeb, audio_dump)
|
||||
{
|
||||
cubeb_audio_dump_session_t session;
|
||||
int rv = cubeb_audio_dump_init(&session);
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
cubeb_stream_params params;
|
||||
params.rate = 44100;
|
||||
params.channels = 2;
|
||||
params.format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
|
||||
cubeb_audio_dump_stream_t dump_stream;
|
||||
rv = cubeb_audio_dump_stream_init(session, &dump_stream, params, "test.wav");
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
rv = cubeb_audio_dump_start(session);
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
float phase = 0;
|
||||
const size_t buf_sz = 2 * 44100 / 50;
|
||||
float buf[buf_sz];
|
||||
for (uint32_t iteration = 0; iteration < 50; iteration++) {
|
||||
uint32_t write_idx = 0;
|
||||
for (uint32_t i = 0; i < buf_sz / params.channels; i++) {
|
||||
for (uint32_t j = 0; j < params.channels; j++) {
|
||||
buf[write_idx++] = sin(phase);
|
||||
}
|
||||
phase += 440 * M_PI * 2 / 44100;
|
||||
if (phase > 2 * M_PI) {
|
||||
phase -= 2 * M_PI;
|
||||
}
|
||||
}
|
||||
rv = cubeb_audio_dump_write(dump_stream, buf, 2 * 44100 / 50);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
ASSERT_EQ(rv, 0);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
rv = cubeb_audio_dump_stop(session);
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
rv = cubeb_audio_dump_stream_shutdown(session, dump_stream);
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
rv = cubeb_audio_dump_shutdown(session);
|
||||
ASSERT_EQ(rv, 0);
|
||||
|
||||
std::ifstream file("test.wav");
|
||||
ASSERT_TRUE(file.good());
|
||||
}
|
||||
|
||||
#undef NOMINMAX
|
|
@ -17,11 +17,6 @@
|
|||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/gtest/MozHelpers.h"
|
||||
|
||||
// #define ENABLE_NORMAL_LOG
|
||||
// #define ENABLE_VERBOSE_LOG
|
||||
|
@ -212,8 +207,6 @@ TEST(cubeb, duplex_collection_change_no_unregister)
|
|||
cubeb * ctx;
|
||||
int r;
|
||||
|
||||
mozilla::gtest::DisableCrashReporter();
|
||||
|
||||
r = common_init(&ctx, "Cubeb duplex example with collection change");
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
|
@ -302,17 +295,6 @@ TEST(cubeb, one_duplex_one_input)
|
|||
user_state_duplex duplex_stream_state;
|
||||
uint32_t latency_frames = 0;
|
||||
|
||||
// Disabled on 10.15, see bug 1867183
|
||||
#ifdef __APPLE__
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
// 10.15 correspond to Darwin 19
|
||||
if (strncmp(uts.release, "19", 2) == 0) {
|
||||
printf("Test disabled on macOS 10.15, exiting.\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = common_init(&ctx, "Cubeb duplex example");
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче