mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	cubeb_sink: Improve logging
This commit is contained in:
		
							parent
							
								
									675ffc1024
								
							
						
					
					
						commit
						a6cf2e1f9d
					
				
					 2 changed files with 71 additions and 21 deletions
				
			
		|  | @ -2,6 +2,7 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstdarg> | ||||
| #include <mutex> | ||||
| #include <vector> | ||||
| #include <cubeb/cubeb.h> | ||||
|  | @ -22,6 +23,7 @@ struct CubebSink::Impl { | |||
|     static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, | ||||
|                              void* output_buffer, long num_frames); | ||||
|     static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); | ||||
|     static void LogCallback(char const* fmt, ...); | ||||
| }; | ||||
| 
 | ||||
| CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Impl>()) { | ||||
|  | @ -29,21 +31,23 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp | |||
|         LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     cubeb_devid output_device = nullptr; | ||||
| 
 | ||||
|     cubeb_stream_params params; | ||||
|     params.rate = native_sample_rate; | ||||
|     params.channels = 2; | ||||
|     params.format = CUBEB_SAMPLE_S16NE; | ||||
|     params.layout = CUBEB_LAYOUT_STEREO; | ||||
|     cubeb_set_log_callback(CUBEB_LOG_NORMAL, &Impl::LogCallback); | ||||
| 
 | ||||
|     impl->sample_rate = native_sample_rate; | ||||
| 
 | ||||
|     u32 minimum_latency = 0; | ||||
|     if (cubeb_get_min_latency(impl->ctx, ¶ms, &minimum_latency) != CUBEB_OK) | ||||
|         LOG_CRITICAL(Audio_Sink, "Error getting minimum latency"); | ||||
|     cubeb_stream_params params; | ||||
|     params.rate = impl->sample_rate; | ||||
|     params.channels = 2; | ||||
|     params.layout = CUBEB_LAYOUT_STEREO; | ||||
|     params.format = CUBEB_SAMPLE_S16NE; | ||||
|     params.prefs = CUBEB_STREAM_PREF_NONE; | ||||
| 
 | ||||
|     u32 minimum_latency = 100 * impl->sample_rate / 1000; // Firefox default
 | ||||
|     if (cubeb_get_min_latency(impl->ctx, ¶ms, &minimum_latency) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio_Sink, "Error getting minimum latency"); | ||||
|     } | ||||
| 
 | ||||
|     cubeb_devid output_device = nullptr; | ||||
|     if (target_device_name != auto_device_name && !target_device_name.empty()) { | ||||
|         cubeb_device_collection collection; | ||||
|         if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { | ||||
|  | @ -61,10 +65,22 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (cubeb_stream_init(impl->ctx, &impl->stream, "Citra Audio Output", nullptr, nullptr, | ||||
|                           output_device, ¶ms, std::max(512u, minimum_latency), | ||||
|                           &Impl::DataCallback, &Impl::StateCallback, impl.get()) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream"); | ||||
|     int stream_err = cubeb_stream_init(impl->ctx, &impl->stream, "CitraAudio", nullptr, nullptr, | ||||
|                                        output_device, ¶ms, std::max(512u, minimum_latency), | ||||
|                                        &Impl::DataCallback, &Impl::StateCallback, impl.get()); | ||||
|     if (stream_err != CUBEB_OK) { | ||||
|         switch (stream_err) { | ||||
|         case CUBEB_ERROR: | ||||
|         default: | ||||
|             LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream ({})", stream_err); | ||||
|             break; | ||||
|         case CUBEB_ERROR_INVALID_FORMAT: | ||||
|             LOG_CRITICAL(Audio_Sink, "Invalid format when initializing cubeb stream"); | ||||
|             break; | ||||
|         case CUBEB_ERROR_DEVICE_UNAVAILABLE: | ||||
|             LOG_CRITICAL(Audio_Sink, "Device unavailable when initializing cubeb stream"); | ||||
|             break; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -75,8 +91,11 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp | |||
| } | ||||
| 
 | ||||
| CubebSink::~CubebSink() { | ||||
|     if (!impl->ctx) | ||||
|     if (!impl->ctx) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     impl->cb = nullptr; | ||||
| 
 | ||||
|     if (cubeb_stream_stop(impl->stream) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream"); | ||||
|  | @ -102,21 +121,53 @@ long CubebSink::Impl::DataCallback(cubeb_stream* stream, void* user_data, const | |||
|     Impl* impl = static_cast<Impl*>(user_data); | ||||
|     s16* buffer = reinterpret_cast<s16*>(output_buffer); | ||||
| 
 | ||||
|     if (!impl || !impl->cb) | ||||
|         return 0; | ||||
|     if (!impl || !impl->cb) { | ||||
|         LOG_DEBUG(Audio_Sink, "Emitting zeros"); | ||||
|         std::memset(output_buffer, 0, num_frames * 2 * sizeof(s16)); | ||||
|         return num_frames; | ||||
|     } | ||||
| 
 | ||||
|     impl->cb(buffer, num_frames); | ||||
| 
 | ||||
|     return num_frames; | ||||
| } | ||||
| 
 | ||||
| void CubebSink::Impl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} | ||||
| void CubebSink::Impl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) { | ||||
|     switch (state) { | ||||
|     case CUBEB_STATE_STARTED: | ||||
|         LOG_INFO(Audio_Sink, "Cubeb Audio Stream Started"); | ||||
|         break; | ||||
|     case CUBEB_STATE_STOPPED: | ||||
|         LOG_INFO(Audio_Sink, "Cubeb Audio Stream Stopped"); | ||||
|         break; | ||||
|     case CUBEB_STATE_DRAINED: | ||||
|         LOG_INFO(Audio_Sink, "Cubeb Audio Stream Drained"); | ||||
|         break; | ||||
|     case CUBEB_STATE_ERROR: | ||||
|         LOG_CRITICAL(Audio_Sink, "Cubeb Audio Stream Errored"); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CubebSink::Impl::LogCallback(char const* format, ...) { | ||||
|     std::array<char, 512> buffer; | ||||
|     std::va_list args; | ||||
|     va_start(args, format); | ||||
| #ifdef _MSC_VER | ||||
|     vsprintf_s(buffer.data(), buffer.size(), format, args); | ||||
| #else | ||||
|     vsnprintf(buffer.data(), buffer.size(), format, args); | ||||
| #endif | ||||
|     va_end(args); | ||||
|     buffer.back() = '\0'; | ||||
|     LOG_INFO(Audio_Sink, "{}", buffer.data()); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> ListCubebSinkDevices() { | ||||
|     std::vector<std::string> device_list; | ||||
|     cubeb* ctx; | ||||
| 
 | ||||
|     if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) { | ||||
|     if (cubeb_init(&ctx, "CitraEnumerator", nullptr) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); | ||||
|         return {}; | ||||
|     } | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ DspInterface::DspInterface() = default; | |||
| DspInterface::~DspInterface() = default; | ||||
| 
 | ||||
| void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) { | ||||
|     sink.reset(); | ||||
|     const SinkDetails& sink_details = GetSinkDetails(sink_id); | ||||
|     sink = sink_details.factory(audio_device); | ||||
|     sink->SetCallback( | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue