# HG changeset patch # User Alex Chronopoulos # Date 1518799070 -7200 # Fri Feb 16 18:37:50 2018 +0200 # Node ID d1a033a5fab7e1ad80272c819bed694fc7de009a # Parent 96009d8697592aca0cba584db3366c7cf6e7cad0 Bug 1438888 - Update cubeb from upstream to 1d53c3a. r=padenot diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA --- a/media/libcubeb/README_MOZILLA +++ b/media/libcubeb/README_MOZILLA @@ -1,8 +1,8 @@ The source from this directory was copied from the cubeb git repository using the update.sh script. The only changes made were those applied by update.sh and the addition of Makefile.in build files for the Mozilla build system. The cubeb git repository is: git://github.com/kinetiknz/cubeb.git -The git commit ID used was cc0d538c40b933a5d7d5c5bf5e05de7d51740486 (2018-02-02 18:06:40 +0100) +The git commit ID used was 1d53c3a3779cbeb860b16aa38cc7f51e196b9745 (2018-02-13 12:30:46 +1000) diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h --- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -594,16 +594,21 @@ CUBEB_EXPORT int cubeb_stream_device_des changed. Passing NULL allow to unregister a function @retval CUBEB_OK @retval CUBEB_ERROR_INVALID_PARAMETER if either stream or device_changed_callback are invalid pointers. @retval CUBEB_ERROR_NOT_SUPPORTED */ CUBEB_EXPORT int cubeb_stream_register_device_changed_callback(cubeb_stream * stream, cubeb_device_changed_callback device_changed_callback); +/** Return the user data pointer registered with the stream with cubeb_stream_init. + @param stream the stream for which to retrieve user data pointer. + @retval user data pointer */ +CUBEB_EXPORT void * cubeb_stream_user_ptr(cubeb_stream * stream); + /** Returns enumerated devices. @param context @param devtype device type to include @param collection output collection. Must be destroyed with cubeb_device_collection_destroy @retval CUBEB_OK in case of success @retval CUBEB_ERROR_INVALID_PARAMETER if collection is an invalid pointer @retval CUBEB_ERROR_NOT_SUPPORTED */ CUBEB_EXPORT int cubeb_enumerate_devices(cubeb * context, diff --git a/media/libcubeb/src/cubeb.c b/media/libcubeb/src/cubeb.c --- a/media/libcubeb/src/cubeb.c +++ b/media/libcubeb/src/cubeb.c @@ -14,17 +14,22 @@ #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0]))) struct cubeb { struct cubeb_ops * ops; }; struct cubeb_stream { + /* + * Note: All implementations of cubeb_stream must keep the following + * layout. + */ struct cubeb * context; + void * user_ptr; }; #if defined(USE_PULSE) int pulse_init(cubeb ** context, char const * context_name); #endif #if defined(USE_PULSE_RUST) int pulse_rust_init(cubeb ** contet, char const * context_name); #endif @@ -473,16 +478,25 @@ int cubeb_stream_register_device_changed if (!stream->context->ops->stream_register_device_changed_callback) { return CUBEB_ERROR_NOT_SUPPORTED; } return stream->context->ops->stream_register_device_changed_callback(stream, device_changed_callback); } +void * cubeb_stream_user_ptr(cubeb_stream * stream) +{ + if (!stream) { + return NULL; + } + + return stream->user_ptr; +} + static void log_device(cubeb_device_info * device_info) { char devfmts[128] = ""; const char * devtype, * devstate, * devdeffmt; switch (device_info->type) { case CUBEB_DEVICE_TYPE_INPUT: diff --git a/media/libcubeb/src/cubeb_alsa.c b/media/libcubeb/src/cubeb_alsa.c --- a/media/libcubeb/src/cubeb_alsa.c +++ b/media/libcubeb/src/cubeb_alsa.c @@ -71,22 +71,24 @@ enum stream_state { INACTIVE, RUNNING, DRAINING, PROCESSING, ERROR }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ pthread_mutex_t mutex; snd_pcm_t * pcm; cubeb_data_callback data_callback; cubeb_state_callback state_callback; - void * user_ptr; snd_pcm_uframes_t stream_position; snd_pcm_uframes_t last_position; snd_pcm_uframes_t buffer_size; cubeb_stream_params params; /* Every member after this comment is protected by the owning context's mutex rather than the stream's mutex, or is only used on the context's run thread. */ diff --git a/media/libcubeb/src/cubeb_audiotrack.c b/media/libcubeb/src/cubeb_audiotrack.c --- a/media/libcubeb/src/cubeb_audiotrack.c +++ b/media/libcubeb/src/cubeb_audiotrack.c @@ -70,22 +70,24 @@ struct AudioTrack { struct cubeb { struct cubeb_ops const * ops; void * library; struct AudioTrack klass; }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ cubeb_stream_params params; cubeb_data_callback data_callback; cubeb_state_callback state_callback; void * instance; - void * user_ptr; /* Number of frames that have been passed to the AudioTrack callback */ long unsigned written; int draining; }; static void audiotrack_refill(int event, void* user, void* info) { diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp --- a/media/libcubeb/src/cubeb_audiounit.cpp +++ b/media/libcubeb/src/cubeb_audiounit.cpp @@ -127,28 +127,30 @@ enum device_flags { struct device_info { AudioDeviceID id = kAudioObjectUnknown; device_flags_value flags = DEV_UNKNOWN; }; struct cubeb_stream { explicit cubeb_stream(cubeb * context); + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr = nullptr; + /**/ + cubeb_data_callback data_callback = nullptr; cubeb_state_callback state_callback = nullptr; cubeb_device_changed_callback device_changed_callback = nullptr; owned_critical_section device_changed_callback_lock; /* Stream creation parameters */ cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE }; cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE }; device_info input_device; device_info output_device; - /* User pointer of data_callback */ - void * user_ptr = nullptr; /* Format descriptions */ AudioStreamBasicDescription input_desc; AudioStreamBasicDescription output_desc; /* I/O AudioUnits */ AudioUnit input_unit = nullptr; AudioUnit output_unit = nullptr; /* I/O device sample rate */ Float64 input_hw_rate = 0; diff --git a/media/libcubeb/src/cubeb_jack.cpp b/media/libcubeb/src/cubeb_jack.cpp --- a/media/libcubeb/src/cubeb_jack.cpp +++ b/media/libcubeb/src/cubeb_jack.cpp @@ -134,27 +134,29 @@ static struct cubeb_ops const cbjack_ops .stream_set_panning = NULL, .stream_get_current_device = cbjack_stream_get_current_device, .stream_device_destroy = cbjack_stream_device_destroy, .stream_register_device_changed_callback = NULL, .register_device_collection_changed = NULL }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ /**< Mutex for each stream */ pthread_mutex_t mutex; bool in_use; /**< Set to false iff the stream is free */ bool ports_ready; /**< Set to true iff the JACK ports are ready */ cubeb_data_callback data_callback; cubeb_state_callback state_callback; - void * user_ptr; cubeb_stream_params in_params; cubeb_stream_params out_params; cubeb_resampler * resampler; uint64_t position; bool pause; float ratio; diff --git a/media/libcubeb/src/cubeb_opensl.c b/media/libcubeb/src/cubeb_opensl.c --- a/media/libcubeb/src/cubeb_opensl.c +++ b/media/libcubeb/src/cubeb_opensl.c @@ -82,17 +82,20 @@ struct cubeb { SLObjectItf outmixObj; }; #define NELEMS(A) (sizeof(A) / sizeof A[0]) #define NBUFS 4 #define AUDIO_STREAM_TYPE_MUSIC 3 struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ pthread_mutex_t mutex; SLObjectItf playerObj; SLPlayItf play; SLBufferQueueItf bufq; SLVolumeItf volume; void ** queuebuf; uint32_t queuebuf_capacity; int queuebuf_idx; @@ -143,18 +146,16 @@ struct cubeb_stream { /* Flag to stop the execution of user callback and * close all working threads. Synchronized by * stream::mutex lock. */ uint32_t shutdown; /* Store user callback. */ cubeb_data_callback data_callback; /* Store state callback. */ cubeb_state_callback state_callback; - /* User pointer for data & state callbacks*/ - void * user_ptr; cubeb_resampler * resampler; unsigned int inputrate; unsigned int output_configured_rate; unsigned int latency_frames; int64_t lastPosition; int64_t lastPositionTimeStamp; int64_t lastCompensativePosition; diff --git a/media/libcubeb/src/cubeb_pulse.c b/media/libcubeb/src/cubeb_pulse.c --- a/media/libcubeb/src/cubeb_pulse.c +++ b/media/libcubeb/src/cubeb_pulse.c @@ -112,22 +112,24 @@ struct cubeb { char * context_name; int error; cubeb_device_collection_changed_callback collection_changed_callback; void * collection_changed_user_ptr; cubeb_strings * device_ids; }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ pa_stream * output_stream; pa_stream * input_stream; cubeb_data_callback data_callback; cubeb_state_callback state_callback; - void * user_ptr; pa_time_event * drain_timer; pa_sample_spec output_sample_spec; pa_sample_spec input_sample_spec; int shutdown; float volume; cubeb_state state; }; diff --git a/media/libcubeb/src/cubeb_sndio.c b/media/libcubeb/src/cubeb_sndio.c --- a/media/libcubeb/src/cubeb_sndio.c +++ b/media/libcubeb/src/cubeb_sndio.c @@ -24,17 +24,20 @@ static struct cubeb_ops const sndio_ops; struct cubeb { struct cubeb_ops const * ops; }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * arg; /* user arg to {data,state}_cb */ + /**/ pthread_t th; /* to run real-time audio i/o */ pthread_mutex_t mtx; /* protects hdl and pos */ struct sio_hdl *hdl; /* link us to sndio */ int mode; /* bitmap of SIO_{PLAY,REC} */ int active; /* cubec_start() called */ int conv; /* need float->s16 conversion */ unsigned char *rbuf; /* rec data consumed from here */ unsigned char *pbuf; /* play data is prepared here */ @@ -43,17 +46,16 @@ struct cubeb_stream { unsigned int pbpf; /* play bytes per frame */ unsigned int rchan; /* number of rec channels */ unsigned int pchan; /* number of play channels */ unsigned int nblks; /* number of blocks in the buffer */ uint64_t hwpos; /* frame number Joe hears right now */ uint64_t swpos; /* number of frames produced/consumed */ cubeb_data_callback data_cb; /* cb to preapare data */ cubeb_state_callback state_cb; /* cb to notify about state changes */ - void *arg; /* user arg to {data,state}_cb */ }; static void float_to_s16(void *ptr, long nsamp) { int16_t *dst = ptr; float *src = ptr; int s; diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -184,17 +184,21 @@ class wasapi_endpoint_notification_clien * - output only * - synchronized input and output * * Returns true when we should continue to play, false otherwise. */ typedef bool (*wasapi_refill_callback)(cubeb_stream * stm); struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context = nullptr; + void * user_ptr = nullptr; + /**/ + /* Mixer pameters. We need to convert the input stream to this samplerate/channel layout, as WASAPI does not resample nor upmix itself. */ cubeb_stream_params input_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE }; cubeb_stream_params output_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE }; /* Stream parameters. This is what the client requested, * and what will be presented in the callback. */ cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE }; @@ -206,17 +210,16 @@ struct cubeb_stream { unsigned latency = 0; cubeb_state_callback state_callback = nullptr; cubeb_data_callback data_callback = nullptr; wasapi_refill_callback refill_callback = nullptr; /* True when a loopback device is requested with no output device. In this case a dummy output device is opened to drive the loopback, but should not be exposed. */ bool has_dummy_output = false; - void * user_ptr = nullptr; /* Lifetime considerations: - client, render_client, audio_clock and audio_stream_volume are interface pointer to the IAudioClient. - The lifetime for device_enumerator and notification_client, resampler, mix_buffer are the same as the cubeb_stream instance. */ /* Main handle on the WASAPI stream. */ com_ptr output_client; @@ -610,16 +613,18 @@ refill(cubeb_stream * stm, void * input_ cubeb_mixer_mix(stm->mixer.get(), out_frames, dest, dest_len, output_buffer, output_buffer_len, &stm->output_stream_params, &stm->output_mix_params); } return out_frames; } +int wasapi_stream_reset_default_device(cubeb_stream * stm); + /* This helper grabs all the frames available from a capture client, put them in * linear_input_buffer. linear_input_buffer should be cleared before the * callback exits. This helper does not work with exclusive mode streams. */ bool get_input_buffer(cubeb_stream * stm) { XASSERT(has_input(stm)); HRESULT hr; @@ -632,16 +637,23 @@ bool get_input_buffer(cubeb_stream * stm uint32_t offset = 0; // If the input stream is event driven we should only ever expect to read a // single packet each time. However, if we're pulling from the stream we may // need to grab multiple packets worth of frames that have accumulated (so // need a loop). for (hr = stm->capture_client->GetNextPacketSize(&next); next > 0; hr = stm->capture_client->GetNextPacketSize(&next)) { + if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { + // Application can recover from this error. More info + // https://msdn.microsoft.com/en-us/library/windows/desktop/dd316605(v=vs.85).aspx + LOG("Device invalidated error, reset default device"); + wasapi_stream_reset_default_device(stm); + return true; + } if (FAILED(hr)) { LOG("cannot get next packet size: %lx", hr); return false; } UINT32 packet_size; hr = stm->capture_client->GetBuffer(&input_packet, @@ -708,20 +720,29 @@ bool get_input_buffer(cubeb_stream * stm bool get_output_buffer(cubeb_stream * stm, void *& buffer, size_t & frame_count) { UINT32 padding_out; HRESULT hr; XASSERT(has_output(stm)); hr = stm->output_client->GetCurrentPadding(&padding_out); + if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { + // Application can recover from this error. More info + // https://msdn.microsoft.com/en-us/library/windows/desktop/dd316605(v=vs.85).aspx + LOG("Device invalidated error, reset default device"); + wasapi_stream_reset_default_device(stm); + return true; + } + if (FAILED(hr)) { LOG("Failed to get padding: %lx", hr); return false; } + XASSERT(padding_out <= stm->output_buffer_frame_count); if (stm->draining) { if (padding_out == 0) { LOG("Draining finished."); stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); return false; } @@ -991,21 +1012,31 @@ wasapi_stream_render_loop(LPVOID stream) is_playing = false; hr = E_FAIL; continue; } LOG("Stream setup successfuly."); } XASSERT(stm->output_client || stm->input_client); if (stm->output_client) { - stm->output_client->Start(); + hr = stm->output_client->Start(); + if (FAILED(hr)) { + LOG("Error starting output after reconfigure, error: %lx", hr); + is_playing = false; + continue; + } LOG("Output started after reconfigure."); } if (stm->input_client) { - stm->input_client->Start(); + hr = stm->input_client->Start(); + if (FAILED(hr)) { + LOG("Error starting input after reconfiguring, error: %lx", hr); + is_playing = false; + continue; + } LOG("Input started after reconfigure."); } break; } case WAIT_OBJECT_0 + 2: /* refill */ XASSERT((has_input(stm) && has_output(stm)) || (!has_input(stm) && has_output(stm))); is_playing = stm->refill_callback(stm); @@ -1952,16 +1983,17 @@ wasapi_stream_init(cubeb * context, cube if (FAILED(hr)) { /* this is not fatal, we can still play audio, but we won't be able to keep using the default audio endpoint if it changes. */ LOG("failed to register notification client, %lx", hr); } *stream = stm.release(); + LOG("Stream init succesfull (%p)", *stream); return CUBEB_OK; } void close_wasapi_stream(cubeb_stream * stm) { XASSERT(stm); stm->stream_reset_lock.assert_current_thread_owns(); @@ -1981,16 +2013,17 @@ void close_wasapi_stream(cubeb_stream * stm->resampler.reset(); stm->mix_buffer.clear(); } void wasapi_stream_destroy(cubeb_stream * stm) { XASSERT(stm); + LOG("Stream destroy (%p)", stm); // Only free stm->emergency_bailout if we could join the thread. // If we could not join the thread, stm->emergency_bailout is true // and is still alive until the thread wakes up and exits cleanly. if (stop_and_join_render_thread(stm)) { delete stm->emergency_bailout.load(); stm->emergency_bailout = nullptr; } diff --git a/media/libcubeb/src/cubeb_winmm.c b/media/libcubeb/src/cubeb_winmm.c --- a/media/libcubeb/src/cubeb_winmm.c +++ b/media/libcubeb/src/cubeb_winmm.c @@ -87,21 +87,23 @@ struct cubeb { int shutdown; PSLIST_HEADER work; CRITICAL_SECTION lock; unsigned int active_streams; unsigned int minimum_latency_ms; }; struct cubeb_stream { + /* Note: Must match cubeb_stream layout in cubeb.c. */ cubeb * context; + void * user_ptr; + /**/ cubeb_stream_params params; cubeb_data_callback data_callback; cubeb_state_callback state_callback; - void * user_ptr; WAVEHDR buffers[NBUFS]; size_t buffer_size; int next_buffer; int free_buffers; int shutdown; int draining; HANDLE event; HWAVEOUT waveout;