static int Open (vlc_object_t *obj) { aout_instance_t *aout = (aout_instance_t *)obj; aout_sys_t *sys = malloc (sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; aout->output.p_sys = sys; sys->opaque = var_InheritAddress (obj, "amem-data"); sys->play = var_InheritAddress (obj, "amem-play"); sys->set_volume = var_InheritAddress (obj, "amem-set-volume"); sys->cleanup = NULL; /* defer */ if (sys->play == NULL) goto error; vlc_audio_format_cb setup = var_InheritAddress (obj, "amem-setup"); char format[5] = "S16N"; unsigned rate, channels; if (setup != NULL) { rate = aout->output.output.i_rate; channels = aout_FormatNbChannels(&aout->output.output); if (setup (&sys->opaque, format, &rate, &channels)) goto error; /* Only call this callback if setup succeeded */ sys->cleanup = var_InheritAddress (obj, "amem-cleanup"); } else { rate = var_InheritInteger (obj, "amem-rate"); channels = var_InheritInteger (obj, "amem-channels"); } if (rate == 0 || rate > 192000 || channels == 0 || channels > AOUT_CHAN_MAX) goto error; /* TODO: amem-format */ /* FIXME/TODO channel mapping */ if (strcmp(format, "S16N") || aout->output.output.i_channels != channels) { msg_Err (aout, "format not supported"); goto error; } aout->output.output.i_format = VLC_CODEC_S16N; aout->output.output.i_rate = rate; aout->output.pf_play = Play; if (sys->set_volume != NULL) aout->output.pf_volume_set = VolumeSet; else aout_VolumeSoftInit (aout); return VLC_SUCCESS; error: Close (obj); return VLC_EGENERIC; }
/***************************************************************************** * OpenAudio: open a dummy audio device *****************************************************************************/ int OpenAudio ( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; p_aout->output.pf_play = Play; p_aout->output.pf_pause = NULL; aout_VolumeSoftInit( p_aout ); if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && var_InheritBool( p_this, "spdif" ) ) { p_aout->output.output.i_format = VLC_CODEC_SPDIFL; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; } else p_aout->output.output.i_format = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N; p_aout->output.i_nb_samples = A52_FRAME_NB; /* Create the variable for the audio-device */ var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); return VLC_SUCCESS; }
static int Open ( vlc_object_t *p_this ) { audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t *p_sys = malloc(sizeof(aout_sys_t)); p_aout->sys = p_sys; OSStatus status = 0; // Setup the audio device. AudioStreamBasicDescription deviceFormat; deviceFormat.mSampleRate = 44100; deviceFormat.mFormatID = kAudioFormatLinearPCM; deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // Signed integer, little endian deviceFormat.mBytesPerPacket = 4; deviceFormat.mFramesPerPacket = 1; deviceFormat.mBytesPerFrame = 4; deviceFormat.mChannelsPerFrame = 2; deviceFormat.mBitsPerChannel = 16; deviceFormat.mReserved = 0; // Create a new output AudioQueue for the device. status = AudioQueueNewOutput(&deviceFormat, // Format AudioQueueCallback, // Callback p_aout, // User data, passed to the callback CFRunLoopGetMain(), // RunLoop kCFRunLoopDefaultMode, // RunLoop mode 0, // Flags ; must be zero (per documentation)... &(p_sys->audioQueue)); // Output // This will be used for boosting the audio without the need of a mixer (floating-point conversion is expensive on ARM) // AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, 12.0); // Defaults to 1.0 msg_Dbg(p_aout, "New AudioQueue output created (status = %i)", status); // Allocate buffers for the AudioQueue, and pre-fill them. for (int i = 0; i < NUMBER_OF_BUFFERS; ++i) { AudioQueueBufferRef buffer = NULL; status = AudioQueueAllocateBuffer(p_sys->audioQueue, FRAME_SIZE * 4, &buffer); AudioQueueCallback(NULL, p_sys->audioQueue, buffer); } /* Volume is entirely done in software. */ aout_VolumeSoftInit( p_aout ); p_aout->format.i_format = VLC_CODEC_S16L; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; p_aout->format.i_rate = 44100; aout_PacketInit(p_aout, &p_sys->packet, FRAME_SIZE); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; msg_Dbg(p_aout, "Starting AudioQueue (status = %i)", status); status = AudioQueueStart(p_sys->audioQueue, NULL); return VLC_SUCCESS; }
/***************************************************************************** * OpenAudio *****************************************************************************/ int E_(OpenAudio) ( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t*) p_this; p_aout->output.p_sys = (aout_sys_t*) malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return -1; } aout_sys_t * p_sys = p_aout->output.p_sys; aout_VolumeSoftInit( p_aout ); int i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); /* BSoundPlayer does not support more than 2 channels AFAIK */ if( i_nb_channels > 2 ) { i_nb_channels = 2; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } media_raw_audio_format * p_format; p_format = (media_raw_audio_format*) malloc( sizeof( media_raw_audio_format ) ); p_format->channel_count = i_nb_channels; p_format->frame_rate = p_aout->output.output.i_rate; p_format->format = media_raw_audio_format::B_AUDIO_FLOAT; #ifdef WORDS_BIGENDIAN p_format->byte_order = B_MEDIA_BIG_ENDIAN; #else p_format->byte_order = B_MEDIA_LITTLE_ENDIAN; #endif p_format->buffer_size = 8192; p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2'); p_aout->output.i_nb_samples = 2048 / i_nb_channels; p_aout->output.pf_play = DoNothing; p_sys->p_player = new BSoundPlayer( p_format, "player", Play, NULL, p_aout ); if( p_sys->p_player->InitCheck() != B_OK ) { msg_Err( p_aout, "BSoundPlayer InitCheck failed" ); delete p_sys->p_player; free( p_sys ); return -1; } /* Start playing */ p_sys->latency = p_sys->p_player->Latency(); p_sys->p_player->Start(); p_sys->p_player->SetHasData( true ); return 0; }
/***************************************************************************** * OpenAudio: open a dummy audio device *****************************************************************************/ int E_(OpenAudio) ( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; p_aout->output.pf_play = Play; aout_VolumeSoftInit( p_aout ); if ( p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i') ) { p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; } else { p_aout->output.i_nb_samples = FRAME_SIZE; } return 0; }
/***************************************************************************** * OpenAudio: open a dummy audio device *****************************************************************************/ int OpenAudio ( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; p_aout->output.pf_play = Play; aout_VolumeSoftInit( p_aout ); if ( p_aout->output.output.i_format == VLC_CODEC_SPDIFL ) { p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; } else { p_aout->output.i_nb_samples = FRAME_SIZE; } /* Create the variable for the audio-device */ var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); return VLC_SUCCESS; }
/***************************************************************************** * Open: create a JACK client *****************************************************************************/ static int Open( vlc_object_t *p_this ) { char psz_name[32]; audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t *p_sys = NULL; int status = VLC_SUCCESS; unsigned int i; int i_error; /* Allocate structure */ p_sys = calloc( 1, sizeof( aout_sys_t ) ); if( p_sys == NULL ) { status = VLC_ENOMEM; goto error_out; } p_aout->sys = p_sys; p_sys->latency = 0; /* Connect to the JACK server */ snprintf( psz_name, sizeof(psz_name), "vlc_%d", getpid()); psz_name[sizeof(psz_name) - 1] = '\0'; p_sys->p_jack_client = jack_client_open( psz_name, JackNullOption | JackNoStartServer, NULL ); if( p_sys->p_jack_client == NULL ) { msg_Err( p_aout, "failed to connect to JACK server" ); status = VLC_EGENERIC; goto error_out; } /* Set the process callback */ jack_set_process_callback( p_sys->p_jack_client, Process, p_aout ); jack_set_graph_order_callback ( p_sys->p_jack_client, GraphChange, p_aout ); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; aout_PacketInit( p_aout, &p_sys->packet, jack_get_buffer_size( p_sys->p_jack_client ) ); aout_VolumeSoftInit( p_aout ); /* JACK only supports fl32 format */ p_aout->format.i_format = VLC_CODEC_FL32; // TODO add buffer size callback p_aout->format.i_rate = jack_get_sample_rate( p_sys->p_jack_client ); p_sys->i_channels = aout_FormatNbChannels( &p_aout->format ); p_sys->p_jack_ports = malloc( p_sys->i_channels * sizeof(jack_port_t *) ); if( p_sys->p_jack_ports == NULL ) { status = VLC_ENOMEM; goto error_out; } p_sys->p_jack_buffers = malloc( p_sys->i_channels * sizeof(jack_sample_t *) ); if( p_sys->p_jack_buffers == NULL ) { status = VLC_ENOMEM; goto error_out; } /* Create the output ports */ for( i = 0; i < p_sys->i_channels; i++ ) { snprintf( psz_name, sizeof(psz_name), "out_%d", i + 1); psz_name[sizeof(psz_name) - 1] = '\0'; p_sys->p_jack_ports[i] = jack_port_register( p_sys->p_jack_client, psz_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); if( p_sys->p_jack_ports[i] == NULL ) { msg_Err( p_aout, "failed to register a JACK port" ); status = VLC_EGENERIC; goto error_out; } } /* Tell the JACK server we are ready */ i_error = jack_activate( p_sys->p_jack_client ); if( i_error ) { msg_Err( p_aout, "failed to activate JACK client (error %d)", i_error ); status = VLC_EGENERIC; goto error_out; } /* Auto connect ports if we were asked to */ if( var_InheritBool( p_aout, AUTO_CONNECT_OPTION ) ) { unsigned int i_in_ports; char *psz_regex = var_InheritString( p_aout, CONNECT_REGEX_OPTION ); const char **pp_in_ports = jack_get_ports( p_sys->p_jack_client, psz_regex, NULL, JackPortIsInput ); free( psz_regex ); /* Count the number of returned ports */ i_in_ports = 0; while( pp_in_ports && pp_in_ports[i_in_ports] ) { i_in_ports++; } /* Tie the output ports to JACK input ports */ for( i = 0; i_in_ports > 0 && i < p_sys->i_channels; i++ ) { const char* psz_in = pp_in_ports[i % i_in_ports]; const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] ); i_error = jack_connect( p_sys->p_jack_client, psz_out, psz_in ); if( i_error ) { msg_Err( p_aout, "failed to connect port %s to port %s (error %d)", psz_out, psz_in, i_error ); } else { msg_Dbg( p_aout, "connecting port %s to port %s", psz_out, psz_in ); } } free( pp_in_ports ); } msg_Dbg( p_aout, "JACK audio output initialized (%d channels, rate=%d)", p_sys->i_channels, p_aout->format.i_rate ); error_out: /* Clean up, if an error occurred */ if( status != VLC_SUCCESS && p_sys != NULL) { if( p_sys->p_jack_client ) { jack_deactivate( p_sys->p_jack_client ); jack_client_close( p_sys->p_jack_client ); aout_PacketDestroy( p_aout ); } free( p_sys->p_jack_ports ); free( p_sys->p_jack_buffers ); free( p_sys ); } return status; }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Open ( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; SDL_AudioSpec desired, obtained; int i_nb_channels; vlc_value_t val, text; /* Check that no one uses the DSP. */ uint32_t i_flags = SDL_INIT_AUDIO; if( SDL_WasInit( i_flags ) ) { return VLC_EGENERIC; } i_flags |= SDL_INIT_EVENTTHREAD; #ifndef NDEBUG /* In debug mode you may want vlc to dump a core instead of staying * stuck */ i_flags |= SDL_INIT_NOPARACHUTE; #endif /* Initialize library */ if( SDL_Init( i_flags ) < 0 ) { msg_Err( p_aout, "cannot initialize SDL (%s)", SDL_GetError() ); return VLC_EGENERIC; } if( var_Get( p_aout, "audio-device", &val ) != VLC_ENOVAR ) { /* The user has selected an audio device. */ if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } } i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); if ( i_nb_channels > 2 ) { /* SDL doesn't support more than two channels. */ i_nb_channels = 2; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } desired.freq = p_aout->output.output.i_rate; desired.format = AUDIO_S16SYS; desired.channels = i_nb_channels; desired.callback = SDLCallback; desired.userdata = p_aout; desired.samples = FRAME_SIZE; /* Open the sound device. */ if( SDL_OpenAudio( &desired, &obtained ) < 0 ) { return VLC_EGENERIC; } SDL_PauseAudio( 0 ); /* Now have a look at what we got. */ switch ( obtained.format ) { case AUDIO_S16LSB: p_aout->output.output.i_format = VLC_CODEC_S16L; break; case AUDIO_S16MSB: p_aout->output.output.i_format = VLC_CODEC_S16B; break; case AUDIO_U16LSB: p_aout->output.output.i_format = VLC_CODEC_U16L; break; case AUDIO_U16MSB: p_aout->output.output.i_format = VLC_CODEC_U16B; break; case AUDIO_S8: p_aout->output.output.i_format = VLC_CODEC_S8; break; case AUDIO_U8: p_aout->output.output.i_format = VLC_CODEC_U8; break; } /* Volume is entirely done in software. */ aout_VolumeSoftInit( p_aout ); if ( obtained.channels != i_nb_channels ) { p_aout->output.output.i_physical_channels = (obtained.channels == 2 ? AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT : AOUT_CHAN_CENTER); if ( var_Type( p_aout, "audio-device" ) == 0 ) { var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Device"); var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL ); val.i_int = (obtained.channels == 2) ? AOUT_VAR_STEREO : AOUT_VAR_MONO; text.psz_string = (obtained.channels == 2) ? _("Stereo") : _("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); } } else if ( var_Type( p_aout, "audio-device" ) == 0 ) { /* First launch. */ var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Device"); var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL ); val.i_int = AOUT_VAR_STEREO; text.psz_string = _("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_MONO; text.psz_string = _("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); if ( i_nb_channels == 2 ) { val.i_int = AOUT_VAR_STEREO; } else { val.i_int = AOUT_VAR_MONO; } var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); } var_TriggerCallback( p_aout, "intf-change" ); p_aout->output.output.i_rate = obtained.freq; p_aout->output.i_nb_samples = obtained.samples; p_aout->output.pf_play = Play; return VLC_SUCCESS; }
/***************************************************************************** * Open: open a dummy audio device *****************************************************************************/ static int Open( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; PCMAudioPlayer * pPlayer; int i_volume; /* Allocate structure */ p_aout->output.p_sys = p_sys = (aout_sys_t *)malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) return VLC_ENOMEM; /* New PCMAudioPlayer */ p_sys->pPlayer = pPlayer = new PCMAudioPlayer(); if( p_sys->pPlayer == NULL ) { free( p_sys ); return VLC_ENOMEM; } /* Get Buffer Requirements */ if( !pPlayer->GetBufferRequirements( p_sys->nAlignment, p_sys->nSizeMultiple, p_sys->nBuffers ) ) { msg_Err( p_aout, "GetBufferRequirements failed" ); delete pPlayer; free( p_sys ); return VLC_EGENERIC; } p_sys->nBuffers = __MIN( p_sys->nBuffers, 4 ); p_sys->ppBuffers = (void **)malloc( p_sys->nBuffers * sizeof( void * ) ); if( p_sys->ppBuffers == NULL ) { delete pPlayer; free( p_sys ); return VLC_ENOMEM; } /* Open PCMAudioPlayer */ p_sys->nBufferSize = FRAME_SIZE * 4; if( !pPlayer->Open( p_sys->nBuffers, p_sys->nBufferSize, p_sys->ppBuffers ) ) { msg_Err( p_aout, "Open failed" ); delete pPlayer; free( p_sys->ppBuffers ); free( p_sys ); return VLC_EGENERIC; } p_sys->nNextBufferIndex = 0; if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) ) { p_aout->output.output.i_rate = 44100; if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) ) { msg_Err( p_aout, "SetSampleRate failed" ); pPlayer->Close(); delete pPlayer; free( p_sys->ppBuffers ); free( p_sys ); return VLC_EGENERIC; } } p_aout->output.output.i_format = VLC_CODEC_S16N; p_aout->output.i_nb_samples = FRAME_SIZE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; p_aout->output.pf_play = Play; aout_VolumeSoftInit( p_aout ); i_volume = config_GetInt( p_aout->p_libvlc, "volume" ); pPlayer->SetVolume( (u32)__MIN( i_volume * 64, 0xFFFF ) ); /* Create thread and wait for its readiness. */ if( vlc_thread_create( p_aout, "aout", Thread, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create OSS thread (%m)" ); pPlayer->Close(); delete pPlayer; free( p_sys->ppBuffers ); free( p_sys ); return VLC_ENOMEM; } return VLC_SUCCESS; }
/***************************************************************************** * Open: open a dummy audio device *****************************************************************************/ static int Open( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; char * psz_name, * psz_format; const char * const * ppsz_compare = format_list; int i_channels, i = 0; psz_name = var_CreateGetString( p_this, "audiofile-file" ); if( !psz_name || !*psz_name ) { msg_Err( p_aout, "you need to specify an output file name" ); free( psz_name ); return VLC_EGENERIC; } /* Allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) return VLC_ENOMEM; if( !strcmp( psz_name, "-" ) ) p_aout->output.p_sys->p_file = stdout; else p_aout->output.p_sys->p_file = utf8_fopen( psz_name, "wb" ); free( psz_name ); if ( p_aout->output.p_sys->p_file == NULL ) { free( p_aout->output.p_sys ); return VLC_EGENERIC; } p_aout->output.pf_play = Play; /* Audio format */ psz_format = var_CreateGetString( p_this, "audiofile-format" ); while ( *ppsz_compare != NULL ) { if ( !strncmp( *ppsz_compare, psz_format, strlen(*ppsz_compare) ) ) { break; } ppsz_compare++; i++; } if ( *ppsz_compare == NULL ) { msg_Err( p_aout, "cannot understand the format string (%s)", psz_format ); if( p_aout->output.p_sys->p_file != stdout ) fclose( p_aout->output.p_sys->p_file ); free( p_aout->output.p_sys ); free( psz_format ); return VLC_EGENERIC; } free( psz_format ); p_aout->output.output.i_format = format_int[i]; if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } else { p_aout->output.i_nb_samples = FRAME_SIZE; aout_VolumeSoftInit( p_aout ); } /* Channels number */ i_channels = var_CreateGetInteger( p_this, "audiofile-channels" ); if( i_channels > 0 && i_channels <= CHANNELS_MAX ) { p_aout->output.output.i_physical_channels = pi_channels_maps[i_channels]; } /* WAV header */ p_aout->output.p_sys->b_add_wav_header = var_CreateGetBool( p_this, "audiofile-wav" ); if( p_aout->output.p_sys->b_add_wav_header ) { /* Write wave header */ WAVEHEADER *wh = &p_aout->output.p_sys->waveh; memset( wh, 0, sizeof(wh) ); switch( p_aout->output.output.i_format ) { case VLC_CODEC_FL32: wh->Format = WAVE_FORMAT_IEEE_FLOAT; wh->BitsPerSample = sizeof(float) * 8; break; case VLC_CODEC_U8: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 8; break; case VLC_CODEC_S16L: default: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 16; break; } wh->MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F'); wh->Length = 0; /* temp, to be filled in as we go */ wh->ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E'); wh->SubChunkID = VLC_FOURCC('f', 'm', 't', ' '); wh->SubChunkLength = 16; wh->Modus = aout_FormatNbChannels( &p_aout->output.output ); wh->SampleFreq = p_aout->output.output.i_rate; wh->BytesPerSample = wh->Modus * ( wh->BitsPerSample / 8 ); wh->BytesPerSec = wh->BytesPerSample * wh->SampleFreq; wh->DataChunkID = VLC_FOURCC('d', 'a', 't', 'a'); wh->DataLength = 0; /* temp, to be filled in as we go */ /* Header -> little endian format */ SetWLE( &wh->Format, wh->Format ); SetWLE( &wh->BitsPerSample, wh->BitsPerSample ); SetDWLE( &wh->SubChunkLength, wh->SubChunkLength ); SetWLE( &wh->Modus, wh->Modus ); SetDWLE( &wh->SampleFreq, wh->SampleFreq ); SetWLE( &wh->BytesPerSample, wh->BytesPerSample ); SetDWLE( &wh->BytesPerSec, wh->BytesPerSec ); if( fwrite( wh, sizeof(WAVEHEADER), 1, p_aout->output.p_sys->p_file ) != 1 ) { msg_Err( p_aout, "write error (%m)" ); } } return 0; }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Open ( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; struct pa_sample_spec ss; const struct pa_buffer_attr *buffer_attr; struct pa_buffer_attr a; struct pa_channel_map map; /* Allocate structures */ p_aout->output.p_sys = p_sys = calloc( 1, sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; PULSE_DEBUG( "Pulse start initialization"); ss.channels = aout_FormatNbChannels( &p_aout->output.output ); /* Get the input stream channel count */ /* Setup the pulse audio stream based on the input stream count */ switch(ss.channels) { case 8: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; break; case 6: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; break; case 4: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; break; case 2: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case 1: p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; break; default: msg_Err(p_aout,"Invalid number of channels"); goto fail; } /* Add a quick command line info message */ msg_Info(p_aout, "No. of Audio Channels: %d", ss.channels); ss.rate = p_aout->output.output.i_rate; ss.format = PA_SAMPLE_FLOAT32NE; p_aout->output.output.i_format = VLC_CODEC_FL32; if (!pa_sample_spec_valid(&ss)) { msg_Err(p_aout,"Invalid sample spec"); goto fail; } /* Reduce overall latency to 200mS to reduce audible clicks * Also pulse minreq and internal buffers are now 20mS which reduces resampling */ a.tlength = pa_bytes_per_second(&ss)/5; a.maxlength = a.tlength * 2; a.prebuf = a.tlength / 2; a.minreq = a.tlength / 10; /* Buffer size is 20mS */ p_sys->buffer_size = a.minreq; /* Initialise the speaker map setup above */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); if (!(p_sys->mainloop = pa_threaded_mainloop_new())) { msg_Err(p_aout, "Failed to allocate main loop"); goto fail; } if (!(p_sys->context = pa_context_new(pa_threaded_mainloop_get_api(p_sys->mainloop), _( PULSE_CLIENT_NAME )))) { msg_Err(p_aout, "Failed to allocate context"); goto fail; } pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout); PULSE_DEBUG( "Pulse before context connect"); if (pa_context_connect(p_sys->context, NULL, 0, NULL) < 0) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto fail; } PULSE_DEBUG( "Pulse after context connect"); pa_threaded_mainloop_lock(p_sys->mainloop); if (pa_threaded_mainloop_start(p_sys->mainloop) < 0) { msg_Err(p_aout, "Failed to start main loop"); goto unlock_and_fail; } msg_Dbg(p_aout, "Pulse mainloop started"); /* Wait until the context is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); if (pa_context_get_state(p_sys->context) != PA_CONTEXT_READY) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } if (!(p_sys->stream = pa_stream_new(p_sys->context, "audio stream", &ss, &map))) { msg_Err(p_aout, "Failed to create stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG( "Pulse after new stream"); pa_stream_set_state_callback(p_sys->stream, stream_state_cb, p_aout); pa_stream_set_write_callback(p_sys->stream, stream_request_cb, p_aout); pa_stream_set_latency_update_callback(p_sys->stream, stream_latency_update_cb, p_aout); if (pa_stream_connect_playback(p_sys->stream, NULL, &a, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) { msg_Err(p_aout, "Failed to connect stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse stream connect"); /* Wait until the stream is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); msg_Dbg(p_aout,"Pulse stream connected"); if (pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse after stream get status"); pa_threaded_mainloop_unlock(p_sys->mainloop); buffer_attr = pa_stream_get_buffer_attr(p_sys->stream); p_aout->output.i_nb_samples = buffer_attr->minreq / pa_frame_size(&ss); p_aout->output.pf_play = Play; aout_VolumeSoftInit(p_aout); msg_Dbg(p_aout, "Pulse initialized successfully"); { char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; msg_Dbg(p_aout, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u", buffer_attr->maxlength, buffer_attr->tlength, buffer_attr->prebuf, buffer_attr->minreq); msg_Dbg(p_aout, "Using sample spec '%s', channel map '%s'.", pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(p_sys->stream)), pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(p_sys->stream))); msg_Dbg(p_aout, "Connected to device %s (%u, %ssuspended).", pa_stream_get_device_name(p_sys->stream), pa_stream_get_device_index(p_sys->stream), pa_stream_is_suspended(p_sys->stream) ? "" : "not "); } return VLC_SUCCESS; unlock_and_fail: msg_Dbg(p_aout, "Pulse initialization unlock and fail"); if (p_sys->mainloop) pa_threaded_mainloop_unlock(p_sys->mainloop); fail: msg_Err(p_aout, "Pulse initialization failed"); uninit(p_aout); return VLC_EGENERIC; }
/***************************************************************************** * Open : creates a handle and opens an alsa device ***************************************************************************** * This function opens an alsa device, through the alsa API *****************************************************************************/ int E_(OpenAudio)( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; int i_ret; int i_bytes_per_sample; int i_nb_channels; snd_pcm_channel_info_t pi; snd_pcm_channel_params_t pp; aout_instance_t *p_aout = (aout_instance_t *)p_this; /* allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return -1; } /* open audio device */ if( ( i_ret = snd_pcm_open_preferred( &p_aout->output.p_sys->p_pcm_handle, &p_aout->output.p_sys->i_card, &p_aout->output.p_sys->i_device, SND_PCM_OPEN_PLAYBACK ) ) < 0 ) { msg_Err( p_aout, "unable to open audio device (%s)", snd_strerror( i_ret ) ); free( p_aout->output.p_sys ); return -1; } /* disable mmap */ if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->output.p_sys->p_pcm_handle, PLUGIN_DISABLE_MMAP ) ) < 0 ) { msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) ); E_(CloseAudio)( p_this ); free( p_aout->output.p_sys ); return -1; } p_aout->output.p_sys->p_silent_buffer = malloc( DEFAULT_FRAME_SIZE * 4 ); p_aout->output.pf_play = Play; aout_VolumeSoftInit( p_aout ); memset( &pi, 0, sizeof(pi) ); memset( &pp, 0, sizeof(pp) ); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if( ( i_ret = snd_pcm_plugin_info( p_aout->output.p_sys->p_pcm_handle, &pi ) ) < 0 ) { msg_Err( p_aout, "unable to get plugin info (%s)", snd_strerror( i_ret ) ); E_(CloseAudio)( p_this ); free( p_aout->output.p_sys ); return -1; } pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_PLAYBACK; pp.start_mode = SND_PCM_START_FULL; pp.stop_mode = SND_PCM_STOP_STOP; pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = p_aout->output.output.i_rate; i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); if ( i_nb_channels > 2 ) { /* I don't know if QNX supports more than two channels. */ i_nb_channels = 2; p_aout->output.output.i_channels = AOUT_CHAN_STEREO; } pp.format.voices = i_nb_channels; p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.i_nb_samples = DEFAULT_FRAME_SIZE; pp.format.format = SND_PCM_SFMT_S16; i_bytes_per_sample = 2; pp.buf.block.frag_size = p_aout->output.i_nb_samples * p_aout->output.output.i_channels * i_bytes_per_sample; /* set parameters */ if( ( i_ret = snd_pcm_plugin_params( p_aout->output.p_sys->p_pcm_handle, &pp ) ) < 0 ) { msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) ); E_(CloseAudio)( p_this ); free( p_aout->output.p_sys ); return -1; } /* prepare channel */ if( ( i_ret = snd_pcm_plugin_prepare( p_aout->output.p_sys->p_pcm_handle, SND_PCM_CHANNEL_PLAYBACK ) ) < 0 ) { msg_Err( p_aout, "unable to prepare channel (%s)", snd_strerror( i_ret ) ); E_(CloseAudio)( p_this ); free( p_aout->output.p_sys ); return -1; } /* Create audio thread and wait for its readiness. */ if( vlc_thread_create( p_aout, "aout", QNXaoutThread, VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) ) { msg_Err( p_aout, "cannot create QNX audio thread (%s)", strerror(errno) ); E_(CloseAudio)( p_this ); free( p_aout->output.p_sys ); return -1; } return( 0 ); }
/***************************************************************************** * Open: open the audio device ***************************************************************************** * This function opens and setups Win32 waveOut *****************************************************************************/ static int Open( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; vlc_value_t val; int i; /* Allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return VLC_EGENERIC; } p_aout->output.pf_play = Play; p_aout->b_die = VLC_FALSE; if( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout ); } if( var_Get( p_aout, "audio-device", &val ) < 0 ) { /* Probe() has failed. */ free( p_aout->output.p_sys ); return VLC_EGENERIC; } var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); /* Open the device */ if( val.i_int == AOUT_VAR_SPDIF ) { p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'), p_aout->output.output.i_physical_channels, aout_FormatNbChannels( &p_aout->output.output ), p_aout->output.output.i_rate, VLC_FALSE ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open waveout audio device" ); free( p_aout->output.p_sys ); return VLC_EGENERIC; } /* Calculate the frame size in bytes */ p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; p_aout->output.p_sys->i_buffer_size = p_aout->output.output.i_bytes_per_frame; aout_VolumeNoneInit( p_aout ); } else { if( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format, p_aout->output.output.i_physical_channels, aout_FormatNbChannels( &p_aout->output.output ), p_aout->output.output.i_rate, VLC_FALSE ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open waveout audio device" ); free( p_aout->output.p_sys ); return VLC_EGENERIC; } /* Calculate the frame size in bytes */ p_aout->output.i_nb_samples = FRAME_SIZE; aout_FormatPrepare( &p_aout->output.output ); p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame; aout_VolumeSoftInit( p_aout ); } waveOutReset( p_aout->output.p_sys->h_waveout ); /* Allocate silence buffer */ p_aout->output.p_sys->p_silence_buffer = malloc( p_aout->output.p_sys->i_buffer_size ); if( p_aout->output.p_sys->p_silence_buffer == NULL ) { free( p_aout->output.p_sys ); msg_Err( p_aout, "out of memory" ); return 1; } /* Zero the buffer. WinCE doesn't have calloc(). */ memset( p_aout->output.p_sys->p_silence_buffer, 0, p_aout->output.p_sys->i_buffer_size ); /* Now we need to setup our waveOut play notification structure */ p_aout->output.p_sys->p_notif = vlc_object_create( p_aout, sizeof(notification_thread_t) ); p_aout->output.p_sys->p_notif->p_aout = p_aout; p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL ); /* Then launch the notification thread */ if( vlc_thread_create( p_aout->output.p_sys->p_notif, "waveOut Notification Thread", WaveOutThread, VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) { msg_Err( p_aout, "cannot create WaveOutThread" ); } /* We need to kick off the playback in order to have the callback properly * working */ for( i = 0; i < FRAMES_NUM; i++ ) { p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE; p_aout->output.p_sys->waveheader[i].dwUser = 0; } PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout, &p_aout->output.p_sys->waveheader[0], NULL ); return 0; }
/***************************************************************************** * Open: create a handle and open an alsa device ***************************************************************************** * This function opens an alsa device, through the alsa API. * * Note: the only heap-allocated string is psz_device. All the other pointers * are references to psz_device or to stack-allocated data. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; vlc_value_t val; char psz_default_iec_device[128]; /* Buffer used to store the default S/PDIF device */ char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF output */ int i_vlc_pcm_format; /* Audio format for VLC's data */ int i_snd_pcm_format; /* Audio format for ALSA's data */ snd_pcm_uframes_t i_buffer_size = 0; snd_pcm_uframes_t i_period_size = 0; int i_channels = 0; snd_pcm_hw_params_t *p_hw; snd_pcm_sw_params_t *p_sw; int i_snd_rc = -1; unsigned int i_old_rate; bool b_retry = true; /* Allocate structures */ p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->b_playing = false; p_sys->start_date = 0; vlc_cond_init( &p_sys->wait ); vlc_mutex_init( &p_sys->lock ); /* Get device name */ if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" ); dialog_Fatal( p_aout, _("No Audio Device"), "%s", _("No audio device name was given. You might want to " \ "enter \"default\".") ); free( p_sys ); return VLC_EGENERIC; } /* Choose the IEC device for S/PDIF output: if the device is overriden by the user then it will be the one otherwise we compute the default device based on the output format. */ if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) ) { snprintf( psz_default_iec_device, sizeof(psz_default_iec_device), "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x", IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO, IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, 0, ( p_aout->output.output.i_rate == 48000 ? IEC958_AES3_CON_FS_48000 : ( p_aout->output.output.i_rate == 44100 ? IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) ); psz_iec_device = psz_default_iec_device; } else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { psz_iec_device = psz_device; } else { psz_iec_device = NULL; } /* Choose the linear PCM format (read the comment above about FPU and float32) */ if( vlc_CPU() & CPU_CAPABILITY_FPU ) { i_vlc_pcm_format = VLC_CODEC_FL32; i_snd_pcm_format = SND_PCM_FORMAT_FLOAT; } else { i_vlc_pcm_format = VLC_CODEC_S16N; i_snd_pcm_format = SND_PCM_FORMAT_S16; } /* If the variable doesn't exist then it's the first time we're called and we have to probe the available audio formats and channels */ if ( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format ); } if ( var_Get( p_aout, "audio-device", &val ) < 0 ) { free( p_sys ); free( psz_device ); return VLC_EGENERIC; } p_aout->output.output.i_format = i_vlc_pcm_format; if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; free( psz_device ); psz_device = strdup( "surround51" ); } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; free( psz_device ); psz_device = strdup( "surround40" ); } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else if( val.i_int != AOUT_VAR_SPDIF ) { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; } #ifdef ALSA_DEBUG snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 ); #endif /* Open the device */ if ( val.i_int == AOUT_VAR_SPDIF ) { if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device, SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_iec_device, snd_strerror( i_snd_rc ) ); dialog_Fatal( p_aout, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_iec_device, snd_strerror( i_snd_rc ) ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; } i_buffer_size = ALSA_SPDIF_BUFFER_SIZE; i_snd_pcm_format = SND_PCM_FORMAT_S16; i_channels = 2; i_vlc_pcm_format = VLC_CODEC_SPDIFL; p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } else { int i; msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device ); /* Since it seems snd_pcm_close hasn't really released the device at the time it returns, probe if the device is available in loop for 1s. We cannot use blocking mode since the we would wait indefinitely when switching from a dmx device to surround51. */ for( i = 10; i >= 0; i-- ) { if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY ) { if( i ) msleep( 100000 /* 100ms */ ); else { msg_Err( p_aout, "audio device: %s is already in use", psz_device ); dialog_Fatal( p_aout, _("Audio output failed"), _("The audio device \"%s\" is already in use."), psz_device ); } continue; } break; } if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_device, snd_strerror( i_snd_rc ) ); dialog_Fatal( p_aout, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_device, snd_strerror( i_snd_rc ) ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; } /* We want blocking mode */ snd_pcm_nonblock( p_sys->p_snd_pcm, 0 ); i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE; i_channels = aout_FormatNbChannels( &p_aout->output.output ); p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE; aout_VolumeSoftInit( p_aout ); } /* Free psz_device so that all the remaining data is stack-allocated */ free( psz_device ); p_aout->output.pf_play = Play; snd_pcm_hw_params_alloca(&p_hw); snd_pcm_sw_params_alloca(&p_sw); /* Due to some bugs in alsa with some drivers, we need to retry in s16l if snd_pcm_hw_params fails in fl32 */ while ( b_retry ) { b_retry = false; /* Get Initial hardware parameters */ if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 ) { msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set format. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_snd_pcm_format ) ) < 0 ) { if( i_snd_pcm_format != SND_PCM_FORMAT_S16 ) { i_snd_pcm_format = SND_PCM_FORMAT_S16; i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_snd_pcm_format ); } if ( i_snd_rc < 0 ) { msg_Err( p_aout, "unable to set stream sample size and " "word order (%s)", snd_strerror( i_snd_rc ) ); goto error; } } if( i_vlc_pcm_format != VLC_CODEC_SPDIFL ) switch( i_snd_pcm_format ) { case SND_PCM_FORMAT_FLOAT: i_vlc_pcm_format = VLC_CODEC_FL32; break; case SND_PCM_FORMAT_S16: i_vlc_pcm_format = VLC_CODEC_S16N; break; } p_aout->output.output.i_format = i_vlc_pcm_format; if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw, SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 ) { msg_Err( p_aout, "unable to set interleaved stream format (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set channels. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw, i_channels ) ) < 0 ) { msg_Err( p_aout, "unable to set number of output channels (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set rate. */ i_old_rate = p_aout->output.output.i_rate; i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw, &p_aout->output.output.i_rate, NULL ); if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate ) { msg_Warn( p_aout, "The rate %d Hz is not supported by your " \ "hardware. Using %d Hz instead.\n", i_old_rate, \ p_aout->output.output.i_rate ); } /* Set period size. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm, p_hw, &i_period_size, NULL ) ) < 0 ) { msg_Err( p_aout, "unable to set period size (%s)", snd_strerror( i_snd_rc ) ); goto error; } p_aout->output.i_nb_samples = i_period_size; /* Set buffer size. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw, &i_buffer_size ) ) < 0 ) { msg_Err( p_aout, "unable to set buffer size (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Commit hardware parameters. */ if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 ) { if ( b_retry == false && i_snd_pcm_format == SND_PCM_FORMAT_FLOAT) { b_retry = true; i_snd_pcm_format = SND_PCM_FORMAT_S16; p_aout->output.output.i_format = VLC_CODEC_S16N; msg_Warn( p_aout, "unable to commit hardware configuration " "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) ); } else { msg_Err( p_aout, "unable to commit hardware configuration (%s)", snd_strerror( i_snd_rc ) ); goto error; } } } if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw, &p_sys->i_period_time, NULL ) ) < 0 ) { msg_Err( p_aout, "unable to get period time (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Get Initial software parameters */ snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw ); i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 ); i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw, p_aout->output.i_nb_samples ); /* start playing when one period has been written */ i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw, ALSA_DEFAULT_PERIOD_SIZE); if( i_snd_rc < 0 ) { msg_Err( p_aout, "unable to set start threshold (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Commit software parameters. */ if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 ) { msg_Err( p_aout, "unable to set software configuration" ); goto error; } #ifdef ALSA_DEBUG snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" ); snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr ); snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" ); snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr ); snd_output_printf( p_sys->p_snd_stderr, "\n" ); #endif /* Create ALSA thread and wait for its readiness. */ if( vlc_thread_create( p_aout, "aout", ALSAThread, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create ALSA thread (%m)" ); goto error; } return 0; error: snd_pcm_close( p_sys->p_snd_pcm ); #ifdef ALSA_DEBUG snd_output_close( p_sys->p_snd_stderr ); #endif free( p_sys ); return VLC_EGENERIC; }
/***************************************************************************** * Open: open the audio device (the digital sound processor) ***************************************************************************** * This function opens the DSP as a usual non-blocking write-only file, and * modifies the p_aout->p_sys->i_fd with the file's descriptor. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { audio_output_t * p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ p_aout->sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; /* Get device name */ if( (psz_device = var_InheritString( p_aout, "oss-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); return VLC_EGENERIC; } /* Open the sound device in non-blocking mode, because ALSA's OSS * emulation and some broken OSS drivers would make a blocking call * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ p_sys->i_fd = vlc_open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); free( psz_device ); free( p_sys ); return VLC_EGENERIC; } /* if the opening was ok, put the device back in blocking mode */ fcntl( p_sys->i_fd, F_SETFL, fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY ); free( psz_device ); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; if ( var_Type( p_aout, "audio-device" ) == 0 ) Probe( p_aout ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); if ( var_Get( p_aout, "audio-device", &val ) < 0 ) /* Probe() has failed. */ goto error; if ( val.i_int == AOUT_VAR_SPDIF ) { p_aout->format.i_format = VLC_CODEC_SPDIFL; } else if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%"PRId64")", val.i_int ); goto error; } var_TriggerCallback( p_aout, "intf-change" ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } /* Set the output format */ if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { int i_format = AFMT_AC3; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } p_aout->format.i_format = VLC_CODEC_SPDIFL; p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->format.i_frame_length = A52_FRAME_NB; aout_PacketInit( p_aout, &p_sys->packet, A52_FRAME_NB ); aout_VolumeNoneInit( p_aout ); } else { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; unsigned int i_rate; unsigned int i_nb_channels; audio_buf_info audio_buf; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); goto error; } switch ( i_format ) { case AFMT_U8: p_aout->format.i_format = VLC_CODEC_U8; break; case AFMT_S8: p_aout->format.i_format = VLC_CODEC_S8; break; case AFMT_U16_LE: p_aout->format.i_format = VLC_CODEC_U16L; break; case AFMT_S16_LE: p_aout->format.i_format = VLC_CODEC_S16L; break; case AFMT_U16_BE: p_aout->format.i_format = VLC_CODEC_U16B; break; case AFMT_S16_BE: p_aout->format.i_format = VLC_CODEC_S16B; break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); goto error; } i_nb_channels = aout_FormatNbChannels( &p_aout->format ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || i_nb_channels != aout_FormatNbChannels( &p_aout->format ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", aout_FormatPrintChannels( &p_aout->format) ); goto error; } /* Set the output rate */ i_rate = p_aout->format.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->format.i_rate ); goto error; } if( i_rate != p_aout->format.i_rate ) { p_aout->format.i_rate = i_rate; } /* Set the fragment size */ aout_FormatPrepare( &p_aout->format ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ i_frame_size = ((uint64_t)p_aout->format.i_bytes_per_frame * p_aout->format.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT; i_fragments = 4; while( i_fragments < 12 && (1U << i_fragments) < i_frame_size ) { ++i_fragments; } i_fragments |= FRAME_COUNT << 16; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 ) { msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments ); } if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); goto error; } /* Number of fragments actually allocated */ p_aout->sys->i_fragstotal = audio_buf.fragstotal; /* Maximum duration the soundcard's buffer can hold */ p_aout->sys->max_buffer_duration = (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 / p_aout->format.i_bytes_per_frame / p_aout->format.i_rate * p_aout->format.i_frame_length; aout_PacketInit( p_aout, &p_sys->packet, audio_buf.fragsize/p_aout->format.i_bytes_per_frame ); aout_VolumeSoftInit( p_aout ); } /* Create OSS thread and wait for its readiness. */ if( vlc_clone( &p_sys->thread, OSSThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create OSS thread (%m)" ); aout_PacketDestroy( p_aout ); goto error; } return VLC_SUCCESS; error: var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; }
static int PAOpenStream( audio_output_t *p_aout ) { aout_sys_t *p_sys = p_aout->sys; const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo(); PaStreamParameters paStreamParameters; vlc_value_t val; int i_channels, i_err; uint32_t i_channel_mask; if( var_Get( p_aout, "audio-device", &val ) < 0 ) { return VLC_EGENERIC; } if( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_3F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } i_channels = aout_FormatNbChannels( &p_aout->format ); msg_Dbg( p_aout, "nb_channels requested = %d", i_channels ); i_channel_mask = p_aout->format.i_physical_channels; /* Calculate the frame size in bytes */ p_sys->i_sample_size = 4 * i_channels; aout_FormatPrepare( &p_aout->format ); aout_PacketInit( p_aout, &p_sys->packet, FRAME_SIZE ); aout_VolumeSoftInit( p_aout ); /* Check for channel reordering */ p_aout->sys->i_channel_mask = i_channel_mask; p_aout->sys->i_bits_per_sample = 32; /* forced to paFloat32 */ p_aout->sys->i_channels = i_channels; p_aout->sys->b_chan_reorder = aout_CheckChannelReorder( NULL, pi_channels_out, i_channel_mask, i_channels, p_aout->sys->pi_chan_table ); if( p_aout->sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } paStreamParameters.device = p_sys->i_device_id; paStreamParameters.channelCount = i_channels; paStreamParameters.sampleFormat = paFloat32; paStreamParameters.suggestedLatency = p_sys->deviceInfo->defaultLowOutputLatency; paStreamParameters.hostApiSpecificStreamInfo = NULL; i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */, &paStreamParameters, (double)p_aout->format.i_rate, FRAME_SIZE, paClipOff, paCallback, p_sys ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err, Pa_GetErrorText( i_err ) ); if( i_err == paUnanticipatedHostError ) { msg_Err( p_aout, "type %d code %ld : %s", paLastHostErrorInfo->hostApiType, paLastHostErrorInfo->errorCode, paLastHostErrorInfo->errorText ); } p_sys->p_stream = 0; aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } i_err = Pa_StartStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StartStream() failed" ); Pa_CloseStream( p_sys->p_stream ); aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } return VLC_SUCCESS; }
/***************************************************************************** * Open: open the audio device (the digital sound processor) ***************************************************************************** * This function opens the DSP as a usual non-blocking write-only file, and * modifies the p_aout->p_sys->i_fd with the file's descriptor. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return VLC_ENOMEM; } /* Get device name */ if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); return VLC_EGENERIC; } /* Open the sound device in non-blocking mode, because ALSA's OSS * emulation and some broken OSS drivers would make a blocking call * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); free( p_sys ); return VLC_EGENERIC; } /* if the opening was ok, put the device back in blocking mode */ fcntl( p_sys->i_fd, F_SETFL, fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY ); free( psz_device ); p_aout->output.pf_play = Play; if ( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout ); } if ( var_Get( p_aout, "audio-device", &val ) < 0 ) { /* Probe() has failed. */ free( p_sys ); return VLC_EGENERIC; } if ( val.i_int == AOUT_VAR_SPDIF ) { p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); } else if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int ); free( p_sys ); return VLC_EGENERIC; } val.b_bool = VLC_TRUE; var_Set( p_aout, "intf-change", val ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } /* Set the output format */ if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { int i_format = AFMT_AC3; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; unsigned int i_rate; unsigned int i_nb_channels; audio_buf_info audio_buf; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } switch ( i_format ) { case AFMT_U8: p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' '); break; case AFMT_S8: p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' '); break; case AFMT_U16_LE: p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l'); break; case AFMT_S16_LE: p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l'); break; case AFMT_U16_BE: p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b'); break; case AFMT_S16_BE: p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b'); break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", aout_FormatPrintChannels( &p_aout->output.output) ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } /* Set the output rate */ i_rate = p_aout->output.output.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->output.output.i_rate ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } if( i_rate != p_aout->output.output.i_rate ) { p_aout->output.output.i_rate = i_rate; } /* Set the fragment size */ aout_FormatPrepare( &p_aout->output.output ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ i_fragments = 0; i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame; while( i_frame_size >>= 1 ) { ++i_fragments; } i_fragments |= FRAME_COUNT << 16; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 ) { msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments ); } if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } else { /* Number of fragments actually allocated */ p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal; /* Maximum duration the soundcard's buffer can hold */ p_aout->output.p_sys->max_buffer_duration = (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 / p_aout->output.output.i_bytes_per_frame / p_aout->output.output.i_rate * p_aout->output.output.i_frame_length; p_aout->output.i_nb_samples = audio_buf.fragsize / p_aout->output.output.i_bytes_per_frame; } aout_VolumeSoftInit( p_aout ); }