mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-30 11:57:27 +01:00
initial BNSF support, with placeholder Siren 14 support (disabled for now)
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@758 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
df9dc92aa5
commit
b29738d9df
@ -18,7 +18,8 @@ CODING_OBJS=coding/adx_decoder.o \
|
|||||||
coding/aica_decoder.o \
|
coding/aica_decoder.o \
|
||||||
coding/nds_procyon_decoder.o \
|
coding/nds_procyon_decoder.o \
|
||||||
coding/l5_555_decoder.o \
|
coding/l5_555_decoder.o \
|
||||||
coding/SASSC_decoder.o
|
coding/SASSC_decoder.o \
|
||||||
|
coding/g7221_decoder.o
|
||||||
|
|
||||||
LAYOUT_OBJS=layout/ast_blocked.o \
|
LAYOUT_OBJS=layout/ast_blocked.o \
|
||||||
layout/blocked.o \
|
layout/blocked.o \
|
||||||
@ -223,7 +224,8 @@ META_OBJS=meta/adx_header.o \
|
|||||||
meta/dmsg_segh.o \
|
meta/dmsg_segh.o \
|
||||||
meta/ngc_aaap.o \
|
meta/ngc_aaap.o \
|
||||||
meta/ngc_dsp_tmnt2.o \
|
meta/ngc_dsp_tmnt2.o \
|
||||||
meta/ps2_ster.o
|
meta/ps2_ster.o \
|
||||||
|
meta/bnsf.o
|
||||||
|
|
||||||
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
|
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
|
||||||
|
|
||||||
|
@ -26,5 +26,6 @@ libcoding_la_SOURCES += msadpcm_decoder.c
|
|||||||
libcoding_la_SOURCES += nds_procyon_decoder.c
|
libcoding_la_SOURCES += nds_procyon_decoder.c
|
||||||
libcoding_la_SOURCES += l5_555_decoder.c
|
libcoding_la_SOURCES += l5_555_decoder.c
|
||||||
libcoding_la_SOURCES += SASSC_decoder.c
|
libcoding_la_SOURCES += SASSC_decoder.c
|
||||||
|
libcoding_la_SOURCES += g7221_decoder.c
|
||||||
|
|
||||||
EXTRA_DIST = coding.h g72x_state.h
|
EXTRA_DIST = coding.h g72x_state.h
|
||||||
|
@ -78,6 +78,11 @@ void decode_mpeg(VGMSTREAMCHANNEL * stream,
|
|||||||
sample * outbuf, int32_t samples_to_do, int channels);
|
sample * outbuf, int32_t samples_to_do, int channels);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
void decode_g7221(VGMSTREAM *vgmstream,
|
||||||
|
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||||
|
#endif
|
||||||
|
|
||||||
void decode_acm(ACMStream * acm, sample * outbuf,
|
void decode_acm(ACMStream * acm, sample * outbuf,
|
||||||
int32_t samples_to_do, int channelspacing);
|
int32_t samples_to_do, int channelspacing);
|
||||||
|
|
||||||
|
28
src/coding/g7221_decoder.c
Normal file
28
src/coding/g7221_decoder.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "coding.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
/* just dump channels to files for now */
|
||||||
|
void decode_g7221(VGMSTREAM * vgmstream,
|
||||||
|
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||||
|
|
||||||
|
static FILE *dumpfiles[2] = {NULL,NULL};
|
||||||
|
|
||||||
|
if (0 == vgmstream->samples_into_block)
|
||||||
|
{
|
||||||
|
uint8_t buffer[960/8];
|
||||||
|
if (NULL == dumpfiles[channel])
|
||||||
|
{
|
||||||
|
char filename[] = "dump0.bin";
|
||||||
|
snprintf(filename,sizeof(filename),"dump%d.bin",channel);
|
||||||
|
dumpfiles[channel] = fopen(filename, "wb");
|
||||||
|
}
|
||||||
|
vgmstream->ch[channel].streamfile->read(vgmstream->ch[channel].streamfile, buffer, vgmstream->ch[channel].offset, vgmstream->interleave_block_size);
|
||||||
|
fwrite(buffer, 1, vgmstream->interleave_block_size, dumpfiles[channel]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -248,6 +248,10 @@
|
|||||||
RelativePath=".\meta\bgw.c"
|
RelativePath=".\meta\bgw.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\meta\bnsf.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\meta\brstm.c"
|
RelativePath=".\meta\brstm.c"
|
||||||
>
|
>
|
||||||
@ -970,6 +974,10 @@
|
|||||||
RelativePath=".\coding\g721_decoder.c"
|
RelativePath=".\coding\g721_decoder.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\g7221_decoder.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\coding\ima_decoder.c"
|
RelativePath=".\coding\ima_decoder.c"
|
||||||
>
|
>
|
||||||
|
@ -181,5 +181,6 @@ libmeta_la_SOURCES += dmsg_segh.c
|
|||||||
libmeta_la_SOURCES += ngc_aaap.c
|
libmeta_la_SOURCES += ngc_aaap.c
|
||||||
libmeta_la_SOURCES += ngc_dsp_tmnt2.c
|
libmeta_la_SOURCES += ngc_dsp_tmnt2.c
|
||||||
libmeta_la_SOURCES += ps2_ster.c
|
libmeta_la_SOURCES += ps2_ster.c
|
||||||
|
libmeta_la_SOURCES += bnsf.c
|
||||||
|
|
||||||
EXTRA_DIST = meta.h
|
EXTRA_DIST = meta.h
|
||||||
|
184
src/meta/bnsf.c
Normal file
184
src/meta/bnsf.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "meta.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
/* Namco Bandai's Bandai Namco Sound Format/File (BNSF) */
|
||||||
|
/* similar to RIFX */
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
char filename[260];
|
||||||
|
|
||||||
|
off_t file_size = -1;
|
||||||
|
uint32_t riff_size;
|
||||||
|
uint32_t bnsf_form;
|
||||||
|
enum {
|
||||||
|
form_IS14 = UINT32_C(0x49533134), /* IS14 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int channel_count = 0;
|
||||||
|
int sample_count = 0;
|
||||||
|
int sample_rate = 0;
|
||||||
|
int coding_type = -1;
|
||||||
|
off_t start_offset = -1;
|
||||||
|
|
||||||
|
int loop_flag = 0;
|
||||||
|
off_t loop_start = -1;
|
||||||
|
off_t loop_end = -1;
|
||||||
|
uint32_t data_size = 0;
|
||||||
|
uint32_t block_size = 0;
|
||||||
|
uint32_t block_samples = 0;
|
||||||
|
|
||||||
|
int FormatChunkFound = 0;
|
||||||
|
int DataChunkFound = 0;
|
||||||
|
|
||||||
|
/* check extension, case insensitive */
|
||||||
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
if (strcasecmp("bnsf",filename_extension(filename)))
|
||||||
|
{
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check header */
|
||||||
|
if ((uint32_t)read_32bitBE(0,streamFile)!=0x424E5346) /* BNSF */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* check form */
|
||||||
|
bnsf_form = read_32bitBE(8,streamFile);
|
||||||
|
switch (bnsf_form)
|
||||||
|
{
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case form_IS14:
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
riff_size = read_32bitBE(4,streamFile);
|
||||||
|
file_size = get_streamfile_size(streamFile);
|
||||||
|
|
||||||
|
/* check for tructated RIFF */
|
||||||
|
if (file_size < riff_size+8) goto fail;
|
||||||
|
|
||||||
|
/* read through chunks to verify format and find metadata */
|
||||||
|
{
|
||||||
|
off_t current_chunk = 0xc; /* start with first chunk */
|
||||||
|
|
||||||
|
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
||||||
|
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||||
|
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile);
|
||||||
|
|
||||||
|
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||||
|
|
||||||
|
switch(chunk_type) {
|
||||||
|
case 0x73666d74: /* "sfmt" */
|
||||||
|
/* only one per file */
|
||||||
|
if (FormatChunkFound) goto fail;
|
||||||
|
FormatChunkFound = 1;
|
||||||
|
|
||||||
|
sample_rate = read_32bitBE(current_chunk+0x0c,streamFile);
|
||||||
|
channel_count = read_16bitBE(current_chunk+0x0a,streamFile);
|
||||||
|
// read_32bitBE(current_chunk+0x10,streamFile); // ?
|
||||||
|
// read_32bitBE(current_chunk+0x14,streamFile); // ?
|
||||||
|
block_size = read_16bitBE(current_chunk+0x18,streamFile);
|
||||||
|
block_samples = read_16bitBE(current_chunk+0x1a,streamFile);
|
||||||
|
|
||||||
|
/* I assume this is still the codec id, but as the codec is
|
||||||
|
specified by the BNSF "form" I've only seen this zero */
|
||||||
|
switch ((uint16_t)read_16bitBE(current_chunk+0x8,streamFile)) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x73646174: /* sdat */
|
||||||
|
/* at most one per file */
|
||||||
|
if (DataChunkFound) goto fail;
|
||||||
|
DataChunkFound = 1;
|
||||||
|
|
||||||
|
start_offset = current_chunk + 8;
|
||||||
|
data_size = chunk_size;
|
||||||
|
break;
|
||||||
|
case 0x6C6F6F70: /* loop */
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_start =
|
||||||
|
read_32bitBE(current_chunk+8, streamFile);
|
||||||
|
loop_end =
|
||||||
|
read_32bitBE(current_chunk+0xc,streamFile);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignorance is bliss */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_chunk += 8+chunk_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
||||||
|
|
||||||
|
switch (bnsf_form) {
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case form_IS14:
|
||||||
|
coding_type = coding_G7221C;
|
||||||
|
sample_count = data_size/block_size*block_samples;
|
||||||
|
|
||||||
|
/* check for 0 bytes at start */
|
||||||
|
if (0 != read_32bitBE(start_offset,streamFile))
|
||||||
|
{
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* skip */
|
||||||
|
start_offset += 4;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
|
||||||
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
/* fill in the vital statistics */
|
||||||
|
vgmstream->num_samples = sample_count;
|
||||||
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
|
||||||
|
vgmstream->coding_type = coding_type;
|
||||||
|
if (channel_count > 1)
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
else
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->interleave_block_size = block_size/channel_count;
|
||||||
|
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = loop_start;
|
||||||
|
vgmstream->loop_end_sample = loop_end;
|
||||||
|
}
|
||||||
|
vgmstream->meta_type = meta_BNSF;
|
||||||
|
|
||||||
|
/* open the file, set up each channel */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||||
|
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
|
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||||
|
|
||||||
|
for (i=0;i<channel_count;i++) {
|
||||||
|
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||||
|
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
||||||
|
start_offset+i*vgmstream->interleave_block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
/* clean up anything we may have opened */
|
||||||
|
fail:
|
||||||
|
if (vgmstream) close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
@ -447,4 +447,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_tmnt2(STREAMFILE* streamFile);
|
|||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ps2_ster(STREAMFILE* streamFile);
|
VGMSTREAM * init_vgmstream_ps2_ster(STREAMFILE* streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE* streamFile);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -244,6 +244,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
|||||||
init_vgmstream_ngc_aaap,
|
init_vgmstream_ngc_aaap,
|
||||||
init_vgmstream_ngc_dsp_tmnt2,
|
init_vgmstream_ngc_dsp_tmnt2,
|
||||||
init_vgmstream_ps2_ster,
|
init_vgmstream_ps2_ster,
|
||||||
|
init_vgmstream_bnsf,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
||||||
@ -748,6 +749,12 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
|
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
|
||||||
case coding_NDS_PROCYON:
|
case coding_NDS_PROCYON:
|
||||||
return 30;
|
return 30;
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case coding_G7221C:
|
||||||
|
return 32000/50;
|
||||||
|
case coding_G7221:
|
||||||
|
return 16000/50;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -829,6 +836,10 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
return 1;
|
return 1;
|
||||||
case coding_APPLE_IMA4:
|
case coding_APPLE_IMA4:
|
||||||
return 34;
|
return 34;
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case coding_G7221C:
|
||||||
|
case coding_G7221:
|
||||||
|
#endif
|
||||||
case coding_MSADPCM:
|
case coding_MSADPCM:
|
||||||
return vgmstream->interleave_block_size;
|
return vgmstream->interleave_block_size;
|
||||||
default:
|
default:
|
||||||
@ -1151,6 +1162,18 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
buffer+samples_written*vgmstream->channels,samples_to_do,
|
buffer+samples_written*vgmstream->channels,samples_to_do,
|
||||||
vgmstream->channels);
|
vgmstream->channels);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case coding_G7221:
|
||||||
|
case coding_G7221C:
|
||||||
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
decode_g7221(vgmstream,
|
||||||
|
buffer+samples_written*vgmstream->channels,
|
||||||
|
vgmstream->channels,
|
||||||
|
samples_to_do,
|
||||||
|
chan);
|
||||||
|
}
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case coding_ACM:
|
case coding_ACM:
|
||||||
/* handled in its own layout, here to quiet compiler */
|
/* handled in its own layout, here to quiet compiler */
|
||||||
@ -1517,6 +1540,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||||||
case coding_MPEG25_L3:
|
case coding_MPEG25_L3:
|
||||||
snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer III Audio (MP3)");
|
snprintf(temp,TEMPSIZE,"MPEG-2.5 Layer III Audio (MP3)");
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
case coding_G7221:
|
||||||
|
snprintf(temp,TEMPSIZE,"ITU G.722.1 (Polycom Siren 7)");
|
||||||
|
break;
|
||||||
|
case coding_G7221C:
|
||||||
|
snprintf(temp,TEMPSIZE,"ITU G.722.1 annex C (Polycom Siren 14)");
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case coding_ACM:
|
case coding_ACM:
|
||||||
snprintf(temp,TEMPSIZE,"InterPlay ACM");
|
snprintf(temp,TEMPSIZE,"InterPlay ACM");
|
||||||
@ -2407,6 +2438,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||||||
case meta_PS2_STER:
|
case meta_PS2_STER:
|
||||||
snprintf(temp,TEMPSIZE,"STER Header");
|
snprintf(temp,TEMPSIZE,"STER Header");
|
||||||
break;
|
break;
|
||||||
|
case meta_BNSF:
|
||||||
|
snprintf(temp,TEMPSIZE,"Namco Bandai BNSF header");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
#ifndef _VGMSTREAM_H
|
#ifndef _VGMSTREAM_H
|
||||||
#define _VGMSTREAM_H
|
#define _VGMSTREAM_H
|
||||||
|
|
||||||
/* Vorbis and MPEG decoding are done by external libraries.
|
/* Due mostly to licensing issues, Vorbis, MPEG, G.722.1 decoding are
|
||||||
|
* done by external libraries.
|
||||||
* If someone wants to do a standalone build, they can do it by simply
|
* If someone wants to do a standalone build, they can do it by simply
|
||||||
* removing these defines (and the references to the libraries in the
|
* removing these defines (and the references to the libraries in the
|
||||||
* Makefile) */
|
* Makefile) */
|
||||||
#define VGM_USE_VORBIS
|
#define VGM_USE_VORBIS
|
||||||
#define VGM_USE_MPEG
|
#define VGM_USE_MPEG
|
||||||
|
//#define VGM_USE_G7221
|
||||||
|
|
||||||
#include "streamfile.h"
|
#include "streamfile.h"
|
||||||
#include "coding/g72x_state.h"
|
#include "coding/g72x_state.h"
|
||||||
@ -91,6 +93,10 @@ typedef enum {
|
|||||||
coding_MPEG25_L2,
|
coding_MPEG25_L2,
|
||||||
coding_MPEG25_L3,
|
coding_MPEG25_L3,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef VGM_USE_G7221
|
||||||
|
coding_G7221, /* G.722.1 (Polycom Siren 7) */
|
||||||
|
coding_G7221C, /* G.722.1 with Annex C extension (Polycom Siren 14) */
|
||||||
|
#endif
|
||||||
|
|
||||||
coding_ACM, /* InterPlay ACM */
|
coding_ACM, /* InterPlay ACM */
|
||||||
/* compressed NWA at various levels */
|
/* compressed NWA at various levels */
|
||||||
@ -212,6 +218,7 @@ typedef enum {
|
|||||||
meta_CFN, /* Namco CAF Audio File */
|
meta_CFN, /* Namco CAF Audio File */
|
||||||
meta_MYSPD, /* U-Sing .myspd */
|
meta_MYSPD, /* U-Sing .myspd */
|
||||||
meta_HIS, /* Her Ineractive .his */
|
meta_HIS, /* Her Ineractive .his */
|
||||||
|
meta_BNSF, /* Bandai Namco Sound Format */
|
||||||
|
|
||||||
meta_PS2_SShd, /* .ADS with SShd header */
|
meta_PS2_SShd, /* .ADS with SShd header */
|
||||||
meta_PS2_NPSF, /* Namco Production Sound File */
|
meta_PS2_NPSF, /* Namco Production Sound File */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user