powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / После перехода на .Net Framework 4.0 и выше перестала работать программа
11 сообщений из 11, страница 1 из 1
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571072
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Программа открывает стерео-микшер/микрофон через waveInOpen и через callback вызывается функция для работы со звуком, передавая ей массив данных.
Так вот в .Net Framework 2.0 - 3.5 всё ок, а выше не работает, точнее работает около 1 секунды после запуска, а потом выдает последние данные или вообще вылетает. Опытным путем нашлась причина в сборщике мусора, то есть если не выходить за пределы 20 мб оперативки пока не вызывается сборщик, всё ок, как только вызывается, что-то убивается, похоже какой-то объект и начинает глючить, но я никак не найду что именно.
Также заметил, что если использовать 1 буфер, то всё работает, а если 16, как было, или любое число, хоть 2, хоть 100 то только один буфер работает, остальные старые данные выдают, как бы не обновляются. Вот выкладываю, я не знаю точно где проблема, но возможно в функции AllocateBuffers, так как непонятно как вообще это работает даже в .Net Framework 2.0, ведь Prev в цикле заменяется, или я чего-то не понимаю?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace playerWave
{
	internal class WaveInHelper
	{
		public static void Try(int err)
		{
            if (err != WaveNative.MMSYSERR_NOERROR)
				throw new Exception(err.ToString());
		}
	}

	public delegate void BufferDoneEventHandler(IntPtr data, int size);

	internal class WaveInBuffer : IDisposable
	{
		public WaveInBuffer NextBuffer;

		private AutoResetEvent m_RecordEvent = new AutoResetEvent(false);
		private IntPtr m_WaveIn;

		private WaveNative.WaveHdr m_Header;
		private byte[] m_HeaderData;
		private GCHandle m_HeaderHandle;
		private GCHandle m_HeaderDataHandle;

		private bool m_Recording;

		internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
		{
			if (uMsg == WaveNative.MM_WIM_DATA)
			{
                try
				{
					GCHandle h = (GCHandle)wavhdr.dwUser;
					WaveInBuffer buf = (WaveInBuffer)h.Target;
                    buf.OnCompleted();
                }
				catch
                {

                }
			}
		}

		public WaveInBuffer(IntPtr waveInHandle, int size)
		{
			m_WaveIn = waveInHandle;

			m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned);
			m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
			m_HeaderData = new byte[size];
			m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
			m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
			m_Header.dwBufferLength = size;
			WaveInHelper.Try(WaveNative.waveInPrepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
		}
		~WaveInBuffer()
		{
			Dispose();
		}

		public void Dispose()
		{
			if (m_Header.lpData != IntPtr.Zero)
			{
				WaveNative.waveInUnprepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header));
				m_HeaderHandle.Free();
				m_Header.lpData = IntPtr.Zero;
			}
			m_RecordEvent.Close();
			if (m_HeaderDataHandle.IsAllocated)
				m_HeaderDataHandle.Free();
			GC.SuppressFinalize(this);
		}

		public int Size
		{
			get { return m_Header.dwBufferLength; }
		}

		public IntPtr Data
		{
			get { return m_Header.lpData; }
		}

		public bool Record()
		{
			lock(this)
			{
				m_RecordEvent.Reset();
                int code_return = WaveNative.waveInAddBuffer(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header));
                m_Recording = code_return == WaveNative.MMSYSERR_NOERROR;

                return m_Recording;
			}
		}

		public void WaitFor()
		{
            if (m_Recording)
				m_Recording = m_RecordEvent.WaitOne();
			else
				Thread.Sleep(0);
		}

		private void OnCompleted()
        {
            m_RecordEvent.Set();
            m_Recording = false;
		}
	}

	public class WaveInRecorder : IDisposable
	{
		private IntPtr m_WaveIn;
		private WaveInBuffer m_Buffers;
		private WaveInBuffer m_CurrentBuffer;
		private Thread m_Thread;
		private BufferDoneEventHandler m_DoneProc;
		private bool m_Finished;

		private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);

		public static int DeviceCount
		{
			get { return WaveNative.waveInGetNumDevs(); }
		}

		public WaveInRecorder(int device, WaveFormat format, int bufferSize, int bufferCount, BufferDoneEventHandler doneProc)
		{
			m_DoneProc = doneProc;
            WaveInHelper.Try(WaveNative.waveInOpen(out m_WaveIn, device, format, m_BufferProc, IntPtr.Zero, WaveNative.CALLBACK_FUNCTION));
			AllocateBuffers(bufferSize, bufferCount);
			for (int i = 0; i < bufferCount; i++)
			{
				SelectNextBuffer();
				m_CurrentBuffer.Record();
			}
			WaveInHelper.Try(WaveNative.waveInStart(m_WaveIn));
			m_Thread = new Thread(new ThreadStart(ThreadProc));
			m_Thread.Start();
		}
		~WaveInRecorder()
		{
			Dispose();
		}
		public void Dispose()
		{
			if (m_Thread != null)
				try
				{
                    m_Finished = true;
                    if (m_WaveIn != IntPtr.Zero)
                        WaveNative.waveInReset(m_WaveIn);
                    m_Thread.Join();
					m_DoneProc = null;
					FreeBuffers();
					if (m_WaveIn != IntPtr.Zero)
						WaveNative.waveInClose(m_WaveIn);
				}
				finally
				{
					m_Thread = null;
					m_WaveIn = IntPtr.Zero;
				}
			GC.SuppressFinalize(this);
		}

		private void ThreadProc()
		{
            while (!m_Finished)
			{
				Advance();
				if (m_DoneProc != null && !m_Finished)
					m_DoneProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size);
				m_CurrentBuffer.Record();
			}
		}

		private void AllocateBuffers(int bufferSize, int bufferCount)
		{
			FreeBuffers();
			if (bufferCount > 0)
			{
				m_Buffers = new WaveInBuffer(m_WaveIn, bufferSize);
				WaveInBuffer Prev = m_Buffers;
				try
				{
					for (int i = 1; i < bufferCount; i++)
					{
						WaveInBuffer Buf = new WaveInBuffer(m_WaveIn, bufferSize);
						Prev.NextBuffer = Buf;
						Prev = Buf;
					}
				}
				finally
				{
					Prev.NextBuffer = m_Buffers;
				}
			}
		}
		private void FreeBuffers()
		{
			m_CurrentBuffer = null;
			if (m_Buffers != null)
			{
				WaveInBuffer First = m_Buffers;
				m_Buffers = null;

				WaveInBuffer Current = First;
				do
				{
					WaveInBuffer Next = Current.NextBuffer;
					Current.Dispose();
					Current = Next;
				} while(Current != First);
			}
		}
		private void Advance()
        {
            SelectNextBuffer();
            m_CurrentBuffer.WaitFor();
        }
		private void SelectNextBuffer()
		{
            m_CurrentBuffer = m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer;
		}
	}
}

...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571112
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maestrox...микшер/микрофон через waveInOpen ...
Темой подобной когда-то занимался, но на VB6, не на .Net, на .Net проект пока не переписывал (и не знаю буду ли), счас мало что уже помню, но есть вредная привычка все логировать на форуме.

Проблема может быть вообще не в .Net и не в мусорщиках (хотя я бы и на .Net делал классические C++/VB6 -образные функции-простыни, а не классы WaveNative, хотя б чтоб как говорится меня не "подмели" из-за того что случайно что-то не заметил).

В общем, есть "wave..." -ф-ции, они вообще говоря для XP, если через них пытаться управлять ползунками-микшерами на всем что >=Vista, то в целом работает но какие-то ньюансы глючат.

Есть Core Audio APIs , они потяжелее, но они надежнее на 10-ках, 8-ках и прочих вистах и именно на них базируется управление звуком на всех новых OS (значечек в трее и то что оттуда растет).

Аудио мультимедиа кто серьезно занимался. Как правильно закрыть канал и миксер на VB6?

Там тест-пример (правда на VB6) который управляет этой кухней 2-мя способами, через Wave-API и через Core Audio APIs.
Не знаю насколько поможет и близко, но свои 5 копеек как говорится вставил.
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571352
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Дмитрий77,

Спасибо, да хотел чтобы и в XP работало, может кто профессиональным взглядом увидит косяк в этом коде всё-таки... Я уж что только не делал и читал, что изменилось в 4.0 и отключал фоновый сборщик мусора через переменную в конфигурации, и ничего. Чувствую просто косяк где-то и в ранней версии фреймворк не обращал внимание, а тут наверно поумнее стал и уже что-то лишнее удаляется из памяти, может ссылка на буфер или ещё что, не знаю... Код старый просто 2003 года примерно, и главное в инете один и тот же гуляет с этим косяком...
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571443
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maestrox,

А что вообще твоя делает?
Wav файл проигрывает?
Если проиграть wav, а не с ползунками громкости колдовать,
то тогда эта wave-технология вполне таки годится и на Win10 тоже.

Но я тебе так скажу, я так проигрываю только memory-wav. Генератор телефонных тонов (длинные гудки, короткие, частоты и т.д.)
Т.е. рисую этот wav в память и оттуда проигрываю (примерно как у тебя).

Но IMHO, если просто играть физический wav или mp3 с диска,
гораздо проще использовать вот это:
mciSendString function
Всего одна ф-ция с несколькими командами, колбэк есть но очень простой (не всегда даже нужен).
и рыться в chank-ах, читать из буферов через коллбэки - ничего этого не надо.

По ошибкам твоим не подскажу, потому как у тебя код сильно .Net-образный,
API все скрыты под какими-то Native-классами,
да и давно этим очень занимался, чтобы чего-то просечь сейчас на "низком уровне".
Я бы оформлял эту кухню (вызовы wave-API) классической простыней.

MaestroxКод старый просто 2003 года примерно, и главное в инете один и тот же гуляет с этим косяком...
Я такие вещи построчно проверяю с чтением документации на каждую API.
А еще может быть что в 2003-м году аффтор 32-битного кода использовал какие-нибудь Int32 вместо IntPtr,
а ты счас запустил этот код в Any CPU/x64 в .Net 4.X в новой студии и огреб по полной.
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571546
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Дмитрий77,

Нет, визуализация звука. Да я уже про все используемые api функции прочитал, менял на x86, по документации менял int на IntPtr там где это нужно. И, к сожалению, ничего...
Все api функции в WaveNative, имена не изменены. Меня вот функция AllocateBuffers смущает, как так в Prev все присваивается, оно же заменяется и тогда первые удалятся ведь или как...
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571613
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MaestroxДмитрий77,

Нет, визуализация звука. Да я уже про все используемые api функции прочитал, менял на x86, по документации менял int на IntPtr там где это нужно. И, к сожалению, ничего...
Все api функции в WaveNative, имена не изменены. Меня вот функция AllocateBuffers смущает, как так в Prev все присваивается, оно же заменяется и тогда первые удалятся ведь или как...

Prev не при чем, там создается кольцевой буфер
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571855
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ViPRos,

А как он работает без массива что-то не пойму. Он же присваивается в один и тот же объект? Может как раз на него ничего не ссылается и только один буфер остаётся. Как кстати узнать что именно удаляется из памяти, или там через отладчик надо ассемблер знать? А если логически может кто увидит что надо изменить, чтобы заработало, там смысл вот в чем: вот эти буферы, когда они все в работе, в функции Record они в m_Header,имеют полный размер 2048 из 2048 допустим, а как только начинает глючить то только один остаётся 2048, а другие любое другое число 1604 или 0 допустим, то есть он передается в функцию не полностью заполненный и в вызове waveInAddBuffer ошибка 33, то есть буфер еще используется, забыл как на английском ошибка называется.
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571862
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел WAVERR_STILLPLAYING, но мне кажется что не то что он используется ошибка, а то что или ссылка на него удалена или он как то поврежден и т.п. ведь первую секунду все ок, и в net 2.0-3.5 тоже, в общем сразу после как вызывается сборщик мусора начинаются глюки со всеми буферами кроме одного. Один остаётся в работе и возвращает каждый раз новые данные, а другие все зависают как бы и возвращают данные до сборки мусора всегда одни и те же, то есть перестают обновляться.
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571874
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GC.KeepAlive
https://msdn.microsoft.com/ru-ru/library/system.gc.keepalive(v=vs.110).aspx
возможно вы передаете какой то объект в неуправляемый код, после чего ссылка удаляется и GC этот объект удаляет. Ведь он не в курсе, что он еще используется в неуправляемом коде.
Я не очень понял, где у вас там точка входа и где вы его используйте. Может вы сюда скините рабочий пример, моделирующих проблему, а не кусок кода. Вникать как это запустить не очень хочется.
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39571979
Maestrox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman Mejtes,

Прикладываю пример, после открытия только надо поменять Any CPU на x86 и всё, после запуска на .net framework 2.0-3.5 при включенном по-умолчанию устройстве записи стерео-микшере, можно включить любую музыку хоть в браузере, хоть в проигрывателе, и в черных полях должно всё замигать. А после смены на >= 4.0, то через секунду после запуска или вылетит с ошибкой, или начнет дрыгаться всё, то есть если даже остановить музыку, всё также будет мигать или наоборот если запустить с выключенной музыкой, а потом после запуска включить, то мигать будет иногда, но бледно, так как один буфер всё-таки рабочий остается. Ах да, закрывать приложение надо через кнопку стоп в студии, так как через закрыть зависает, там тоже что-то с буферами не закрытыми правильно, но это не первостепенная задача. И главное чтобы всё замигало как надо в >= 4.0 :-)
...
Рейтинг: 0 / 0
После перехода на .Net Framework 4.0 и выше перестала работать программа
    #39572406
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maestrox... Ах да, закрывать приложение надо через кнопку стоп в студии, так как через закрыть зависает, там тоже что-то с буферами не закрытыми правильно, но это не ...
Я твой проект скачал, но он и в .Net 2.0 глючит по мелочам, какие-то NullReference, окно когда муваешь может какая-то идиотская ошибка прорисовки быть и т.д., через "закрыть зависает" как сам признался...
В общем он написан судя по всему курица жопой лапой. И неудивительно что что-то там крашит и вылетает непонятно где.

Ну и я свое мнение сказал вначале. Я не сторонник такого стиля кода.
Если работаешь с API а тем более такими навороченными, будь то C++, VB6 или .Net,
изволь писать "качественную простыню-функцию" с классической обработкой ошибок на каждую вызванную API, как в msdn-примерах (C++).
Вот мой пример на .Net .
(один из многих, никакого отношения к звуку, я говорю про правильный стиль работы с такими API)
При ошибке GoTo ToExit с распечаткой названия вылетевшей ф-ции, номера ошибки и ее описания
Код: vbnet
1.
        err_text = "FunctionName Error " & RaiseAPIErrorByNumber(dwRes)


(ну, естественно, не забываем закрывать все хандлы, в том числе по Exit согласно докам на API)
Будешь делать так, место ошибки вылезет сразу.
А вот к .Net-приблудам лучше обращаться по минимуму (и уж точно без try...catch).

Т.е. (код так понимаю откуда-то не глядя содран), если тебе это надо, берешь и пишешь свой в него глядя, строчка за строчкой. С проверками и обработками, попутно читая документацию. Ну, я так во всяком случае делаю.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / После перехода на .Net Framework 4.0 и выше перестала работать программа
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]