struct a2dp_stream_out;
struct a2dp_audio_device {
+ // Important: device must be first as an audio_hw_device* may be cast to
+ // a2dp_audio_device* when the type is implicitly known.
struct audio_hw_device device;
+ std::recursive_mutex* mutex; // See note below on mutex acquisition order.
struct a2dp_stream_in* input;
struct a2dp_stream_out* output;
};
/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
struct a2dp_stream_common {
- std::recursive_mutex* mutex;
+ std::recursive_mutex* mutex; // See note below on mutex acquisition order.
int ctrl_fd;
int audio_fd;
size_t buffer_sz;
struct a2dp_stream_common common;
};
+/*
+ * Mutex acquisition order:
+ *
+ * The a2dp_audio_device (adev) mutex must be acquired before
+ * the a2dp_stream_common (out or in) mutex.
+ *
+ * This may differ from other audio HALs.
+ */
+
/*****************************************************************************
* Static variables
*****************************************************************************/
int ret = 0;
INFO("opening output");
-
+ // protect against adev->output and stream_out from being inconsistent
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
out = (struct a2dp_stream_out*)calloc(1, sizeof(struct a2dp_stream_out));
if (!out) return -ENOMEM;
struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
- INFO("closing output (state %d)", out->common.state);
+ // prevent interference with adev_set_parameters.
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ {
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+ const a2dp_state_t state = out->common.state;
+ INFO("closing output (state %d)", (int)state);
+ if ((state == AUDIO_A2DP_STATE_STARTED) ||
+ (state == AUDIO_A2DP_STATE_STOPPING)) {
+ stop_audio_datapath(&out->common);
+ }
- std::unique_lock<std::recursive_mutex> lock(*out->common.mutex);
- if ((out->common.state == AUDIO_A2DP_STATE_STARTED) ||
- (out->common.state == AUDIO_A2DP_STATE_STOPPING)) {
- stop_audio_datapath(&out->common);
+ skt_disconnect(out->common.ctrl_fd);
+ out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
}
- skt_disconnect(out->common.ctrl_fd);
- out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
- lock.unlock();
a2dp_stream_common_destroy(&out->common);
free(stream);
a2dp_dev->output = NULL;
static int adev_set_parameters(struct audio_hw_device* dev,
const char* kvpairs) {
struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
- struct a2dp_stream_out* out = a2dp_dev->output;
int retval = 0;
+ // prevent interference with adev_close_output_stream
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ struct a2dp_stream_out* out = a2dp_dev->output;
+
if (out == NULL) return retval;
INFO("state %d", out->common.state);
FNLOG();
+ // protect against adev->input and stream_in from being inconsistent
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
in = (struct a2dp_stream_in*)calloc(1, sizeof(struct a2dp_stream_in));
if (!in) return -ENOMEM;
struct audio_stream_in* stream) {
struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
- a2dp_state_t state = in->common.state;
- INFO("closing input (state %d)", state);
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ {
+ std::lock_guard<std::recursive_mutex> lock(*in->common.mutex);
+ const a2dp_state_t state = in->common.state;
+ INFO("closing input (state %d)", (int)state);
- if ((state == AUDIO_A2DP_STATE_STARTED) ||
- (state == AUDIO_A2DP_STATE_STOPPING))
- stop_audio_datapath(&in->common);
+ if ((state == AUDIO_A2DP_STATE_STARTED) ||
+ (state == AUDIO_A2DP_STATE_STOPPING))
+ stop_audio_datapath(&in->common);
- skt_disconnect(in->common.ctrl_fd);
- in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ skt_disconnect(in->common.ctrl_fd);
+ in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
a2dp_stream_common_destroy(&in->common);
free(stream);
a2dp_dev->input = NULL;
}
static int adev_close(hw_device_t* device) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)device;
FNLOG();
+ delete a2dp_dev->mutex;
+ a2dp_dev->mutex = nullptr;
free(device);
return 0;
}
if (!adev) return -ENOMEM;
+ adev->mutex = new std::recursive_mutex;
+
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->device.common.module = (struct hw_module_t*)module;