mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	mic: Refactor microphone state and management. (#7134)
This commit is contained in:
		
							parent
							
								
									831c9c4a38
								
							
						
					
					
						commit
						5118798c30
					
				
					 10 changed files with 137 additions and 145 deletions
				
			
		|  | @ -19,7 +19,7 @@ struct CubebInput::Impl { | |||
|     cubeb* ctx = nullptr; | ||||
|     cubeb_stream* stream = nullptr; | ||||
| 
 | ||||
|     std::unique_ptr<SampleQueue> sample_queue{}; | ||||
|     SampleQueue sample_queue{}; | ||||
|     u8 sample_size_in_bytes = 0; | ||||
| 
 | ||||
|     static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, | ||||
|  | @ -28,38 +28,34 @@ struct CubebInput::Impl { | |||
| }; | ||||
| 
 | ||||
| CubebInput::CubebInput(std::string device_id) | ||||
|     : impl(std::make_unique<Impl>()), device_id(std::move(device_id)) { | ||||
|     if (cubeb_init(&impl->ctx, "Citra Input", nullptr) != CUBEB_OK) { | ||||
|         LOG_ERROR(Audio, "cubeb_init failed! Mic will not work properly"); | ||||
|         return; | ||||
|     } | ||||
|     impl->sample_queue = std::make_unique<SampleQueue>(); | ||||
| } | ||||
|     : impl(std::make_unique<Impl>()), device_id(std::move(device_id)) {} | ||||
| 
 | ||||
| CubebInput::~CubebInput() { | ||||
|     if (impl->stream) { | ||||
|         if (cubeb_stream_stop(impl->stream) != CUBEB_OK) { | ||||
|             LOG_ERROR(Audio, "Error stopping cubeb input stream."); | ||||
|         } | ||||
|         cubeb_stream_destroy(impl->stream); | ||||
|     } | ||||
| 
 | ||||
|     if (impl->ctx) { | ||||
|         cubeb_destroy(impl->ctx); | ||||
|     } | ||||
|     StopSampling(); | ||||
| } | ||||
| 
 | ||||
| void CubebInput::StartSampling(const InputParameters& params) { | ||||
|     if (IsSampling()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Cubeb apparently only supports signed 16 bit PCM (and float32 which the 3ds doesn't support)
 | ||||
|     // TODO: Resample the input stream.
 | ||||
|     if (params.sign == Signedness::Unsigned) { | ||||
|         LOG_ERROR(Audio, | ||||
|                   "Application requested unsupported unsigned pcm format. Falling back to signed."); | ||||
|         LOG_WARNING( | ||||
|             Audio, | ||||
|             "Application requested unsupported unsigned pcm format. Falling back to signed."); | ||||
|     } | ||||
| 
 | ||||
|     parameters = params; | ||||
|     impl->sample_size_in_bytes = params.sample_size / 8; | ||||
| 
 | ||||
|     auto init_result = cubeb_init(&impl->ctx, "Citra Input", nullptr); | ||||
|     if (init_result != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio, "cubeb_init failed: {}", init_result); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     cubeb_devid input_device = nullptr; | ||||
|     if (device_id != auto_device_name && !device_id.empty()) { | ||||
|         cubeb_device_collection collection; | ||||
|  | @ -87,25 +83,28 @@ void CubebInput::StartSampling(const InputParameters& params) { | |||
|     }; | ||||
| 
 | ||||
|     u32 latency_frames = 512; // Firefox default
 | ||||
|     if (cubeb_get_min_latency(impl->ctx, &input_params, &latency_frames) != CUBEB_OK) { | ||||
|         LOG_WARNING(Audio, "Error getting minimum input latency, falling back to default latency."); | ||||
|     auto latency_result = cubeb_get_min_latency(impl->ctx, &input_params, &latency_frames); | ||||
|     if (latency_result != CUBEB_OK) { | ||||
|         LOG_WARNING( | ||||
|             Audio, "cubeb_get_min_latency failed, falling back to default latency of {} frames: {}", | ||||
|             latency_frames, latency_result); | ||||
|     } | ||||
| 
 | ||||
|     if (cubeb_stream_init(impl->ctx, &impl->stream, "Citra Microphone", input_device, &input_params, | ||||
|                           nullptr, nullptr, latency_frames, Impl::DataCallback, Impl::StateCallback, | ||||
|                           impl.get()) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio, "Error creating cubeb input stream."); | ||||
|     auto stream_init_result = cubeb_stream_init( | ||||
|         impl->ctx, &impl->stream, "Citra Microphone", input_device, &input_params, nullptr, nullptr, | ||||
|         latency_frames, Impl::DataCallback, Impl::StateCallback, impl.get()); | ||||
|     if (stream_init_result != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio, "cubeb_stream_init failed: {}", stream_init_result); | ||||
|         StopSampling(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cubeb_stream_start(impl->stream) != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio, "Error starting cubeb input stream."); | ||||
|         cubeb_stream_destroy(impl->stream); | ||||
|         impl->stream = nullptr; | ||||
|     auto start_result = cubeb_stream_start(impl->stream); | ||||
|     if (start_result != CUBEB_OK) { | ||||
|         LOG_CRITICAL(Audio, "cubeb_stream_start failed: {}", start_result); | ||||
|         StopSampling(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     is_sampling = true; | ||||
| } | ||||
| 
 | ||||
| void CubebInput::StopSampling() { | ||||
|  | @ -114,11 +113,18 @@ void CubebInput::StopSampling() { | |||
|         cubeb_stream_destroy(impl->stream); | ||||
|         impl->stream = nullptr; | ||||
|     } | ||||
|     is_sampling = false; | ||||
|     if (impl->ctx) { | ||||
|         cubeb_destroy(impl->ctx); | ||||
|         impl->ctx = nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool CubebInput::IsSampling() { | ||||
|     return impl->ctx && impl->stream; | ||||
| } | ||||
| 
 | ||||
| void CubebInput::AdjustSampleRate(u32 sample_rate) { | ||||
|     if (!is_sampling) { | ||||
|     if (!IsSampling()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -129,9 +135,13 @@ void CubebInput::AdjustSampleRate(u32 sample_rate) { | |||
| } | ||||
| 
 | ||||
| Samples CubebInput::Read() { | ||||
|     if (!IsSampling()) { | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     Samples samples{}; | ||||
|     Samples queue; | ||||
|     while (impl->sample_queue->Pop(queue)) { | ||||
|     while (impl->sample_queue.Pop(queue)) { | ||||
|         samples.insert(samples.end(), queue.begin(), queue.end()); | ||||
|     } | ||||
|     return samples; | ||||
|  | @ -162,7 +172,7 @@ long CubebInput::Impl::DataCallback(cubeb_stream* stream, void* user_data, const | |||
|         const u8* data = reinterpret_cast<const u8*>(input_buffer); | ||||
|         samples.insert(samples.begin(), data, data + num_frames * impl->sample_size_in_bytes); | ||||
|     } | ||||
|     impl->sample_queue->Push(samples); | ||||
|     impl->sample_queue.Push(samples); | ||||
| 
 | ||||
|     // returning less than num_frames here signals cubeb to stop sampling
 | ||||
|     return num_frames; | ||||
|  |  | |||
|  | @ -17,11 +17,9 @@ public: | |||
|     ~CubebInput() override; | ||||
| 
 | ||||
|     void StartSampling(const InputParameters& params) override; | ||||
| 
 | ||||
|     void StopSampling() override; | ||||
| 
 | ||||
|     bool IsSampling() override; | ||||
|     void AdjustSampleRate(u32 sample_rate) override; | ||||
| 
 | ||||
|     Samples Read() override; | ||||
| 
 | ||||
| private: | ||||
|  |  | |||
|  | @ -37,12 +37,8 @@ public: | |||
|     /// Stops the microphone. Called by Core
 | ||||
|     virtual void StopSampling() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Called from the actual event timing at a constant period under a given sample rate. | ||||
|      * When sampling is enabled this function is expected to return a buffer of 16 samples in ideal | ||||
|      * conditions, but can be lax if the data is coming in from another source like a real mic. | ||||
|      */ | ||||
|     virtual Samples Read() = 0; | ||||
|     /// Checks whether the microphone is currently sampling.
 | ||||
|     virtual bool IsSampling() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Adjusts the Parameters. Implementations should update the parameters field in addition to | ||||
|  | @ -50,36 +46,15 @@ public: | |||
|      */ | ||||
|     virtual void AdjustSampleRate(u32 sample_rate) = 0; | ||||
| 
 | ||||
|     /// Value from 0 - 100 to adjust the mic gain setting. Called by Core
 | ||||
|     virtual void SetGain(u8 mic_gain) { | ||||
|         gain = mic_gain; | ||||
|     } | ||||
| 
 | ||||
|     u8 GetGain() const { | ||||
|         return gain; | ||||
|     } | ||||
| 
 | ||||
|     void SetPower(bool power) { | ||||
|         powered = power; | ||||
|     } | ||||
| 
 | ||||
|     bool GetPower() const { | ||||
|         return powered; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSampling() const { | ||||
|         return is_sampling; | ||||
|     } | ||||
| 
 | ||||
|     const InputParameters& GetParameters() const { | ||||
|         return parameters; | ||||
|     } | ||||
|     /**
 | ||||
|      * Called from the actual event timing at a constant period under a given sample rate. | ||||
|      * When sampling is enabled this function is expected to return a buffer of 16 samples in ideal | ||||
|      * conditions, but can be lax if the data is coming in from another source like a real mic. | ||||
|      */ | ||||
|     virtual Samples Read() = 0; | ||||
| 
 | ||||
| protected: | ||||
|     InputParameters parameters; | ||||
|     u8 gain = 0; | ||||
|     bool is_sampling = false; | ||||
|     bool powered = false; | ||||
| }; | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -23,13 +23,18 @@ public: | |||
|         is_sampling = false; | ||||
|     } | ||||
| 
 | ||||
|     void AdjustSampleRate(u32 sample_rate) override { | ||||
|         parameters.sample_rate = sample_rate; | ||||
|     bool IsSampling() override { | ||||
|         return is_sampling; | ||||
|     } | ||||
| 
 | ||||
|     void AdjustSampleRate(u32 sample_rate) override {} | ||||
| 
 | ||||
|     Samples Read() override { | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     bool is_sampling = false; | ||||
| }; | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ OpenALInput::~OpenALInput() { | |||
| } | ||||
| 
 | ||||
| void OpenALInput::StartSampling(const InputParameters& params) { | ||||
|     if (is_sampling) { | ||||
|     if (IsSampling()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -45,19 +45,20 @@ void OpenALInput::StartSampling(const InputParameters& params) { | |||
|     impl->device = alcCaptureOpenDevice( | ||||
|         device_id != auto_device_name && !device_id.empty() ? device_id.c_str() : nullptr, | ||||
|         params.sample_rate, format, static_cast<ALsizei>(params.buffer_size)); | ||||
|     if (!impl->device) { | ||||
|         LOG_CRITICAL(Audio, "alcCaptureOpenDevice failed."); | ||||
|     auto open_error = alcGetError(impl->device); | ||||
|     if (impl->device == nullptr || open_error != ALC_NO_ERROR) { | ||||
|         LOG_CRITICAL(Audio, "alcCaptureOpenDevice failed: {}", open_error); | ||||
|         StopSampling(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     alcCaptureStart(impl->device); | ||||
|     auto error = alcGetError(impl->device); | ||||
|     if (error != ALC_NO_ERROR) { | ||||
|         LOG_CRITICAL(Audio, "alcCaptureStart failed: {}", error); | ||||
|     auto capture_error = alcGetError(impl->device); | ||||
|     if (capture_error != ALC_NO_ERROR) { | ||||
|         LOG_CRITICAL(Audio, "alcCaptureStart failed: {}", capture_error); | ||||
|         StopSampling(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     is_sampling = true; | ||||
| } | ||||
| 
 | ||||
| void OpenALInput::StopSampling() { | ||||
|  | @ -66,11 +67,14 @@ void OpenALInput::StopSampling() { | |||
|         alcCaptureCloseDevice(impl->device); | ||||
|         impl->device = nullptr; | ||||
|     } | ||||
|     is_sampling = false; | ||||
| } | ||||
| 
 | ||||
| bool OpenALInput::IsSampling() { | ||||
|     return impl->device != nullptr; | ||||
| } | ||||
| 
 | ||||
| void OpenALInput::AdjustSampleRate(u32 sample_rate) { | ||||
|     if (!is_sampling) { | ||||
|     if (!IsSampling()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -81,7 +85,7 @@ void OpenALInput::AdjustSampleRate(u32 sample_rate) { | |||
| } | ||||
| 
 | ||||
| Samples OpenALInput::Read() { | ||||
|     if (!is_sampling) { | ||||
|     if (!IsSampling()) { | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,11 +17,9 @@ public: | |||
|     ~OpenALInput() override; | ||||
| 
 | ||||
|     void StartSampling(const InputParameters& params) override; | ||||
| 
 | ||||
|     void StopSampling() override; | ||||
| 
 | ||||
|     bool IsSampling() override; | ||||
|     void AdjustSampleRate(u32 sample_rate) override; | ||||
| 
 | ||||
|     Samples Read() override; | ||||
| 
 | ||||
| private: | ||||
|  |  | |||
|  | @ -19,24 +19,4 @@ StaticInput::StaticInput() | |||
|     : CACHE_8_BIT{NOISE_SAMPLE_8_BIT.begin(), NOISE_SAMPLE_8_BIT.end()}, | ||||
|       CACHE_16_BIT{NOISE_SAMPLE_16_BIT.begin(), NOISE_SAMPLE_16_BIT.end()} {} | ||||
| 
 | ||||
| StaticInput::~StaticInput() = default; | ||||
| 
 | ||||
| void StaticInput::StartSampling(const InputParameters& params) { | ||||
|     sample_rate = params.sample_rate; | ||||
|     sample_size = params.sample_size; | ||||
| 
 | ||||
|     parameters = params; | ||||
|     is_sampling = true; | ||||
| } | ||||
| 
 | ||||
| void StaticInput::StopSampling() { | ||||
|     is_sampling = false; | ||||
| } | ||||
| 
 | ||||
| void StaticInput::AdjustSampleRate(u32 sample_rate) {} | ||||
| 
 | ||||
| Samples StaticInput::Read() { | ||||
|     return (sample_size == 8) ? CACHE_8_BIT : CACHE_16_BIT; | ||||
| } | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -15,17 +15,29 @@ namespace AudioCore { | |||
| class StaticInput final : public Input { | ||||
| public: | ||||
|     StaticInput(); | ||||
|     ~StaticInput() override; | ||||
|     ~StaticInput() = default; | ||||
| 
 | ||||
|     void StartSampling(const InputParameters& params) override; | ||||
|     void StopSampling() override; | ||||
|     void AdjustSampleRate(u32 sample_rate) override; | ||||
|     void StartSampling(const InputParameters& params) { | ||||
|         parameters = params; | ||||
|         is_sampling = true; | ||||
|     } | ||||
| 
 | ||||
|     Samples Read() override; | ||||
|     void StopSampling() { | ||||
|         is_sampling = false; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSampling() { | ||||
|         return is_sampling; | ||||
|     } | ||||
| 
 | ||||
|     void AdjustSampleRate(u32 sample_rate) {} | ||||
| 
 | ||||
|     Samples Read() { | ||||
|         return (parameters.sample_size == 8) ? CACHE_8_BIT : CACHE_16_BIT; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     u16 sample_rate = 0; | ||||
|     u8 sample_size = 0; | ||||
|     bool is_sampling = false; | ||||
|     std::vector<u8> CACHE_8_BIT; | ||||
|     std::vector<u8> CACHE_16_BIT; | ||||
| }; | ||||
|  |  | |||
|  | @ -76,6 +76,8 @@ struct State { | |||
|     u32 initial_offset = 0; | ||||
|     bool looped_buffer = false; | ||||
|     u8 sample_size = 0; | ||||
|     u8 gain = 0; | ||||
|     bool power = false; | ||||
|     SampleRate sample_rate = SampleRate::Rate16360; | ||||
| 
 | ||||
|     void WriteSamples(std::span<const u8> samples) { | ||||
|  | @ -124,6 +126,8 @@ private: | |||
|         ar& initial_offset; | ||||
|         ar& looped_buffer; | ||||
|         ar& sample_size; | ||||
|         ar& gain; | ||||
|         ar& power; | ||||
|         ar& sample_rate; | ||||
|         sharedmem_buffer = _memory_ref ? _memory_ref->GetPointer() : nullptr; | ||||
|     } | ||||
|  | @ -167,13 +171,14 @@ struct MIC_U::Impl { | |||
|     } | ||||
| 
 | ||||
|     void UpdateSharedMemBuffer(std::uintptr_t user_data, s64 cycles_late) { | ||||
|         // If the event was scheduled before the application requested the mic to stop sampling
 | ||||
|         if (!mic || !mic->IsSampling()) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (change_mic_impl_requested.exchange(false)) { | ||||
|             CreateMic(); | ||||
|         } | ||||
|         // If the event was scheduled before the application requested the mic to stop sampling
 | ||||
|         if (!mic->IsSampling()) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         AudioCore::Samples samples = mic->Read(); | ||||
|         if (!samples.empty()) { | ||||
|  | @ -204,10 +209,11 @@ struct MIC_U::Impl { | |||
|         u32 audio_buffer_size = rp.Pop<u32>(); | ||||
|         bool audio_buffer_loop = rp.Pop<bool>(); | ||||
| 
 | ||||
|         if (mic->IsSampling()) { | ||||
|         if (mic && mic->IsSampling()) { | ||||
|             LOG_CRITICAL(Service_MIC, | ||||
|                          "Application started sampling again before stopping sampling"); | ||||
|             mic->StopSampling(); | ||||
|             mic.reset(); | ||||
|         } | ||||
| 
 | ||||
|         u8 sample_size = encoding == Encoding::PCM8Signed || encoding == Encoding::PCM8 ? 8 : 16; | ||||
|  | @ -218,6 +224,7 @@ struct MIC_U::Impl { | |||
|         state.looped_buffer = audio_buffer_loop; | ||||
|         state.size = audio_buffer_size; | ||||
| 
 | ||||
|         CreateMic(); | ||||
|         StartSampling(); | ||||
| 
 | ||||
|         timing.ScheduleEvent(GetBufferUpdatePeriod(state.sample_rate), buffer_write_event); | ||||
|  | @ -233,7 +240,10 @@ struct MIC_U::Impl { | |||
|     void AdjustSampling(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp(ctx); | ||||
|         SampleRate sample_rate = rp.PopEnum<SampleRate>(); | ||||
|         mic->AdjustSampleRate(GetSampleRateInHz(sample_rate)); | ||||
|         state.sample_rate = sample_rate; | ||||
|         if (mic) { | ||||
|             mic->AdjustSampleRate(GetSampleRateInHz(sample_rate)); | ||||
|         } | ||||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | @ -245,8 +255,11 @@ struct MIC_U::Impl { | |||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         mic->StopSampling(); | ||||
|         timing.RemoveEvent(buffer_write_event); | ||||
|         if (mic) { | ||||
|             mic->StopSampling(); | ||||
|             mic.reset(); | ||||
|         } | ||||
|         LOG_TRACE(Service_MIC, "called"); | ||||
|     } | ||||
| 
 | ||||
|  | @ -255,7 +268,7 @@ struct MIC_U::Impl { | |||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         bool is_sampling = mic->IsSampling(); | ||||
|         bool is_sampling = mic && mic->IsSampling(); | ||||
|         rb.Push<bool>(is_sampling); | ||||
|         LOG_TRACE(Service_MIC, "IsSampling: {}", is_sampling); | ||||
|     } | ||||
|  | @ -272,7 +285,7 @@ struct MIC_U::Impl { | |||
|     void SetGain(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp(ctx); | ||||
|         u8 gain = rp.Pop<u8>(); | ||||
|         mic->SetGain(gain); | ||||
|         state.gain = gain; | ||||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | @ -284,15 +297,14 @@ struct MIC_U::Impl { | |||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         u8 gain = mic->GetGain(); | ||||
|         rb.Push<u8>(gain); | ||||
|         rb.Push<u8>(state.gain); | ||||
|         LOG_TRACE(Service_MIC, "gain={}", gain); | ||||
|     } | ||||
| 
 | ||||
|     void SetPower(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp(ctx); | ||||
|         bool power = rp.Pop<bool>(); | ||||
|         mic->SetPower(power); | ||||
|         state.power = power; | ||||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | @ -304,8 +316,7 @@ struct MIC_U::Impl { | |||
| 
 | ||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         bool mic_power = mic->GetPower(); | ||||
|         rb.Push<u8>(mic_power); | ||||
|         rb.Push<u8>(state.power); | ||||
|         LOG_TRACE(Service_MIC, "called"); | ||||
|     } | ||||
| 
 | ||||
|  | @ -358,21 +369,18 @@ struct MIC_U::Impl { | |||
|     } | ||||
| 
 | ||||
|     void CreateMic() { | ||||
|         std::unique_ptr<AudioCore::Input> new_mic = AudioCore::CreateInputFromID( | ||||
|             Settings::values.input_type.GetValue(), Settings::values.input_device.GetValue()); | ||||
| 
 | ||||
|         // If theres already a mic, copy over any data to the new mic impl
 | ||||
|         if (mic) { | ||||
|             new_mic->SetGain(mic->GetGain()); | ||||
|             new_mic->SetPower(mic->GetPower()); | ||||
|             auto params = mic->GetParameters(); | ||||
|             if (mic->IsSampling()) { | ||||
|                 mic->StopSampling(); | ||||
|                 new_mic->StartSampling(params); | ||||
|             } | ||||
|         const auto was_sampling = mic && mic->IsSampling(); | ||||
|         if (was_sampling) { | ||||
|             mic->StopSampling(); | ||||
|             mic.reset(); | ||||
|         } | ||||
| 
 | ||||
|         mic = AudioCore::CreateInputFromID(Settings::values.input_type.GetValue(), | ||||
|                                            Settings::values.input_device.GetValue()); | ||||
|         if (was_sampling) { | ||||
|             StartSampling(); | ||||
|         } | ||||
| 
 | ||||
|         mic = std::move(new_mic); | ||||
|         change_mic_impl_requested.store(false); | ||||
|     } | ||||
| 
 | ||||
|  | @ -503,12 +511,14 @@ MIC_U::MIC_U(Core::System& system) | |||
|         // clang-format on
 | ||||
|     }; | ||||
| 
 | ||||
|     impl->CreateMic(); | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| MIC_U::~MIC_U() { | ||||
|     impl->mic->StopSampling(); | ||||
|     if (impl->mic) { | ||||
|         impl->mic->StopSampling(); | ||||
|         impl->mic.reset(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MIC_U::ReloadMic() { | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ namespace Service::MIC { | |||
| class MIC_U final : public ServiceFramework<MIC_U> { | ||||
| public: | ||||
|     explicit MIC_U(Core::System& system); | ||||
|     ~MIC_U(); | ||||
|     ~MIC_U() override; | ||||
| 
 | ||||
|     void ReloadMic(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue