Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.78
Nachinka
11 / 11 / 0
Регистрация: 19.02.2014
Сообщений: 95
#1

Записать массив байтов с микрофона - Android

24.03.2014, 21:28. Просмотров 1121. Ответов 4
Метки нет (Все метки)

Всем привет!

Возникла проблема, никак не могу придумать такую штуку, допустим, имеется небольшое приложение, две кнопки:

Java
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
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
 
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="Start" />
 
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="Stop" />
 
</RelativeLayout>
Нажимаешь на Start пошла запись в массив байтов, нажимаешь на Stop запись остановилась, массив байтов( с микрофона устройства) получен.

Помогите, пожалуйста, разобраться с проблемой)

Есть небольшая, неработающая заготовка:

Java
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
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
 
public class MainActivity extends Activity implements OnClickListener {
 
    Button start_button;
    Button stop_button;
    boolean reading = false;
    final String TAG = "TAG";
    int myBufferSize = 8192;
    AudioRecord audioRecord;
    private Thread recordingThread = null;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        start_button = (Button) findViewById(R.id.button1);
        stop_button = (Button) findViewById(R.id.button2);
        start_button.setOnClickListener(this);
        stop_button.setOnClickListener(this);
        createAudioRecorder();
    }
 
    private void createAudioRecorder() {
        int sampleRate = 16000;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
 
        int minInternalBufferSize = AudioRecord.getMinBufferSize(sampleRate,
                channelConfig, audioFormat);
        int internalBufferSize = minInternalBufferSize * 4;
        Log.d(TAG, "minInternalBufferSize = " + minInternalBufferSize
                + ", internalBufferSize = " + internalBufferSize
                + ", myBufferSize = " + myBufferSize);
 
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                sampleRate, channelConfig, audioFormat, internalBufferSize);
    }
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            Log.d(TAG, "record start");
            reading = true;
            startRecorder();
        case R.id.button2:
            Log.d(TAG, "stop recorder");
            reading = false;
            stopRecorder();
        }
    }
 
    private void startRecorder() {
        reading = true;
        Log.d(TAG, "recording...");
        audioRecord.startRecording();
 
        recordingThread = new Thread(new Runnable() {
 
            @Override
            public void run() {
                AudioData();
            }
        }, "AudioRecorder Thread");
 
        recordingThread.start();
    }
 
    protected void AudioData() {
        byte data[] = new byte[myBufferSize];
        byte[] myBuffer = new byte[myBufferSize];
        int readCount = 0;
        int totalCount = 0;
        while (reading) {
            readCount = audioRecord.read(myBuffer, 0, myBufferSize);
            data = myBuffer;
            totalCount += readCount;
            Log.d(TAG, "readCount = " + readCount + ", totalCount = "
                    + totalCount);
            Log.d(TAG, "lenght: " + data.length);
            Log.d(TAG, "data1: " + data[0]);
            Log.d(TAG, "data2: " + data[1]);
        }
    }
 
    private void stopRecorder() {
        reading = false;
        Log.d(TAG, "record stop!");
        // audioRecord.stop();
        if (null != audioRecord) {
            reading = false;
            audioRecord.stop();
            audioRecord.release();
            audioRecord = null;
            recordingThread = null;
        }
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}
В манифесте добавлены права на запись звука.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.03.2014, 21:28     Записать массив байтов с микрофона
Посмотрите здесь:

Как на java получить с микрофона звук во flac формате? Android
Как записать аудио с микрофона и воспроизвести? Android
Вычитывание байтов из InputStream сокета Bluetooth Android
Как записать массив строк в файл? Android
Записать массив String как столбец таблицы базы данных Android
Android Отправка массива байтов по сети
Записать строку в двумерный массив Android
Android studio определение громкости микрофона Android
Подмена потока с микрофона Android
Звук не с микрофона? Android
Android Использование микрофона в фоне
Запрет использования микрофона Android

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
verylazy
Заблокирован
25.03.2014, 11:12     Записать массив байтов с микрофона #2
проблема в чем и ошибка?
Nachinka
11 / 11 / 0
Регистрация: 19.02.2014
Сообщений: 95
26.03.2014, 00:16  [ТС]     Записать массив байтов с микрофона #3
Проблема в том, что если код выше запускать, то можно вот такие странности увидеть:


Bash
1
2
3
4
5
6
7
8
9
10
11
03-25 09:47:01.782: D/TAG(788): minInternalBufferSize = 640, internalBufferSize = 2560, myBufferSize = 8192
03-25 09:47:04.262: D/TAG(788): record start
03-25 09:47:04.262: D/TAG(788): recording...
03-25 09:47:04.312: D/TAG(788): stop recorder
03-25 09:47:04.322: D/TAG(788): record stop!
03-25 09:47:04.372: D/TAG(788): readCount = 160, totalCount = 160
03-25 09:47:04.381: D/TAG(788): lenght: 8192
03-25 09:47:04.381: D/TAG(788): data1: 0
03-25 09:47:04.381: D/TAG(788): data2: 0
03-25 09:47:06.942: D/TAG(788): stop recorder
03-25 09:47:06.942: D/TAG(788): record stop!
То ест нажимаю на старт, он выдает start recorder recorder... и тут же стоп. Следовательно и стопорится запись массива байт.

Вот это выдает после нажатия на Start:
Bash
1
2
3
4
5
6
7
8
03-25 09:47:04.262: D/TAG(788): record start
03-25 09:47:04.262: D/TAG(788): recording...
03-25 09:47:04.312: D/TAG(788): stop recorder
03-25 09:47:04.322: D/TAG(788): record stop!
03-25 09:47:04.372: D/TAG(788): readCount = 160, totalCount = 160
03-25 09:47:04.381: D/TAG(788): lenght: 8192
03-25 09:47:04.381: D/TAG(788): data1: 0
03-25 09:47:04.381: D/TAG(788): data2: 0
А вот это после нажатия на Stop:
Bash
1
2
03-25 09:47:06.942: D/TAG(788): stop recorder
03-25 09:47:06.942: D/TAG(788): record stop!
Что вот за преждевременная остановка..

Добавлено через 10 часов 27 минут
Ну что, ни у кого нет каких-нибудь догадок?
verylazy
Заблокирован
26.03.2014, 11:09     Записать массив байтов с микрофона #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
так как ни у кого нет идей, отпишусь

- в switch-case нет break; в каждой секции case, это врятли относится к делу, но для чего-то же их туда ставят

- мне не понятно, почему в основном потоке делаем audioRecord.startRecording(); а потом запускается отдельный поток для AudioData(); может audioRecord.startRecording(); стоит в тот же поток перенести?

- это точно не по делу, но строки лишние - два раза присваивается reading = true; и reading = false;
первый раз в case, а потом на входе в startRecorder() и stopRecorder()
Nachinka
11 / 11 / 0
Регистрация: 19.02.2014
Сообщений: 95
26.03.2014, 13:50  [ТС]     Записать массив байтов с микрофона #5
Спасибо, verylazy!

Вот такие теперь логи выдает:

Bash
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
03-26 09:46:28.005: D/TAG(798): minInternalBufferSize = 640, internalBufferSize = 2560, myBufferSize = 8192
03-26 09:46:32.335: D/TAG(798): record start
03-26 09:46:32.335: D/TAG(798): recording...
03-26 09:46:32.395: D/TAG(798): readCount = 2560, totalCount = 2560
03-26 09:46:32.395: D/TAG(798): lenght: 8192
03-26 09:46:32.405: D/TAG(798): data1: 0
03-26 09:46:32.405: D/TAG(798): data2: 0
03-26 09:46:32.495: D/TAG(798): readCount = 2560, totalCount = 5120
03-26 09:46:32.495: D/TAG(798): lenght: 8192
03-26 09:46:32.495: D/TAG(798): data1: -4
03-26 09:46:32.495: D/TAG(798): data2: -1
03-26 09:46:32.568: D/TAG(798): readCount = 2560, totalCount = 7680
03-26 09:46:32.568: D/TAG(798): lenght: 8192
03-26 09:46:32.568: D/TAG(798): data1: 102
03-26 09:46:32.568: D/TAG(798): data2: 0
03-26 09:46:32.715: D/TAG(798): readCount = 2560, totalCount = 10240
03-26 09:46:32.715: D/TAG(798): lenght: 8192
03-26 09:46:32.715: D/TAG(798): data1: -113
03-26 09:46:32.715: D/TAG(798): data2: -1
03-26 09:46:32.857: D/TAG(798): readCount = 2560, totalCount = 12800
03-26 09:46:32.857: D/TAG(798): lenght: 8192
03-26 09:46:32.865: D/TAG(798): data1: -22
03-26 09:46:32.865: D/TAG(798): data2: -1
03-26 09:46:32.865: D/TAG(798): readCount = 2560, totalCount = 15360
03-26 09:46:32.865: D/TAG(798): lenght: 8192
03-26 09:46:32.865: D/TAG(798): data1: 21
03-26 09:46:32.865: D/TAG(798): data2: 0
03-26 09:46:33.011: D/TAG(798): readCount = 2560, totalCount = 17920
03-26 09:46:33.011: D/TAG(798): lenght: 8192
03-26 09:46:33.015: D/TAG(798): data1: 100
03-26 09:46:33.015: D/TAG(798): data2: 0
03-26 09:46:33.085: D/TAG(798): readCount = 2560, totalCount = 20480
03-26 09:46:33.085: D/TAG(798): lenght: 8192
03-26 09:46:33.085: D/TAG(798): data1: 45
03-26 09:46:33.085: D/TAG(798): data2: 0
03-26 09:46:33.235: D/TAG(798): readCount = 2560, totalCount = 23040
03-26 09:46:33.235: D/TAG(798): lenght: 8192
03-26 09:46:33.235: D/TAG(798): data1: 7
03-26 09:46:33.235: D/TAG(798): data2: 0
03-26 09:46:33.307: D/TAG(798): readCount = 2560, totalCount = 25600
03-26 09:46:33.307: D/TAG(798): lenght: 8192
03-26 09:46:33.307: D/TAG(798): data1: 22
03-26 09:46:33.315: D/TAG(798): data2: 0
03-26 09:46:33.385: D/TAG(798): readCount = 2560, totalCount = 28160
03-26 09:46:33.385: D/TAG(798): lenght: 8192
03-26 09:46:33.385: D/TAG(798): data1: 2
03-26 09:46:33.395: D/TAG(798): data2: 0
03-26 09:46:33.465: D/TAG(798): readCount = 2560, totalCount = 30720
03-26 09:46:33.465: D/TAG(798): lenght: 8192
03-26 09:46:33.465: D/TAG(798): data1: 2
03-26 09:46:33.465: D/TAG(798): data2: 0
03-26 09:46:33.545: D/TAG(798): readCount = 2560, totalCount = 33280
03-26 09:46:33.545: D/TAG(798): lenght: 8192
03-26 09:46:33.545: D/TAG(798): data1: 1
03-26 09:46:33.545: D/TAG(798): data2: 0
03-26 09:46:33.615: D/TAG(798): readCount = 2560, totalCount = 35840
03-26 09:46:33.615: D/TAG(798): lenght: 8192
03-26 09:46:33.615: D/TAG(798): data1: 1
03-26 09:46:33.615: D/TAG(798): data2: 0
03-26 09:46:33.695: D/TAG(798): readCount = 2560, totalCount = 38400
03-26 09:46:33.695: D/TAG(798): lenght: 8192
03-26 09:46:33.695: D/TAG(798): data1: 4
03-26 09:46:33.695: D/TAG(798): data2: 0
03-26 09:46:33.766: D/TAG(798): readCount = 2560, totalCount = 40960
03-26 09:46:33.766: D/TAG(798): lenght: 8192
03-26 09:46:33.766: D/TAG(798): data1: 0
03-26 09:46:33.766: D/TAG(798): data2: 0
03-26 09:46:33.911: D/TAG(798): readCount = 2560, totalCount = 43520
03-26 09:46:33.911: D/TAG(798): lenght: 8192
03-26 09:46:33.915: D/TAG(798): data1: 0
03-26 09:46:33.915: D/TAG(798): data2: 0
03-26 09:46:33.915: D/TAG(798): readCount = 2560, totalCount = 46080
03-26 09:46:33.915: D/TAG(798): lenght: 8192
03-26 09:46:33.925: D/TAG(798): data1: 0
03-26 09:46:33.925: D/TAG(798): data2: 0
03-26 09:46:34.135: D/TAG(798): readCount = 2560, totalCount = 48640
03-26 09:46:34.135: D/TAG(798): lenght: 8192
03-26 09:46:34.135: D/TAG(798): data1: 0
03-26 09:46:34.135: D/TAG(798): data2: 0
03-26 09:46:34.285: D/TAG(798): readCount = 2560, totalCount = 51200
03-26 09:46:34.285: D/TAG(798): lenght: 8192
03-26 09:46:34.285: D/TAG(798): data1: -5
03-26 09:46:34.285: D/TAG(798): data2: -1
03-26 09:46:34.357: D/TAG(798): readCount = 2560, totalCount = 53760
03-26 09:46:34.357: D/TAG(798): lenght: 8192
03-26 09:46:34.357: D/TAG(798): data1: -81
03-26 09:46:34.357: D/TAG(798): data2: -1
03-26 09:46:34.435: D/TAG(798): readCount = 2560, totalCount = 56320
03-26 09:46:34.435: D/TAG(798): lenght: 8192
03-26 09:46:34.435: D/TAG(798): data1: 45
03-26 09:46:34.435: D/TAG(798): data2: 0
03-26 09:46:34.515: D/TAG(798): readCount = 2560, totalCount = 58880
03-26 09:46:34.515: D/TAG(798): lenght: 8192
03-26 09:46:34.515: D/TAG(798): data1: -2
03-26 09:46:34.515: D/TAG(798): data2: -1
03-26 09:46:34.515: D/TAG(798): readCount = 2560, totalCount = 61440
03-26 09:46:34.515: D/TAG(798): lenght: 8192
03-26 09:46:34.525: D/TAG(798): data1: 2
03-26 09:46:34.525: D/TAG(798): data2: 0
03-26 09:46:34.668: D/TAG(798): readCount = 2560, totalCount = 64000
03-26 09:46:34.668: D/TAG(798): lenght: 8192
03-26 09:46:34.668: D/TAG(798): data1: 2
03-26 09:46:34.668: D/TAG(798): data2: 0
03-26 09:46:34.745: D/TAG(798): readCount = 2560, totalCount = 66560
03-26 09:46:34.745: D/TAG(798): lenght: 8192
03-26 09:46:34.745: D/TAG(798): data1: -1
03-26 09:46:34.745: D/TAG(798): data2: -1
03-26 09:46:34.887: D/TAG(798): readCount = 2560, totalCount = 69120
03-26 09:46:34.887: D/TAG(798): lenght: 8192
03-26 09:46:34.895: D/TAG(798): data1: 1
03-26 09:46:34.895: D/TAG(798): data2: 0
03-26 09:46:34.895: D/TAG(798): readCount = 2560, totalCount = 71680
03-26 09:46:34.895: D/TAG(798): lenght: 8192
03-26 09:46:34.895: D/TAG(798): data1: -2
03-26 09:46:34.895: D/TAG(798): data2: -1
03-26 09:46:35.044: D/TAG(798): readCount = 2560, totalCount = 74240
03-26 09:46:35.044: D/TAG(798): lenght: 8192
03-26 09:46:35.044: D/TAG(798): data1: -1
03-26 09:46:35.044: D/TAG(798): data2: -1
03-26 09:46:35.119: D/TAG(798): readCount = 2560, totalCount = 76800
03-26 09:46:35.119: D/TAG(798): lenght: 8192
03-26 09:46:35.125: D/TAG(798): data1: 1
03-26 09:46:35.125: D/TAG(798): data2: 0
03-26 09:46:35.265: D/TAG(798): readCount = 2560, totalCount = 79360
03-26 09:46:35.265: D/TAG(798): lenght: 8192
03-26 09:46:35.265: D/TAG(798): data1: 1
03-26 09:46:35.265: D/TAG(798): data2: 0
03-26 09:46:35.410: D/TAG(798): readCount = 2560, totalCount = 81920
03-26 09:46:35.410: D/TAG(798): lenght: 8192
03-26 09:46:35.415: D/TAG(798): data1: -7
03-26 09:46:35.415: D/TAG(798): data2: -1
03-26 09:46:35.495: D/TAG(798): readCount = 2560, totalCount = 84480
03-26 09:46:35.495: D/TAG(798): lenght: 8192
03-26 09:46:35.515: D/TAG(798): data1: 24
03-26 09:46:35.515: D/TAG(798): data2: 0
03-26 09:46:35.515: D/TAG(798): readCount = 2560, totalCount = 87040
03-26 09:46:35.515: D/TAG(798): lenght: 8192
03-26 09:46:35.515: D/TAG(798): data1: 35
03-26 09:46:35.515: D/TAG(798): data2: -1
03-26 09:46:35.525: D/TAG(798): stop recorder
03-26 09:46:35.525: D/TAG(798): record stop!
03-26 09:46:35.575: D/TAG(798): readCount = 0, totalCount = 87040
03-26 09:46:35.585: D/TAG(798): lenght: 8192
03-26 09:46:35.585: D/TAG(798): data1: 35
03-26 09:46:35.585: D/TAG(798): data2: -1
Ну и вот такой код:
Java
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
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
 
public class MainActivity extends Activity implements OnClickListener {
 
    Button start_button;
    Button stop_button;
    boolean reading = false;
    final String TAG = "TAG";
    int myBufferSize = 8192;
    AudioRecord audioRecord;
    private Thread recordingThread = null;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        start_button = (Button) findViewById(R.id.button1);
        stop_button = (Button) findViewById(R.id.button2);
        start_button.setOnClickListener(this);
        stop_button.setOnClickListener(this);
        createAudioRecorder();
    }
 
    private void createAudioRecorder() {
        int sampleRate = 16000;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
 
        int minInternalBufferSize = AudioRecord.getMinBufferSize(sampleRate,
                channelConfig, audioFormat);
        int internalBufferSize = minInternalBufferSize * 4;
        Log.d(TAG, "minInternalBufferSize = " + minInternalBufferSize
                + ", internalBufferSize = " + internalBufferSize
                + ", myBufferSize = " + myBufferSize);
 
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                sampleRate, channelConfig, audioFormat, internalBufferSize);
    }
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            Log.d(TAG, "record start");
            reading = true;
            startRecorder();
            break;
        case R.id.button2:
            Log.d(TAG, "stop recorder");
            reading = false;
            stopRecorder();
            break;
        }
    }
 
    private void startRecorder() {
        Log.d(TAG, "recording...");
        recordingThread = new Thread(new Runnable() {
 
            @Override
            public void run() {
                AudioData();
            }
        }, "AudioRecorder Thread");
 
        recordingThread.start();
    }
 
    protected void AudioData() {
        audioRecord.startRecording();
        byte data[] = new byte[myBufferSize];
        byte[] myBuffer = new byte[myBufferSize];
        int readCount = 0;
        int totalCount = 0;
        while (reading) {
            readCount = audioRecord.read(myBuffer, 0, myBufferSize);
            data = myBuffer;
            totalCount += readCount;
            Log.d(TAG, "readCount = " + readCount + ", totalCount = "
                    + totalCount);
            Log.d(TAG, "lenght: " + data.length);
            Log.d(TAG, "data1: " + data[0]);
            Log.d(TAG, "data2: " + data[1]);
        }
    }
 
    private void stopRecorder() {
        Log.d(TAG, "record stop!");
        // audioRecord.stop();
        if (null != audioRecord) {
            reading = false;
            audioRecord.stop();
            audioRecord.release();
            audioRecord = null;
            recordingThread = null;
        }
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}
Уху, спасибо!
Yandex
Объявления
26.03.2014, 13:50     Записать массив байтов с микрофона
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru