1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20     npipe_.c
21 
22     Functions to output raw sound data to a windows Named Pipe.
23 
24 */
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdio.h>
30 
31 #ifdef __POCC__
32 #include <sys/types.h>
33 #endif //for off_t
34 
35 #ifdef __W32__
36 #include <windows.h>
37 #include <stdlib.h>
38 #include <io.h>
39 #endif
40 
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 
45 #ifdef STDC_HEADERS
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #elif HAVE_STRINGS_H
50 #include <strings.h>
51 #endif
52 
53 #include <fcntl.h>
54 
55 #ifdef __FreeBSD__
56 #include <stdio.h>
57 #endif
58 
59 #include "timidity.h"
60 #include "common.h"
61 #include "output.h"
62 #include "controls.h"
63 #include "instrum.h"
64 #include "playmidi.h"
65 #include "readmidi.h"
66 
67 //#define PIPE_BUFFER_SIZE (AUDIO_BUFFER_SIZE * 8)
68 #define PIPE_BUFFER_SIZE (88200)
69 static HANDLE hPipe=NULL;
70   OVERLAPPED pipe_ovlpd;
71   HANDLE hPipeEvent;
72 static volatile int pipe_close=-1;
73 static volatile int clear_pipe=-1;
74 
75 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
76 static void close_output(void);
77 static int output_data(char *buf, int32 bytes);
78 static int acntl(int request, void *arg);
79 
80 /* export the playback mode */
81 
82 #define dpm npipe_play_mode
83 
84 PlayMode dpm = {
85     DEFAULT_RATE,
86 	PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_CAN_TRACE,
87     -1,
88     {0,0,0,0,0},
89     "Windows Named Pipe", 'N',
90     NULL,
91     open_output,
92     close_output,
93     output_data,
94     acntl
95 };
96 
97 /*************************************************************************/
98 
npipe_output_open(const char * pipe_name)99 static int npipe_output_open(const char *pipe_name)
100 {
101   char PipeName[256];
102   DWORD ret;
103   DWORD n;
104   int i;
105 
106 
107  if (hPipe != NULL) return 0;
108  hPipeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
109  memset( &pipe_ovlpd, 0, sizeof(OVERLAPPED));
110  pipe_ovlpd.hEvent = hPipeEvent;
111 
112   sprintf(PipeName, "\\\\.\\pipe\\%s", pipe_name);
113   hPipe = CreateNamedPipe(PipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
114 //    PIPE_WAIT|
115   	PIPE_READMODE_BYTE |PIPE_TYPE_BYTE, 2,
116    PIPE_BUFFER_SIZE, 0, 0, NULL);
117   if (hPipe == INVALID_HANDLE_VALUE) {
118     ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't create Named Pipe %s : %ld",
119     	pipe_name, GetLastError());
120  	return -1;
121   }
122   ret = ConnectNamedPipe(hPipe, &pipe_ovlpd);
123 	if ( (ret == 0)  && (ERROR_IO_PENDING!=GetLastError()) ){
124     ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "CnnectNamePipe(%ld) error %s",
125     	GetLastError(), pipe_name);
126         CloseHandle(hPipe);
127   	    hPipe=NULL;
128         return -1;
129    }
130 //	WaitForSingleObject(pipe_ovlpd.hPipeEvent, 1000);
131 
132 	return 0;
133 }
134 
open_output(void)135 static int open_output(void)
136 {
137   dpm.encoding = validate_encoding(dpm.encoding, 0, 0);
138 
139   if(dpm.name == NULL) {
140     if (NULL==current_file_info || NULL==current_file_info->filename){
141       return -1;
142   	}
143   }else{
144   	      if ( -1 == npipe_output_open(dpm.name))
145   			return -1;
146   }
147   dpm.fd = 1;
148 //  clear_pipe = 0;
149   return 0;
150 }
151 
output_data(char * buf,int32 bytes)152 static int output_data(char *buf, int32 bytes)
153 {
154 	DWORD n;
155 	int ret;
156 	int32 retnum;
157 	retnum = bytes;
158 	DWORD length;
159 	char *clear_data;
160 
161 	if (hPipe == NULL) return -1;
162 	if ( ( 0 == PeekNamedPipe(hPipe,NULL,0,NULL,&length,NULL)) &&
163 		 (GetLastError()==ERROR_BAD_PIPE) )  return -1;
164 	if(dpm.fd == -1) return -1;
165 	if (pipe_close = 0){
166 		  hPipe=NULL;
167 		  dpm.fd = -1;
168 		  return retnum;
169 	}
170 
171 	if (0 != PeekNamedPipe(hPipe,NULL,0,NULL,&length,NULL)){
172 		if(clear_pipe == -1){
173 			if(bytes <= PIPE_BUFFER_SIZE-length){
174 				ret=WriteFile(hPipe,buf,bytes,&n,&pipe_ovlpd);
175 				if( (GetLastError() != ERROR_SUCCESS) &&
176 					(GetLastError() != ERROR_IO_PENDING) &&
177 					(GetLastError() != ERROR_BAD_PIPE) ){      //why BAD_PIPE occurs here?
178 	      			ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_error %s: %ld",
179 		    		dpm.name, GetLastError());
180 					if(hPipe != NULL) CloseHandle(hPipe);
181 		 			hPipe=NULL;
182 					dpm.fd = -1;
183 					return -1;
184 				}
185 			}else{
186 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_errror overflow");
187 			}
188 		}else{
189 			if(length < audio_buffer_size){
190 				clear_data = (char*)safe_malloc(audio_buffer_size-length);
191 				memset(clear_data, 0, audio_buffer_size-length);
192 				WriteFile(hPipe,clear_data,audio_buffer_size-length,&n,&pipe_ovlpd);
193 				free(clear_data);
194 				if( (GetLastError() != ERROR_SUCCESS) &&
195 					(GetLastError() != ERROR_IO_PENDING) &&
196 					(GetLastError() != ERROR_BAD_PIPE) ){      //why BAD_PIPE occurs here?
197 	      			ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_error %s: %ld",
198 		    		dpm.name, GetLastError());
199 					if(hPipe != NULL) CloseHandle(hPipe);
200 		 			hPipe=NULL;
201 					dpm.fd = -1;
202 					return -1;
203 				}
204 				clear_pipe =-1;
205 			}
206 		}
207 	}
208 	return retnum;
209 }
210 
close_output(void)211 static void close_output(void)
212 {
213 	if(dpm.fd != -1){
214 		CloseHandle(hPipeEvent);
215 		CloseHandle(hPipe);
216 		hPipe=NULL;
217     	dpm.fd = -1;
218 	}
219 }
220 
acntl(int request,void * arg)221 static int acntl(int request, void *arg)
222 {
223   switch(request) {
224   case PM_REQ_PLAY_START:
225     return 0;
226   case PM_REQ_PLAY_END:
227     return 0;
228   case PM_REQ_DISCARD:
229   case PM_REQ_FLUSH:
230 //		clear_pipe=0;
231   	return 0;
232 
233   }
234   return -1;
235 }
236 
npipe_a_pipe_close()237 int npipe_a_pipe_close()
238 {
239 	int count;
240 	if (hPipe == NULL) return;
241 	pipe_close=0;
242 	count = 100;
243 	while( (hPipe != NULL) && (count >0)) Sleep(10);
244 	if (hPipe != NULL){
245 		CloseHandle(hPipe);
246 		hPipe=NULL;
247 	}
248 
249 }
250 
251 
252 
253