[经验] 【NanoPi NEO2试用体验】智能家庭控制器--结项

[复制链接]

技术员

发表于 2017-7-15 12:08:17   731 查看 4 回复 显示全部楼层 倒序浏览
分享
       智能家庭控制器这个项目忙活了将近一个多月,我的工作重点放在了图像传输和音频传输上,而控制方面我这没有做太多工作,因为之前做Orangepi Zero的时候已经做过了很多这些任务,参考以前的帖子,包括GPIO的控制、LCD5110的控制,I2C读取MPU6050等等,这里不再多做重复的工作,将重点放在核心上。
       前面几个帖子已经介绍了使用UVC摄像头进行图像采集并进行jpeg图像转换的工作,后面我又做了一些音频方面的工作,在linux下进行音频采集和播放我使用的是基于oss框架的程序设计,alsa框架稍微麻烦一点。进行声音播放和录制其实很简单,和其他的设备使用方式一样就是打开、读写和关闭设备就行了。打开的设备是dsp设备,打开之后设置采集音频的参数包括采样率、量化位数、声道数。然后调用read函数就能进行进行录音了,获得的数据就是原始的PCM数据也就是原始音频数据,这些数据可以直接write到dsp设备上进行播放。下面就是使用dsp设备进行数据采集和播放的程序段:
  1. #define LENGTH                8                //录音时间,秒
  2. #define RATE                8000        //采样频率
  3. #define SIZE                8                //量化位数
  4. #define CHANNELS        1                //声道数目
  5. #define RSIZE                8192        //buf的大小

  6. static int recoder_fd = -1;

  7. int OpenRecoder()
  8. {
  9.         recoder_fd = open("/dev/dsp", O_RDWR);
  10.         if (recoder_fd < 0)
  11.         {
  12.                 perror("Cannot open /dev/dsp device");
  13.                 return 1;
  14.         }

  15.         int arg = SIZE;
  16.         if (ioctl(recoder_fd, SOUND_PCM_WRITE_BITS, &arg) == -1)    //设置量化位数
  17.         {
  18.                 perror("Cannot set SOUND_PCM_WRITE_BITS ");
  19.                 return 1;
  20.         }

  21.         arg = CHANNELS;
  22.         if (ioctl(recoder_fd, SOUND_PCM_WRITE_CHANNELS, &arg) == -1)   //设置声道数
  23.         {
  24.                 perror("Cannot set SOUND_PCM_WRITE_CHANNELS");
  25.                 return 1;
  26.         }
  27.        
  28.         arg = RATE;
  29.         if (ioctl(recoder_fd, SOUND_PCM_WRITE_RATE, &arg) == -1)      //设置采样率
  30.         {
  31.                 perror("Cannot set SOUND_PCM_WRITE_WRITE");
  32.                 return 1;
  33.         }
  34. }

  35. void CloseRecoder()
  36. {
  37.         if(recoder_fd > 0)
  38.                 close(recoder_fd);
  39. }

  40. int Recording(unsigned char *buff,int len)
  41. {
  42.         if(recoder_fd > 0)
  43.                 return read(recoder_fd, buff, len);
  44.         else
  45.                 return 0;
  46. }

  47. int Playing(unsigned char *buff,int len)
  48. {
  49.         if(recoder_fd > 0)
  50.                 write(recoder_fd, buff, len);
  51. }
复制代码
采集到的数据是不能直接保存成文件在Windows等系统识别,需要进行格式封装,这里进行的是wav格式的封装,wav的格式可以参考:http://blog.csdn.net/mlkiller/article/details/12567139,wav的数据格式表如下:
偏移地址
大小
字节
数据块
类型
内容
00H~03H
4
4字符
资源交换文件标志(RIFF)
04H~07H
4
长整数
从下个地址开始到文件尾的总字节数
08H~0BH
4
4字符
WAV文件标志(WAVE)
0CH~0FH
4
4字符
波形格式标志(fmt ),最后一位空格。
10H~13H
4
整数
过滤字节(一般为00000010H)
14H~15H
2
整数
格式种类(值为1时,表示数据为线性PCM编码)
16H~17H
2
整数
通道数,单声道为1,双声道为2
18H~1BH
4
长整数
采样频率
1CH~1FH
4
长整数
波形数据传输速率(每秒平均字节数)
20H~21H
2
整数
DATA数据块长度,字节。
22H~23H
2
整数
PCM位宽
24H~27H
4
4字符
“fact”,该部分一下是可选部分,即可能有,可能没有,一般到WAV文件由某些软件转换而成时,包含这部分。
28H~2BH
4
长整数
size,数值为4

wav是我见过的最简单的文件格式,封装wav的函数也很简单:
  1. struct WAV_HEADER wavehead =
  2. {
  3.         .RIFF = {'R','I','F','F'},
  4.         .WAVE = {'W','A','V','E'},
  5.         .fmt = {'f','m','t',' '},
  6.         .appendinfo = 16,
  7.         .format = 1,
  8.         .desc = {'d','a','t','a'},
  9. };

  10. //保存采样率8000,采样深度8位,1声道的数据
  11. void SavePCM2WAV(unsigned char *buff,int len,char *file)
  12. {
  13.         system("rm a.wav");
  14.         system("touch a.wav");
  15.        
  16.         wavehead.lenth = len + sizeof(struct WAV_HEADER) - 8;
  17.         wavehead.channel = 1;
  18.         wavehead.freq = 8000;
  19.         wavehead.rate = 8000*8/8;
  20.         wavehead.sampling = 1;
  21.         wavehead.datalenth = len;
  22.         wavehead.depth = 8;
  23.        
  24.         int fd = open("a.wav",O_RDWR);
  25.         if(fd > 0)
  26.         {
  27.                 int ret = write(fd,(unsigned char*)(&wavehead),sizeof(struct WAV_HEADER));
  28.                 if(ret != sizeof(struct WAV_HEADER))
  29.                 {
  30.                         printf("write header error\r\n");
  31.                         system("rm a.wav");
  32.                         return;
  33.                 }
  34.                 ret = write(fd,buff,len);
  35.                 if(ret != len)
  36.                 {
  37.                         printf("write data error\r\n");
  38.                         system("rm a.wav");
  39.                         return;
  40.                 }
  41.                 close(fd);
  42.         }
  43. }
复制代码
wav格式的文件虽然简单但是文件很大,不利于网络传输,这里可以使用命令将wav文件转成成mp3文件,文件大小会被压缩很多,使用的是lame库,可以自己安装或者编译lame源码:
lame sample.wav sample.mp3
得到的mp3文件就能进行网络传输了。
图像和音频基本上搞定了下面就是做主要的程序部分了,包括网络部分和硬件电路部分,由于NanoPi NEO2没有接出mic和扬声器我需要自己设计一个mic和扬声器放大的电路,我准备自己做一个PCB板,包含mic电路和扬声器放大电路,但是这里我犯了一个极为傻逼的错误,我把可爱的NanoPi NEO2当成了orangepi zero了,我做板的时候都是按照orangepi zero的尺寸和电路做的,我真的是。。。看错电路拿错板子。不过我想程序都是Linux通用的,哪里跑都是一样的,我先用这个orangepi zero板子实验了就,因为pcb打板要很长的时间,我没时间等待了,现在就发出了结项贴了,实在抱歉。电路板的图片如下:
IMG_20170715_113920(1).jpg

上面有mic和喇叭接口,喇叭是有功放的,声音很大。电路图如下:
1.jpg

功放电路


2.jpg

mic电路


3.jpg

USB扩展电路

等我的NanoPi NEO2的板子做好了得等一个多星期,到时候补一个帖子吧。主要还是创作的分享过程,硬件上大同小异,不过NanoPi NEO2的小巧身材的确加了很多分。我很喜欢,要是自带wifi的话就好了。



电路弄好了下面就是程序了。服务器使用的是公司的不开源的一个小型的服务器,并不是很牛的服务器,而是因为商业原因没有开源,所以只能使用不能研究了。控制器的核心网络部分的代码是一个状态机程序:

  1. void* network_thread(void *arg)
  2. {
  3.         int i;
  4.         printf("network_thread start\r\n");
  5.         while(1)
  6.         {
  7.                 if(network_stm == 0)
  8.                 {
  9.                         if(NetworkInit() == 0)
  10.                         {
  11.                                 printf("Network Initialize successfully\r\n");
  12.                                 network_stm = 1;
  13.                         }
  14.                         else
  15.                         {
  16.                                 printf("Network Initialize failed\r\n");
  17.                                 usleep(5000000);        //网络初始化失败的话延时一会再重连
  18.                         }
  19.                 }
  20.                 else if(network_stm == 1)
  21.                 {
  22.                         sprintf(login_string,"lock,%s,",key);
  23.                         printf("login_string:%s\r\n",login_string);
  24.                         // write(sock_client,str,strlen(str));
  25.                         SendNetFrame(login_string,strlen(login_string));
  26.                         int len = read(sock_client,read_buff,1024);
  27.                         // printf("%d\r\n",len);
  28.                         if(len > 0)
  29.                         {
  30.                                 read_buff[len] = 0;
  31.                                 printf("%s\r\n",read_buff);
  32.                                 if(strcmp(read_buff,"success") == 0)
  33.                                 {
  34.                                         printf("login successfully\r\n");
  35.                                         network_stm = 2;
  36.                                 }
  37.                                 else
  38.                                 {
  39.                                         printf("login failed\r\n");
  40.                                         close(sock_client);
  41.                                         network_stm = 0;
  42.                                         usleep(5000000);        //登录失败,关闭socket然后回到状态0
  43.                                 }
  44.                         }
  45.                         else if(len == 0)
  46.                         {
  47.                                 printf("connection closed by server\r\n");
  48.                                 network_stm = 0;
  49.                         }
  50.                 }
  51.                 else if(network_stm == 2)
  52.                 {
  53.                         int len = read(sock_client,read_buff,1024);
  54.                         if(len > 0)
  55.                         {
  56.                                 // printf("read_buff len:%d,",len);
  57.                                 // read_buff[len] = 0;
  58.                                 // printf("%s\r\n",read_buff);
  59.                                 for(i=0;i<len;i++)
  60.                                 {
  61.                                         InputData(read_buff[i]);
  62.                                         if(IsDataReady == 1)
  63.                                         {
  64.                                                 IsDataReady = 0;
  65.                                                 input_frame[input_frame_len] = 0;        //最后补0,防止进行字符串比较的时候数组越界
  66.                                                 printf("frame is ready,length:%d\r\n",input_frame_len);
  67.                                                
  68.                                                 if(input_frame[0] == 'p')        //如果收到的是语言数据
  69.                                                 {
  70.                                                         printf("frame type:PCM data\r\n");
  71.                                                         OpenRecoder();
  72.                                                         Playing(input_frame+1,input_frame_len-1);
  73.                                                         CloseRecoder();
  74.                                                 }
  75.                                                 else if(input_frame[0] == 'c')        //如果收到的是控制命令
  76.                                                 {
  77.                                                         printf("frame type:command:%s\r\n",input_frame);
  78.                                                         if(strstr(input_frame,"get picture") != 0)
  79.                                                         {
  80.                                                                 FLAG_GET_AND_SEND_PIC = 1;
  81.                                                         }
  82.                                                         else if(strstr(input_frame,"open lock") != 0)
  83.                                                         {
  84.                                                                 FLAG_OPENDOOR = 1;
  85.                                                         }
  86.                                                         else if(strstr(input_frame,"stream_on_off") != 0)
  87.                                                         {
  88.                                                                 FLAG_GET_VIDEO_STREAM = FLAG_GET_VIDEO_STREAM?0:1;
  89.                                                         }
  90.                                                 }
  91.                                         }
  92.                                 }
  93.                                
  94.                         }
  95.                         else if(len == 0)
  96.                         {
  97.                                 printf("connection closed by server\r\n");
  98.                                 network_stm = 0;
  99.                         }
  100.                 }
  101.                 usleep(1000);
  102.         }
  103. }
复制代码
用于解析接收到的网络数据,这是程序的核心,其他的摄像头和音频的部分前面都有程序不再说了。当收到来自手机端发来的命令的时候网络线程就会处理接收到的命令判断是拍照命令还是来自手机上的音频数据等等。安卓手机上的程序我也是简单的做了一个,我不是专门做安卓的所以做的很粗糙,只是一个大致的结构:

Screenshot_2017-07-15-11-55-15-697_com.example.ad.png

手机端连接上手机之后就和NanoPi进行通信了:

Screenshot_2017-07-15-11-58-21-192_com.example.ad.png


Screenshot_2017-07-15-11-58-26-631_com.example.ad.png

还可以进行双边语言通信,通信方式和微信类似,按下说话松开发送,安卓这块的代码写的很垃圾,仅供参考:

  1. public class MainActivity extends AppCompatActivity {
  2.     static Socket socket = null;
  3.     OutputStream ou;
  4.     InputStream in;

  5.     LinearLayout main_linear_layout;
  6.     ImageView image_view;
  7.     ImageView big_image_view;
  8.     Button btn_openlock;
  9.     Button btn_getpic;
  10.     Button btn_setup;
  11.     Button btn_record;
  12.     Handler handler = new Handler();

  13.     byte send_buff[];   //发送数据缓冲区
  14.     int send_buff_len;   //发送数据缓冲区长度
  15.     byte raw_data_buff[] = new byte[1024 * 1024];   //读取socket得到的原始数据
  16.     byte frame_buff[] = new byte[1024*1024];    //原始数据解析得到的有效数据帧
  17.     boolean IsFrameReady = false;
  18.     int frame_buffLen;
  19.     int state = 0;
  20.     int count = 0;

  21.     Bitmap bitmap;

  22.     byte[] img_buf = new byte[1024 * 1024];     //接收到的jpeg图片数据
  23.     byte[] mp3_buf = new byte[1024 * 1024];     //接收到的mp3数据

  24.     private NotificationManager notificationManager;

  25.     Thread RecordThread = null;
  26.     AudioRecord audioRecord = null;
  27.     byte[] RecordBuffer = new byte[8000 * 20];
  28.     int RecordBufferLen = 0;
  29.     int audioSource = MediaRecorder.AudioSource.MIC;
  30.     //设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
  31.     int sampleRateInHz = 8000;
  32.     //设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
  33.     int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
  34.     //音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
  35.     int audioFormat = AudioFormat.ENCODING_PCM_8BIT;
  36.     int bufferSizeInBytes;

  37.     @Override
  38.     protected void onCreate(Bundle savedInstanceState) {
  39.         super.onCreate(savedInstanceState);
  40.         supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
  41.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  42.         setContentView(R.layout.activity_main);

  43.         main_linear_layout = (LinearLayout)findViewById(R.id.main_linear_layout);

  44.         image_view = (ImageView)findViewById(R.id.image_view);
  45.         image_view.setOnClickListener(new View.OnClickListener() {
  46.             @Override
  47.             public void onClick(View v) {
  48.                 big_image_view.setVisibility(View.VISIBLE);
  49.                 main_linear_layout.setVisibility(View.GONE);
  50.             }
  51.         });
  52.         big_image_view = (ImageView)findViewById(R.id.big_image_view);
  53.         big_image_view.setOnClickListener(new View.OnClickListener() {
  54.             @Override
  55.             public void onClick(View v) {
  56.                 big_image_view.setVisibility(View.GONE);
  57.                 main_linear_layout.setVisibility(View.VISIBLE);
  58.             }
  59.         });

  60.         btn_openlock = (Button)findViewById(R.id.btn_openlock);
  61.         btn_openlock.setOnClickListener(btn_openlock_OnClickListener);

  62.         btn_setup = (Button)findViewById(R.id.btn_setup);
  63.         btn_setup.setOnClickListener(btn_setup_OnClickListener);

  64.         btn_getpic = (Button)findViewById(R.id.btn_getpic);
  65.         btn_getpic.setOnClickListener(btn_getpic_OnClickListener);

  66.         btn_record = (Button)findViewById(R.id.btn_record);
  67. //        btn_record.setOnClickListener(btn_record_OnClickListener);
  68.         btn_record.setOnTouchListener(btn_record_OnTouchListener);

  69.         ReadThread.start();

  70.         // 第一步:通过getSystemService()方法得到NotificationManager对象;
  71.         notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

  72.         //动态申请权限,高版本的安卓系统需要动态申请权限才行,只修改manifest文件没用
  73.         ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.RECORD_AUDIO},0);
  74.     }

  75.     //动态申请权限回调函数
  76.     public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) {
  77.         switch (requestCode) {
  78.             case 0: {
  79.                 // If request is cancelled, the result arrays are empty.
  80.                 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  81.                     Log.i("tangquan", "permission RECORD_AUDIO request success");
  82.                 } else {
  83.                     Log.i("tangquan", "permission RECORD_AUDIO request failed");
  84.                 }
  85.                 return;
  86.             }
  87.         }
  88.     }

  89.     //帧控制输入一个字节的数据
  90.     void InputData(byte data)
  91.     {
  92.         if(state == 0)
  93.         {
  94.             if(IsFrameReady == false)
  95.             {
  96.                 if(data == 'T')
  97.                 {
  98.                     state = 1;
  99.                     count = 0;
  100.                 }
  101.             }
  102.         }
  103.         else if(state == 1)
  104.         {
  105.             if(data == '\\')
  106.             {
  107.                 state = 2;
  108.             }
  109.             else if(data == 'Q')
  110.             {
  111.                 state = 0;
  112.                 IsFrameReady = true;
  113.                 frame_buffLen = count;
  114.             }
  115.             else
  116.             {
  117.                 frame_buff[count++] = data;
  118.             }
  119.         }
  120.         else if(state == 2)
  121.         {
  122.             state = 1;
  123.             frame_buff[count++] = data;
  124.         }
  125.     }

  126.     void SendFrame(char type,byte[] buff)
  127.     {
  128.         byte frame[] = new byte[buff.length * 2];
  129.         int i,j = 0;        //j用于计数frame的长度
  130.         frame[j++] =  'T';
  131.         frame[j++] = (byte)type;
  132.         for(i=0;i<buff.length;i++)
  133.         {
  134.             if(buff[i] == 'T' || buff[i] == 'Q' || buff[i] == '\\')
  135.             {
  136.                 frame[j] = '\\';        //插入一个转义字符
  137.                 j++;
  138.             }
  139.             frame[j] = buff[i];
  140.             j++;
  141.         }
  142.         frame[j] = 'Q';
  143.         j++;
  144.         SocketSendBytes(frame,j);
  145.     }

  146.     void SendFrame(char type,byte[] buff,int len)
  147.     {
  148.         byte frame[] = new byte[buff.length * 2];
  149.         int i,j = 0;        //j用于计数frame的长度
  150.         frame[j++] =  'T';
  151.         frame[j++] = (byte)type;
  152.         for(i=0;i<len;i++)
  153.         {
  154.             if(buff[i] == 'T' || buff[i] == 'Q' || buff[i] == '\\')
  155.             {
  156.                 frame[j] = '\\';        //插入一个转义字符
  157.                 j++;
  158.             }
  159.             frame[j] = buff[i];
  160.             j++;
  161.         }
  162.         frame[j] = 'Q';
  163.         j++;
  164.         SocketSendBytes(frame,j);
  165.     }

  166.     Thread ReadThread = new Thread()
  167.     {
  168.         public void run()
  169.         {
  170.             socket = new Socket();
  171.             try
  172.             {
  173. //                socket.connect(new InetSocketAddress("192.168.1.106",5000),1000);
  174.                 socket.connect(new InetSocketAddress("103.76.85.83",5000),1000);
  175.                 ou = socket.getOutputStream();
  176.                 in = socket.getInputStream();

  177.                 SocketSendStr("phone,AAAAEqo7V7dNvVP8,");//发送账号和密码
  178.                 int len = in.read(raw_data_buff,0,100);//read是阻塞式的,用SocketChannel可以不阻塞
  179.                 if(len > 0)
  180.                 {
  181.                     //需要进行截断,不然直接把result转成字符串那么这个字符串的长度是result的长度
  182.                     String res_str = new String(Arrays.copyOfRange(raw_data_buff, 0, len));
  183.                     if(res_str.equals("success"))
  184.                     {
  185.                         PostToast("连接成功");
  186.                     }
  187.                     else
  188.                     {
  189.                         PostToast("账号错误");
  190.                         socket.close();//关闭socket连接
  191.                         socket = null;
  192.                         return;
  193.                     }
  194.                 }
  195.             }
  196.             catch(Exception e)
  197.             {
  198.                 socket = null;
  199.                 PostToast("连接失败");
  200.                 return;
  201.             }

  202.             while(socket != null)
  203.             {
  204.                 try {
  205.                     int len = in.read(raw_data_buff,0,raw_data_buff.length);
  206.                     if(len > 0)
  207.                     {
  208. //                        PostToast("len:" + String.valueOf(len));
  209.                         for(int i=0;i<len;i++)
  210.                         {
  211.                             InputData(raw_data_buff[i]);

  212.                             //是否接受到一帧数据
  213.                             if(IsFrameReady)
  214.                             {
  215.                                 IsFrameReady = false;
  216. //                                PostToast("get one frame,len:"+String.valueOf(frame_buffLen)+",type:"+String.valueOf((char)frame_buff[0]));
  217.                                 Log.i("tangquan","get one frame,len:"+String.valueOf(frame_buffLen)+",type:"+String.valueOf((char)frame_buff[0]));
  218.                                 if((char)frame_buff[0] == 'j')
  219.                                 {
  220. //                                    showNotification("tangquan","content","contenttext",0,0);

  221.                                     for(int j=1;j<frame_buffLen;j++)
  222.                                     {
  223.                                         img_buf[j - 1] = frame_buff[j];
  224.                                     }
  225.                                     handler.post(new Runnable()
  226.                                     {
  227.                                         @Override
  228.                                         public void run(){
  229.                                             bitmap = BitmapFactory.decodeByteArray(img_buf,0,frame_buffLen-1);
  230.                                             image_view.setImageBitmap(bitmap);
  231.                                             big_image_view.setImageBitmap(bitmap);
  232.                                         }
  233.                                     });
  234.                                 }
  235.                                 else if((char)frame_buff[0] == 'm')
  236.                                 {
  237.                                     Log.i("tangquan", "get mp3 data");
  238.                                     for(int j=1;j<frame_buffLen;j++)
  239.                                         mp3_buf[j - 1] = frame_buff[j];

  240.                                     String filename = "a.mp3";
  241.                                     File file = new File(MainActivity.this.getFilesDir(),filename);

  242.                                     FileOutputStream outputStream;
  243.                                     try{
  244.                                         outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  245.                                         outputStream.write(mp3_buf);
  246.                                         outputStream.close();
  247.                                     } catch(Exception e) {
  248.                                         e.printStackTrace();
  249.                                     }

  250.                                     Log.i("tangquan", MainActivity.this.getFilesDir()+"/"+filename);
  251.                                     MediaPlayer mp = new MediaPlayer();
  252.                                     mp.setDataSource(MainActivity.this.getFilesDir()+"/"+filename);
  253.                                     mp.prepare();
  254.                                     mp.start();
  255.                                 }
  256.                             }
  257.                         }
  258.                     }
  259.                 } catch (IOException e) {
  260.                     e.printStackTrace();
  261.                 }
  262.                 try {
  263.                     sleep(10);
  264.                 } catch (Exception ignored) {}
  265.             }
  266.         }
  267.     };


  268.     View.OnClickListener btn_openlock_OnClickListener = new View.OnClickListener() {
  269.         @Override
  270.         public void onClick(View v) {
  271.             PostToast("btn_openlock_OnClickListener");
  272. //            showNotification("tangquan","content","contenttext",0,0);
  273.             SendFrame('c',"open lock".getBytes());
  274.         }
  275.     };

  276.     View.OnClickListener btn_getpic_OnClickListener = new View.OnClickListener() {
  277.         @Override
  278.         public void onClick(View v) {
  279.             SendFrame('c',"get picture".getBytes());
  280.         }
  281.     };

  282.     View.OnClickListener btn_record_OnClickListener = new View.OnClickListener() {
  283.         @Override
  284.         public void onClick(View v) {
  285.             Log.i("tangquan", "btn_setup press");
  286.         }
  287.     };

  288.     boolean isRecording = false;
  289.     View.OnTouchListener btn_record_OnTouchListener = new View.OnTouchListener() {
  290.         @Override
  291.         public boolean onTouch(View v, MotionEvent event) {
  292.             if(event.getAction() == MotionEvent.ACTION_DOWN)
  293.             {
  294.                 Log.i("tangquan", "btn_record pressed");
  295.                 RecordThread = new Thread()
  296.                 {
  297.                     public void run()
  298.                     {
  299.                         // Create a new AudioRecord object to record the audio.
  300.                         // 获得满足条件的最小缓冲区大小
  301.                         bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
  302.                         Log.i("tangquan", "bufferSizeInBytes:" + String.valueOf(bufferSizeInBytes));
  303.                         // 创建AudioRecord对象
  304.                         audioRecord = new AudioRecord(audioSource, sampleRateInHz,channelConfig, audioFormat, bufferSizeInBytes);
  305.                         if(audioRecord != null)
  306.                         {
  307.                             audioRecord.startRecording();
  308.                             isRecording = true;
  309.                             RecordBufferLen = 0;
  310.                             while (isRecording) {
  311.                                 RecordBufferLen += audioRecord.read(RecordBuffer, RecordBufferLen, bufferSizeInBytes);
  312.                                 Log.i("tangquan", String.valueOf(RecordBufferLen));
  313.                             }
  314.                             audioRecord.stop();
  315.                             audioRecord.release();// 释放资源
  316.                             audioRecord = null;
  317.                         }
  318.                         else
  319.                         {
  320.                             Log.i("tangquan", "create AudioRecord failed");
  321.                         }
  322.                     }
  323.                 };
  324.                 RecordThread.start();
  325.             }
  326.             else if(event.getAction() == MotionEvent.ACTION_UP)
  327.             {
  328.                 Log.i("tangquan", "btn_record released");
  329.                 if(RecordThread != null && audioRecord != null)
  330.                 {
  331.                     isRecording = false;
  332.                     new Thread()
  333.                     {
  334.                         public void run()
  335.                         {
  336. //                            AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat,bufferSizeInBytes, AudioTrack.MODE_STREAM);
  337. //                            audioTrack.play();  //放音
  338. //                            try {
  339. //                                audioTrack.write(RecordBuffer, 0, RecordBufferLen);
  340. //                            } catch (Exception e) {
  341. //                                Log.e("AudioTrack", "Playback Failed");
  342. //                            }
  343.                             SendFrame('p',RecordBuffer,RecordBufferLen);
  344.                         }
  345.                     }.start();
  346.                 }
  347.             }
  348.             return false;
  349.         }
  350.     };

  351.     View.OnClickListener btn_setup_OnClickListener = new View.OnClickListener() {
  352.         @Override
  353.         public void onClick(View v) {

  354.         }
  355.     };

  356.     void SocketSendBytes(byte[] buff,int len) {
  357.         send_buff = buff;
  358.         send_buff_len = len;
  359. //        Log.i("tangquan", String.valueOf(send_buff_len));
  360.         new Thread()
  361.         {
  362.             @Override
  363.             public void run() {
  364.                 if (socket == null)
  365.                     return;
  366.                 try {
  367.                     ou.write(send_buff,0,send_buff_len);
  368.                 } catch (IOException e) {
  369.                     e.printStackTrace();
  370.                 }
  371.             }
  372.         }.start();
  373.     }

  374.     void SocketSendStr(String str) {
  375.         send_buff = str.getBytes();
  376.         new Thread()
  377.         {
  378.             @Override
  379.             public void run() {
  380.                 if (socket == null)
  381.                     return;
  382.                 try {
  383.                     ou.write(send_buff);
  384.                 } catch (IOException e) {
  385.                     e.printStackTrace();
  386.                 }
  387.             }
  388.         }.start();
  389.     }

  390.     //在线程中调用Toast会出错,不知道具体原因,但是网上说用 handler.post可以做
  391.     //所以弄了一个类和一个函数,类是实现了Runnable接口,同时添加了一个字符串变量
  392.     class MyRunnable implements Runnable
  393.     {
  394.         String Message;
  395.         public MyRunnable(String msg)
  396.         {
  397.             Message = msg;
  398.         }
  399.         public void run(){

  400.         }
  401.     }
  402.     void PostToast(String msg)
  403.     {
  404.         handler.post(new MyRunnable(msg)
  405.         {
  406.             @Override
  407.             public void run(){
  408.                 Toast.makeText(MainActivity.this, Message, Toast.LENGTH_SHORT).show();
  409.             }
  410.         });
  411.     }

  412.     // 第二步:对Notification的一些属性进行设置比如:内容,图标,标题,相应notification的动作进行处理等等;
  413.     public void showNotification(String tickerText, String contentTitle, String contentText, int iconId, int notiId) {
  414.         Notification myNotify = new Notification();
  415.         myNotify.icon = R.drawable.lock;
  416.         myNotify.tickerText = "TickerText:您有新短消息,请注意查收!";
  417.         myNotify.when = System.currentTimeMillis();
  418. //        myNotify.flags = Notification.FLAG_NO_CLEAR;// 不能够自动清除  \
  419. //        rv.setTextViewText(R.id.text_content, "hello wrold!");
  420. //        myNotify.contentView = rv;
  421.         Intent intent = new Intent(Intent.ACTION_MAIN);
  422.         PendingIntent contentIntent = PendingIntent.getActivity(this, 1,intent, FLAG_UPDATE_CURRENT);
  423.         myNotify.contentIntent = contentIntent;
  424.         notificationManager.notify(2, myNotify);
  425.     }

  426.     // 6步:使用notificationManager对象的cancelAll()方法取消
  427.     public void clearNoti(View v) {
  428.         notificationManager.cancelAll();// 清除所有
  429.     }
  430. }
复制代码



至此家庭控制器已经做完了,可以进行家庭拍照和家庭语言对讲,唯一的不足时PCB做错了,这点真的很懊恼,PCB制版费还真不便宜,诶。这一个月的使用我对NanoPi有一些小感触,不得不说NanoPi的做工真的很好,说实话我不是可以夸大NanoPi贬低Orangepi,NanoPi的做工比Orangepi好很多,我看了一下板子的布线,NanoPi以如此小的面积布出这样的板子实在是厉害,真的很喜欢NanoPi NEO2,太小了太强大了,希望后面能够使用NEO2做更多有趣的东西,谢谢电子发烧友提供的机会!

评分

参与人数 1积分 +10 收起 理由
Elecfans管家 + 10 您的帖子很精彩,期待您分享的下一个帖子!.

查看全部评分

技术员

发表于 2017-7-18 09:35:03  
楼主有视频嘛?
回复

点赞

技术员

发表于 2017-7-18 09:58:42    楼主|

PCB在线计价下单

板子大小:

cm
X
cm

层数:

2

板子数量:

10

厚度:

1.6

没拍呢,没想过有人想看我的这个的视频,哈哈,做的很挫。
回复

点赞

工程师

发表于 2017-8-8 13:37:37  
牛,利害了楼主!!!!
回复

点赞

实习生

发表于 2017-8-9 22:51:24  
我顶呀,学习喽
回复

点赞

高级模式
您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐 上一条 /8 下一条

小黑屋|手机版|Archiver| 电子发烧友 ( 粤ICP备14022951号-2 )  

GMT+8, 2017-8-22 11:43 , Processed in 0.105338 second(s), 19 queries , Memcache On.

微信扫描
快速回复 返回顶部 返回列表
-

推荐专区

技术干货集中营

专家问答

用户帮助┃咨询与建议┃版主议事

我的提问

工程师杂谈

工程师创意

工程师职场

论坛电子赛事

社区活动专版

发烧友活动

-

嵌入式论坛

单片机/MCU论坛

FPGA|CPLD|ASIC论坛

DSP论坛

嵌入式系统论坛

-

电源技术论坛

电源技术论坛

-

硬件设计论坛

PCB设计论坛

电路设计论坛

电子元器件论坛

控制|传感

总线技术|接口技术

-

测试测量论坛

LabVIEW论坛

Matlab论坛

测试测量技术专区

仪器仪表技术专区

-

EDA设计论坛

multisim论坛

PADS技术论坛

Protel|AD|DXP论坛

Allegro论坛

proteus论坛|仿真论坛

EasyEDA-中国人自已的EDA工具

Orcad论坛

-

综合技术与应用

电机控制

智能电网

光电及显示

参考设计中心

汽车电子技术论坛

医疗电子论坛

-

开源硬件

DFRobot专区

树莓派论坛

智能硬件论坛

开发快智能硬件开发平台

Intel物联网开发者专区

Waveshare

乐美客SBC专区

Arduino论坛

BeagleBone论坛

机器人论坛

创客神器NanoPi

小钢炮CANNON

比派科技banana pi专区

-

无线通信论坛

无线通信技术专区

天线|RF射频|微波|雷达技术

-

IC设计论坛

芯片测试与失效分析

Mixed Signal/SOC[数模混合芯片设计]

Analog/RF IC设计

设计与制造封装测试

-

个人版区

阿东Verilog技术专版

直流马达驱动电路设计

LabVIEW英雄联盟

特权同学FPGA专区

-

厂商专区

灵动微电子 MM32

盈鹏飞嵌入式

TI论坛

TI Deyisupport社区

芯灵思嵌入式论坛

Tisan

米尔科技

庆科社区

WIZnet技术专区

Cypress技术论坛

飞凌嵌入式

Qualcomm技术论坛

英创嵌入式

机智云GoKit论坛

-

检测技术与质量

电磁兼容(EMC)设计与整改

安规知识论坛

检测与认证

-

消费电子论坛

手机技术论坛

平板电脑/mid论坛

音视/视频/机顶盒论坛

-

电子论坛综合区

聚丰众筹官方社区

新人报道区

聚丰供应链

-

论坛服务区

-

供求信息发布

供需广告

招聘┃求职发布区

电子展览展会专区