Bonjour a tous.

Voila j'ai un probleme, je me lance a peine dans le multithreading donc je commence juste a comprendre les bases.

Je voudrais créer un client/serveur qui permette d'envoyer un son. Jusque la pas de probleme ca marche. Mais je me suis dis que pendant que le client joue le son qu'il a recu au lieu de freezer il pourait lui aussi envoyer un son -> d'ou le multithreading.

Alors ok je connect le signal du client qui informe que des infos arrivent a la creation d'un nouveau thread dans lequel le client effectuera sa lecture.

Pas de probleme le client ne gele plus. Youpi et il peut meme envoyer un son pendant qu'il en lit un autre.



Mais voila le probleme si jamais il recoit un autre son alors qu'il est en train dans lire un aïe caramba !!!.

Du coup je me dis tiens allons voir du coté des mutex mais la l'effet n'est pas escompté le bug n'est pas réparé alors je m'en remet à vous. Je ne sais meme pas si c'est un mutex qu'il faut utiliser en tout cas voila le code :

D'abord le .h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
#ifndef HEADER_FENCLIENT
#define HEADER_FENCLIENT
 
 
#include <AL/al.h>
#include <AL/alc.h>
#include <sndfile.h>
#include <QtGui>
#include <QtNetwork>
#include <iostream>
#include <vector>
 
class threadEnvoie;
 
class FenClient : public QWidget
{
	Q_OBJECT
 
	public :
	FenClient();
	~FenClient();
	bool initOpenAl();
	std::vector<ALshort> loadSound(const std::string& Filename);
	void shutdownAL();
	void playSound(std::vector<ALshort> musique);
	QTcpSocket* getSocket();
	void donneesRecues();
	QMutex* getMutex();
 
	private slots:
	void connexion();
	void connected();
	void deconnexion();
	void envoiWave();
	void donneesRecuesThread();
 
	private :
 
	QTextEdit* log;
	QLineEdit* editAdresseIp;
	QSpinBox* port;
	QPushButton *boutonConnexion;
	QPushButton *test;
	QTcpSocket *socket;
	int tailleMessage;
	ALsizei SampleRate;
	threadEnvoie* tEnvoie;
	QMutex* mutex;
};
 
 
class threadEnvoie : public QThread
{
 
 public:
  threadEnvoie(FenClient *fen);
  void run();
  FenClient* fenClient;
};
 
 
#endif

Puis le .cpp

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
 
#include "FenClient.h"
 
using namespace std;
 
 
FenClient::FenClient()
{
 
	editAdresseIp = new QLineEdit("127.0.0.1");
	log = new QTextEdit;
	port = new QSpinBox();
	port->setMaximum(65536);
	port->setValue(12012);
 
	boutonConnexion = new QPushButton("Connexion");
	QPushButton *boutonQuitter = new QPushButton("Quitter");
	test = new QPushButton("Test");
	test->setEnabled(false);
 
	QGridLayout *layout = new QGridLayout;
	QGridLayout *layoutEdit = new QGridLayout;
	layoutEdit->addWidget(log,0,0);
	layout->setColumnStretch(2,8);
	layout->setColumnStretch(0,1);
	layout->setColumnStretch(4,1);
 
 
	layout->addWidget(editAdresseIp,0,0,1,2);
	layout->addWidget(port,0,4);
 
	layout->addWidget(log,1,0,1,5);
	layout->addWidget(boutonQuitter,2,0);
	layout->addWidget(test,2,1);
	layout->addWidget(boutonConnexion,2,4);
 
	setLayout(layout);
	socket = new QTcpSocket;
 
	tailleMessage = 0;
 
	connect(boutonQuitter,SIGNAL(clicked()),qApp,SLOT(quit()));
	connect(boutonConnexion,SIGNAL(clicked()),this,SLOT(connexion()));
	connect(socket,SIGNAL(connected()),this,SLOT(connected()));
	connect(socket,SIGNAL(disconnected()),this,SLOT(deconnexion()));
	connect(test,SIGNAL(clicked()),this,SLOT(envoiWave()));
 
	connect(socket,SIGNAL(readyRead()), this, SLOT(donneesRecuesThread()));
 
	tEnvoie=new threadEnvoie(this);
	mutex= new QMutex();
}
 
FenClient::~FenClient()
{
  delete tEnvoie;
  delete mutex;
}
 
void FenClient::connexion()
{
	log->append(tr("<em>Tentative de connexion en cours ...</em>"));
 
	socket->abort();
	socket->connectToHost(editAdresseIp->text(), port->value());
}
 
void FenClient::connected()
{
	log->append(tr("<em>Connexion reussi vous pouvez parler</em>"));
	boutonConnexion->setEnabled(false);
	test->setEnabled(true);
}
 
void FenClient::deconnexion()
{
  test->setEnabled(false);
  boutonConnexion->setEnabled(true);
  log->append(tr("<em>Deconnecté du serveur</em>"));
}
 
bool FenClient::initOpenAl()
{
	//Ouverture du device
	ALCdevice* Device = alcOpenDevice(NULL);
	if(!Device)
	{
		cerr<<"impossible d'ouvrir le device"<<endl;
	        return false;
	 }
	//Création contexte
	ALCcontext *Context = alcCreateContext(Device, NULL);
	if (!Context)
	{
		cerr<<"impossible d'initialiser un contexte"<<endl;
		return false;
	}
	//Activationn du contexte
	if (!alcMakeContextCurrent(Context))
		return false;
 
	return true;
}
 
vector<ALshort> FenClient::loadSound(const string& Filename)
{
 
	//librairy sndfile
	//ouverture du fichier audio avec libsndfile
	SF_INFO FileInfos;
	SNDFILE* File = sf_open(Filename.c_str(), SFM_READ, &FileInfos);
	if (!File)
		cerr<<"impossible d'ouvrir le fichier"<<endl;
	//Lecture du nombre d'echantillon et taux echantillon
	ALsizei NbSamples = static_cast<ALsizei>(FileInfos.channels * FileInfos.frames);
	SampleRate = static_cast<ALsizei>(FileInfos.samplerate);
	//Lecture des echantillon audio au format 16 bits signe
	vector<ALshort> Samples(NbSamples);
	if (sf_read_short(File, &Samples[0], NbSamples)<NbSamples)
		cerr<<"Impossible"<<endl;
 
	//fermeture du fichier 
	sf_close(File);
 
	return Samples;
}
 
void FenClient::shutdownAL()
{
	//Récupération du contexte et du device
	ALCcontext* Context = alcGetCurrentContext();
	ALCdevice* Device = alcGetContextsDevice(Context);
 
	//Désactivation du contexte
	alcMakeContextCurrent(NULL);
 
	// Destruction du contexte
	alcDestroyContext (Context);
 
	//Fermeture du device
	alcCloseDevice(Device);
}
 
 
void FenClient::envoiWave()
{
 
	if(!initOpenAl())
	{
		cerr<<"impossible d'envoyer le message"<<endl;
		return;
	}
 
	vector<ALshort> sound;
	sound=loadSound("ocean.wav");
	QByteArray paquet;
	QDataStream stream(&paquet,QIODevice::WriteOnly);
	stream<<static_cast <int> (sound.size());
 
	for(int i =0;i<(int) sound.size();i++)
	{
		stream<<(int)sound[i];
	}
	socket->write(paquet);
 
	shutdownAL();
}
 
 
 
void FenClient::playSound(vector<ALshort> musique)
{
	if(!initOpenAl())
	  {
	    cout<<"impossible d'init"<<endl;
		return;
	  }
 
 
 
	//création tampon
	ALuint buffer;
	alGenBuffers(1, &buffer);
 
	//Remplissage avec les echantillons lus
	alBufferData(buffer,AL_FORMAT_MONO16, &musique[0],musique.size() * sizeof(ALshort),SampleRate);
 
 
	if (alGetError() != AL_NO_ERROR)
		return;
 
 
 
	//Création de la source
	ALuint Source;
	alGenSources(1, &Source);
 
	//On attache le tampon contenant les echantillons audio a la source
	alSourcei(Source, AL_BUFFER, buffer);
 
	//Lecture
	alSourcePlay(Source);
 
	//Attendre la fin de la musique
	ALint Status;
 
	do
	{
		alGetSourcei(Source,AL_SOURCE_STATE, &Status);
	}
	while (Status == AL_PLAYING);
 
	//Destruction du tampon
	alDeleteBuffers(1, &buffer);
 
	//Destruction de la source
	alSourcei(Source, AL_BUFFER, 0);
	alDeleteSources(1, &Source);
 
	shutdownAL();
 
} 
 
 
void FenClient::donneesRecues()
{
	cout<<"recoi"<<endl;
	QDataStream stream(socket);
 
	if (tailleMessage == 0)
	{
		if(socket->bytesAvailable()<(int)sizeof(int))
			return;
		stream >> tailleMessage;
	}
 
	if (socket->bytesAvailable() < (tailleMessage)*sizeof(int))
		return;
 
	vector<ALshort> message;
	for (int j =0 ; j<tailleMessage;j++)
	{
		int chiffre;
		stream>>chiffre;
		message.push_back(chiffre);
	}
 
	playSound(message);
}
 
QTcpSocket* FenClient::getSocket()
{
  return socket;
}
 
void FenClient::donneesRecuesThread()
{
    tEnvoie->start();
}
 
QMutex* FenClient::getMutex()
{
  return mutex;
}
 
threadEnvoie::threadEnvoie(FenClient *fen)
{
 
  fenClient=fen;
}
 
 
void threadEnvoie::run()
{
  fenClient->getMutex()->lock();
  fenClient->donneesRecues();
  fenClient->getMutex()->unlock();
}


La derniere fonction utilise des mutex.

Voila j'espere avoir ete assez clair en vous remerciant d'avance.

Remarque lors du beug c'est comme si le thread ne finissait jamais et comme si le programme passait outre le lockage.

EDIT : Finalement lorsque je met des mutex.lock et unlock aussi dans la fonction envoyerWave ca refonction bien que ca gele des le deuxieme appuie. Peut etre est -ce que la gestion des paquets est a revoir.

EDIT : Peut etre que le serveur doit aussi etre en multithreading.