int main(int argc, char **argv) { time_t cur_time; pthread_t signal_thread; pthread_t reader_thread; pthread_t ipc_thread; QUEUE_T *p_queue = create_queue(MAX_QUEUE); BUFSZ *bufptr; decoder *decoder = NULL; splitter *splitter = NULL; static thread_data tdata; decoder_options dopt = { 4, /* round */ 0, /* strip */ 0 /* emm */ }; tdata.dopt = &dopt; tdata.lnb = 0; tdata.tfd = -1; int result; int option_index; struct option long_options[] = { #ifdef HAVE_LIBARIB25 { "b25", 0, NULL, 'b'}, { "B25", 0, NULL, 'b'}, { "round", 1, NULL, 'r'}, { "strip", 0, NULL, 's'}, { "emm", 0, NULL, 'm'}, { "EMM", 0, NULL, 'm'}, #endif { "LNB", 1, NULL, 'n'}, { "lnb", 1, NULL, 'n'}, { "udp", 0, NULL, 'u'}, { "addr", 1, NULL, 'a'}, { "port", 1, NULL, 'p'}, { "http", 1, NULL, 'H'}, { "dev", 1, NULL, 'd'}, { "help", 0, NULL, 'h'}, { "version", 0, NULL, 'v'}, { "sid", 1, NULL, 'i'}, { "tsid", 1, NULL, 't'}, { "lch", 0, NULL, 'c'}, {0, 0, NULL, 0} /* terminate */ }; boolean use_b25 = FALSE; boolean use_udp = FALSE; boolean use_http = FALSE; boolean fileless = FALSE; boolean use_stdout = FALSE; boolean use_splitter = FALSE; boolean use_lch = FALSE; char *host_to = NULL; int port_to = 1234; int port_http = 12345; sock_data *sockdata = NULL; int dev_num = 0; int val; char *voltage[] = {"0V", "11V", "15V"}; char *sid_list = NULL; unsigned int tsid = 0; int connected_socket, listening_socket; unsigned int len; char *channel, *pch = NULL; while((result = getopt_long(argc, argv, "br:smn:ua:H:p:d:hvitcl:", long_options, &option_index)) != -1) { switch(result) { case 'b': use_b25 = TRUE; fprintf(stderr, "using B25...¥n"); break; case 's': dopt.strip = TRUE; fprintf(stderr, "enable B25 strip¥n"); break; case 'm': dopt.emm = TRUE; fprintf(stderr, "enable B25 emm processing¥n"); break; case 'u': use_udp = TRUE; host_to = "localhost"; fprintf(stderr, "enable UDP broadcasting¥n"); break; case 'H': use_http = TRUE; port_http = atoi(optarg); fprintf(stderr, "creating a http daemon¥n"); break; case 'h': fprintf(stderr, "¥n"); show_usage(argv[0]); fprintf(stderr, "¥n"); show_options(); fprintf(stderr, "¥n"); exit(0); break; case 'v': fprintf(stderr, "%s %s¥n", argv[0], version); fprintf(stderr, "recorder command for DVB tuner.¥n"); exit(0); break; /* following options require argument */ case 'n': val = atoi(optarg); switch(val) { case 11: tdata.lnb = 1; break; case 15: tdata.lnb = 2; break; default: tdata.lnb = 0; break; } fprintf(stderr, "LNB = %s¥n", voltage[tdata.lnb]); break; case 'r': dopt.round = atoi(optarg); fprintf(stderr, "set round %d¥n", dopt.round); break; case 'a': use_udp = TRUE; host_to = optarg; fprintf(stderr, "UDP destination address: %s¥n", host_to); break; case 'p': port_to = atoi(optarg); fprintf(stderr, "UDP port: %d¥n", port_to); break; case 'd': dev_num = atoi(optarg); fprintf(stderr, "using device: /dev/dvb/adapter%d¥n", dev_num); break; case 'i': use_splitter = TRUE; sid_list = optarg; break; case 't': tsid = atoi(optarg); if(strlen(optarg) > 2){ if((optarg[0] == '0') && ((optarg[1] == 'X') ||(optarg[1] == 'x'))){ sscanf(optarg+2, "%x", &tsid); } } fprintf(stderr, "tsid = 0x%x¥n", tsid); break; case 'c': use_lch = TRUE; break; } } if(use_http){ // http-server add- fprintf(stderr, "run as a daemon..¥n"); if(daemon(1,1)){ perror("failed to start"); return 1; } fprintf(stderr, "pid = %d¥n", getpid()); struct sockaddr_in sin; int ret; int sock_optval = 1; listening_socket = socket(AF_INET, SOCK_STREAM, 0); if ( listening_socket == -1 ){ perror("socket"); return 1; } if ( setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &sock_optval, sizeof(sock_optval)) == -1 ){ perror("setsockopt"); return 1; } sin.sin_family = AF_INET; sin.sin_port = htons(port_http); sin.sin_addr.s_addr = htonl(INADDR_ANY); if ( bind(listening_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0 ){ perror("bind"); return 1; } ret = listen(listening_socket, SOMAXCONN); if ( ret == -1 ){ perror("listen"); return 1; } fprintf(stderr,"listening at port %d¥n", port_http); //set rectime to the infinite if(parse_time("-",&tdata.recsec) != 0){ return 1; } if(tdata.recsec == -1) tdata.indefinite = TRUE; }else{ // -http-server add if(argc - optind < 3) { if(argc - optind == 2 && use_udp) { fprintf(stderr, "Fileless UDP broadcasting¥n"); fileless = TRUE; tdata.wfd = -1; } else { fprintf(stderr, "Some required parameters are missing!¥n"); fprintf(stderr, "Try '%s --help' for more information.¥n", argv[0]); return 1; } } fprintf(stderr, "pid = %d¥n", getpid()); if(use_lch){ set_lch(argv[optind], &pch, &sid_list, &tsid); if(sid_list) use_splitter = TRUE; fprintf(stderr, "tsid = 0x%x¥n", tsid); } if(pch == NULL) pch = argv[optind]; /* tune */ if(tune(pch, &tdata, dev_num, tsid) != 0) return 1; /* set recsec */ if(parse_time(argv[optind + 1], &tdata.recsec) != 0) // no other thread --yaz return 1; if(tdata.recsec == -1) tdata.indefinite = TRUE; /* open output file */ char *destfile = argv[optind + 2]; if(destfile && !strcmp("-", destfile)) { use_stdout = TRUE; tdata.wfd = 1; /* stdout */ } else { if(!fileless) { int status; char *path = strdup(argv[optind + 2]); char *dir = dirname(path); status = mkpath(dir, 0777); if(status == -1) perror("mkpath"); free(path); tdata.wfd = open(argv[optind + 2], (O_RDWR | O_CREAT | O_TRUNC), 0666); if(tdata.wfd < 0) { fprintf(stderr, "Cannot open output file: %s¥n", argv[optind + 2]); return 1; } } } } // http-server add /* initialize decoder */ if(use_b25) { decoder = b25_startup(&dopt); if(!decoder) { fprintf(stderr, "Cannot start b25 decoder¥n"); fprintf(stderr, "Fall back to encrypted recording¥n"); use_b25 = FALSE; } } while(1){ // http-server add- if(use_http){ struct hostent *peer_host; struct sockaddr_in peer_sin; pch = NULL; sid_list = NULL; len = sizeof(peer_sin); connected_socket = accept(listening_socket, (struct sockaddr *)&peer_sin, &len); if ( connected_socket == -1 ){ perror("accept"); return 1; } peer_host = gethostbyaddr((char *)&peer_sin.sin_addr.s_addr, sizeof(peer_sin.sin_addr), AF_INET); if ( peer_host == NULL ){ fprintf(stderr, "gethostbyname failed¥n"); return 1; } fprintf(stderr,"connect from: %s [%s] port %d¥n", peer_host->h_name, inet_ntoa(peer_sin.sin_addr), ntohs(peer_sin.sin_port)); char buf[256]; read_line(connected_socket, buf); fprintf(stderr,"request command is %s¥n",buf); char s0[256],s1[256],s2[256]; sscanf(buf,"%s%s%s",s0,s1,s2); char delim[] = "/"; channel = strtok(s1,delim); char *sidflg = strtok(NULL,delim); if(sidflg) sid_list = sidflg; if(use_lch) set_lch(channel, &pch, &sid_list, &tsid); if(pch == NULL) pch = channel; fprintf(stderr,"channel is %s¥n",channel); if(sid_list == NULL){ use_splitter = FALSE; splitter = NULL; }else if(!strcmp(sid_list,"all")){ use_splitter = FALSE; splitter = NULL; }else{ use_splitter = TRUE; } } // -http-server add /* initialize splitter */ if(use_splitter) { splitter = split_startup(sid_list); if(splitter->sid_list == NULL) { fprintf(stderr, "Cannot start TS splitter¥n"); return 1; } } if(use_http){ // http-server add- char header[100]; if(use_b25) { strcpy(header, "HTTP/1.1 200 OK¥r¥nContent-Type: video/mpeg¥r¥nCache-Control: no-cache¥r¥n¥r¥n"); }else if(!strcmp(sid_list,"1seg")){ strcpy(header, "HTTP/1.1 200 OK¥r¥nContent-Type: video/mpeg¥r¥nCache-Control: no-cache¥r¥n¥r¥n"); }else{ strcpy(header, "HTTP/1.1 200 OK¥r¥nContent-Type: application/octet-stream¥r¥nCache-Control: no-cache¥r¥n¥r¥n"); } write(connected_socket, header, strlen(header)); //set write target to http tdata.wfd = connected_socket; //tune if(tune(pch, &tdata, dev_num, tsid) != 0){ fprintf(stderr, "Tuner cannot start recording¥n"); continue; } }else{ // -http-server add /* initialize udp connection */ if(use_udp) { sockdata = calloc(1, sizeof(sock_data)); struct in_addr ia; ia.s_addr = inet_addr(host_to); if(ia.s_addr == INADDR_NONE) { struct hostent *hoste = gethostbyname(host_to); if(!hoste) { perror("gethostbyname"); return 1; } ia.s_addr = *(in_addr_t*) (hoste->h_addr_list[0]); } if((sockdata->sfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } sockdata->addr.sin_family = AF_INET; sockdata->addr.sin_port = htons (port_to); sockdata->addr.sin_addr.s_addr = ia.s_addr; if(connect(sockdata->sfd, (struct sockaddr *)&sockdata->addr, sizeof(sockdata->addr)) < 0) { perror("connect"); return 1; } } } // http-server add /* prepare thread data */ tdata.queue = p_queue; tdata.decoder = decoder; tdata.splitter = splitter; tdata.sock_data = sockdata; tdata.tune_persistent = FALSE; /* spawn signal handler thread */ init_signal_handlers(&signal_thread, &tdata); /* spawn reader thread */ tdata.signal_thread = signal_thread; pthread_create(&reader_thread, NULL, reader_func, &tdata); /* spawn ipc thread */ key_t key; key = (key_t)getpid(); if ((tdata.msqid = msgget(key, IPC_CREAT | 0666)) < 0) { perror("msgget"); } pthread_create(&ipc_thread, NULL, mq_recv, &tdata); fprintf(stderr, "¥nRecording...¥n"); time(&tdata.start_time); /* read from tuner */ while(1) { if(f_exit) break; time(&cur_time); bufptr = malloc(sizeof(BUFSZ)); if(!bufptr) { f_exit = TRUE; break; } bufptr->size = read(tdata.tfd, bufptr->buffer, MAX_READ_SIZE); if(bufptr->size <= 0) { if((cur_time - tdata.start_time) >= tdata.recsec && !tdata.indefinite) { f_exit = TRUE; enqueue(p_queue, NULL); break; } else { free(bufptr); continue; } } enqueue(p_queue, bufptr); /* stop recording */ time(&cur_time); if((cur_time - tdata.start_time) >= tdata.recsec && !tdata.indefinite) { break; } } /* delete message queue*/ msgctl(tdata.msqid, IPC_RMID, NULL); pthread_kill(signal_thread, SIGUSR1); /* wait for threads */ pthread_join(reader_thread, NULL); pthread_join(signal_thread, NULL); pthread_join(ipc_thread, NULL); /* close tuner */ if(close_tuner(&tdata) != 0) return 1; /* release queue */ destroy_queue(p_queue); if(use_http){ // http-server add- //reset queue p_queue = create_queue(MAX_QUEUE); /* close http socket */ close(tdata.wfd); fprintf(stderr,"connection closed. still listening at port %d¥n",port_http); f_exit = FALSE; }else{ // -http-server add /* close output file */ if(!use_stdout){ fsync(tdata.wfd); close(tdata.wfd); } /* free socket data */ if(use_udp) { close(sockdata->sfd); free(sockdata); } /* release decoder */ if(!use_http) if(use_b25) { b25_shutdown(decoder); } } // http-server add if(use_splitter) { split_shutdown(splitter); } if(!use_http) // http-server add return 0; } // http-server add }
int tune(char *channel, thread_data *tdata, char *driver) { /* get channel */ BON_CHANNEL_SET *channel_set = searchrecoff(tdata->dwSpace, channel); if(channel_set == NULL) { fprintf(stderr, "Invalid Channel: %s\n", channel); return 1; } DWORD dwSendBonNum; boolean reqChannel; fprintf(stderr, "Space = %d\n", channel_set->bon_space); if(channel_set->bon_num != ARIB_CH_ERROR){ dwSendBonNum = channel_set->bon_num; reqChannel = FALSE; fprintf(stderr, "Channel = B%d\n", channel_set->bon_num); }else{ dwSendBonNum = channel_set->set_freq; reqChannel = TRUE; fprintf(stderr, "Channel = %dkHz\n", channel_set->set_freq); } /* open tuner */ char *dri_tmp = driver; int aera; char **tuner; int num_devs; if(dri_tmp && *dri_tmp == 'P'){ // proxy dri_tmp++; aera = 1; }else aera = 0; if(dri_tmp && *dri_tmp != '\0') { /* case 1: specified tuner driver */ int num = 0; int code; if(*dri_tmp == 'S'){ if(channel_set->type != CHTYPE_GROUND){ if(aera == 0){ tuner = bsdev; num_devs = NUM_BSDEV; }else{ tuner = bsdev_proxy; num_devs = NUM_BSDEV_PROXY; } }else goto OPEN_TUNER; }else if(*dri_tmp == 'T'){ if(channel_set->type != CHTYPE_SATELLITE){ if(aera == 0){ tuner = isdb_t_dev; num_devs = NUM_ISDB_T_DEV; }else{ tuner = isdb_t_dev_proxy; num_devs = NUM_ISDB_T_DEV_PROXY; } }else goto OPEN_TUNER; }else goto OPEN_TUNER; if(!isdigit(*++dri_tmp)) goto OPEN_TUNER; do{ num = num * 10 + *dri_tmp++ - '0'; }while(isdigit(*dri_tmp)); if(*dri_tmp == '\0' && num+1 <= num_devs) driver = tuner[num]; OPEN_TUNER:; if((code = open_tuner(tdata, driver))){ if(code == -4) fprintf(stderr, "OpenTuner error: %s\n", driver); return 1; } /* tune to specified channel */ while(tdata->pIBon2->SetChannel(channel_set->bon_space, dwSendBonNum) == FALSE) { if(tdata->tune_persistent) { if(f_exit) goto err; fprintf(stderr, "No signal. Still trying: %s\n", driver); } else { fprintf(stderr, "Cannot tune to the specified channel: %s\n", driver); goto err; } } fprintf(stderr, "driver = %s\n", driver); } else { /* case 2: loop around available devices */ int lp; switch(channel_set->type){ case CHTYPE_BonNUMBER: default: fprintf(stderr, "No driver name\n"); goto err; case CHTYPE_SATELLITE: if(aera == 0){ tuner = bsdev; num_devs = NUM_BSDEV; }else{ tuner = bsdev_proxy; num_devs = NUM_BSDEV_PROXY; } break; case CHTYPE_GROUND: if(aera == 0){ tuner = isdb_t_dev; num_devs = NUM_ISDB_T_DEV; }else{ tuner = isdb_t_dev_proxy; num_devs = NUM_ISDB_T_DEV_PROXY; } break; } for(lp = 0; lp < num_devs; lp++) { if(open_tuner(tdata, tuner[lp]) == 0) { // 同CHチェック DWORD m_dwSpace = tdata->pIBon2->GetCurSpace(); DWORD m_dwChannel = tdata->pIBon2->GetCurChannel(); if(m_dwSpace == channel_set->bon_space && m_dwChannel == dwSendBonNum) goto SUCCESS_EXIT; else{ close_tuner(tdata); continue; } } } for(lp = 0; lp < num_devs; lp++) { int count = 0; if(open_tuner(tdata, tuner[lp]) == 0) { // 使用中チェック・BSのCh比較は、局再編があると正しくない可能性がある DWORD m_dwSpace = tdata->pIBon2->GetCurSpace(); DWORD m_dwChannel = tdata->pIBon2->GetCurChannel(); if(m_dwChannel != ARIB_CH_ERROR){ if(m_dwSpace != channel_set->bon_space || m_dwChannel != dwSendBonNum){ close_tuner(tdata); continue; } }else{ /* tune to specified channel */ if(tdata->tune_persistent) { while(tdata->pIBon2->SetChannel(channel_set->bon_space, dwSendBonNum) == FALSE && count < MAX_RETRY) { if(f_exit) goto err; fprintf(stderr, "No signal. Still trying: %s\n", tuner[lp]); count++; } if(count >= MAX_RETRY) { close_tuner(tdata); count = 0; continue; } } /* tune_persistent */ else { if(tdata->pIBon2->SetChannel(channel_set->bon_space, dwSendBonNum) == FALSE) { close_tuner(tdata); continue; } } } goto SUCCESS_EXIT; /* found suitable tuner */ } } /* all tuners cannot be used */ fprintf(stderr, "Cannot tune to the specified channel\n"); return 1; SUCCESS_EXIT: if(tdata->tune_persistent) fprintf(stderr, "driver = %s\n", tuner[lp]); } tdata->table = channel_set; if(reqChannel) { channel_set->bon_space = tdata->pIBon2->GetCurSpace(); channel_set->bon_num = tdata->pIBon2->GetCurChannel(); } // TS受信開始待ち timespec ts; ts.tv_sec = 0; ts.tv_nsec = 50 * 1000 * 1000; // 50ms { int lop = 0; do{ nanosleep(&ts, NULL); }while(tdata->pIBon->GetReadyCount() < 2 && ++lop < 20); } if(!tdata->tune_persistent) { /* show signal strength */ calc_cn(tdata, FALSE); } return 0; /* success */ err: close_tuner(tdata); return 1; }
int main(int argc, char **argv) { pthread_t signal_thread; static thread_data tdata; int result; int option_index; struct option long_options[] = { { "bell", 0, NULL, 'b'}, { "help", 0, NULL, 'h'}, { "version", 0, NULL, 'v'}, { "list", 0, NULL, 'l'}, { "driver", 1, NULL, 'd'}, {0, 0, NULL, 0} /* terminate */ }; tdata.hModule = NULL; tdata.dwSpace = 0; tdata.table = NULL; char *driver = NULL; boolean use_bell = FALSE; while((result = getopt_long(argc, argv, "bhvln:d:", long_options, &option_index)) != -1) { switch(result) { case 'b': use_bell = TRUE; break; case 'h': fprintf(stderr, "\n"); show_usage(argv[0]); fprintf(stderr, "\n"); show_options(); fprintf(stderr, "\n"); show_channels(); fprintf(stderr, "\n"); exit(0); break; case 'v': fprintf(stderr, "%s %s\n", argv[0], version); fprintf(stderr, "signal check utility for BonDriver based tuners.\n"); exit(0); break; case 'l': show_channels(); exit(0); break; case 'd': driver = optarg; break; } } if(argc - optind < 1) { fprintf(stderr, "channel must be specified!\n"); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } /* set tune_persistent flag */ tdata.tune_persistent = TRUE; /* spawn signal handler thread */ init_signal_handlers(&signal_thread, &tdata); /* tune */ if(tune(argv[optind], &tdata, driver) != 0) return 1; while(1) { if(f_exit) break; tdata.pIBon->PurgeTsStream(); // 凡ドラはCh設定時からストリームデータをバッファに溜め込むため追加 /* show signal strength */ calc_cn(&tdata, use_bell); sleep(1); } /* wait for signal thread */ pthread_kill(signal_thread, SIGUSR1); pthread_join(signal_thread, NULL); /* close tuner */ if(close_tuner(&tdata) != 0) return 1; return 0; }